Handler
handler通过发送和处理Message和Runnable对像来关联相应线程的MessageQueue.
- 可以让对应的Message何Runnable在未来的某个时间点进行相应的处理
- 让自己想要处理的好事的操作放在子线程,让更新ui的操作放在主线程
handler的使用
handler创建的时候会绑定到当前的线程当中(主线程中)
mhandler.post(runnable)
//这种方式只是对 sendMessage的封装
mHandler.post(runnable);
//源码实例
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
mHandler.sendMessage(msg);
Message msg = Message.obtain();
mHandler.sendMessage(msg);
原理
message: 传递的时消息
MessageQueue:时消息的队列
Looper: handler中的轮询器,不断从消息队列中查询消息,交由handler来处理消息。
Looper是每个线程所独有的,在创建looper的时候就创建了 MessageQueue,此时looper何MessageQueue就关联到了一起,通过loop()方法读取 MessageQueue中的消息,读到消息后将message发送到 handler进行处理,handler发送消息只能发送自己相关的线程.
handler构造方法
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//创建looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//创建消息队列
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
后去looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//sThreadLocal 通过不同的线程,访问同一个sThreadLocal,所进行的操作都仅限于自己线程的内部,这样就能保证每一个线程有单独唯一的looper
真正创建了looper
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
这样三者就关联到了一起
Looper.loop()查询消息
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//创建的死循环遍历队列,获取消息,处理消息
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//消息进行分发 target就是handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
消息分发
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler引起内存泄漏
原因:静态内部类会持有外部类的匿名引用,导致外部的activity无法释放
内部类虽然和外部类写在同一个文件中, 但是编译完成后, 还是生成各自的class文件,内部类通过this访问外部类的成员。1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用;2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值;3在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。
解决:handler内部持有外部的activity的弱引用,并把handler改为静态内部类,在activity的生命周期中调用 mhandler.removeCallback()。
AsyncTask
轻量级的异步类,它本质上就是一个封装了线程池和handler的异步框架。
三个参数:
- 第一参数 在执行任务时需要的参数,可以在后台任务中使用。
- 第二个参数 在后台执行任务时,需要在当前界面显示的进度.
- 第三个,当任务结束时需要对任务结果进行返回参数
/**
* 三个参数:
* - 第一参数 在执行任务时需要的参数,可以在后台任务中使用。
* - 第二个参数 在后台执行任务时,需要在当前界面显示的进度.
* - 第三个,当任务结束时需要对任务结果进行返回参数
*/
class MyTask extends AsyncTask<Integer, Integer, String> {
@Override
protected void onPreExecute() {
//任务执行前调用,在ui线程
System.out.println("开始执行任务");
super.onPreExecute();
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
System.out.println("任务结束");
//后台任务结束时调用
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
//doInBackground 执行时会调用这个方法
}
@Override
protected void onCancelled(String s) {
super.onCancelled(s);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected String doInBackground(Integer... integers) {
//在子线程操作,计算网络等操作
//发布进度信息等操作
System.out.println("计算等任务开始");
for (int i = 0; i <= 100; i++) {
//同步进度
publishProgress(i);
}
return integers[0].intValue()+"";
}
}
原理
- AyncTask的本质是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是交到静态线程池中执行的
- 线程池中的工作线程执行的doInBackground()方法执行异步的任务
- 当任务状态改变之后,工作线程会向ui线程发送消息,AsyncTask内部的InternalHandler响应这些消息,并调用相关的回调函数.
注意事项
- 内存泄漏(activity)
- 生命周期(为调用cancle())
- 结果丢失
- 并行or串行
HandlerThread
开启子线程进行好事操作时,多次的创建和销毁线程时很耗费系统资源的。
本质就是: handler + thrad + looper,是一个thead内部有looper
子线程不能开启handler?
在handler发送消息的时候,需要一个消息队列MessageQueue来保存所发送给的消息,子线程时默认没有开启消息轮询器的,而messagequeue是由looper来管理的,如果想在子线程中开启handler,需要手动初始化一个looper,之后调用looper.loop(),创建一个handler
特点:
- HandlerThread本质上是一个线程类,它继承了Thead
- HandlerThread有自己内部的Looper对象,可以进行looper循环。
- 通过获取HandlerThread中的looper对象传递给Handler对象,可以在handleMessage方法中执行异步任务
- 优点是不会有堵塞,减少了对性能的消耗,缺点是不能同时进行多任务的处理,需要等待进行处理,处理效率较低
- 与线程池注重并发不同,HandlerThread是一个串行队列,HandlerThread背后只有一个线程
源码:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
IntentService
继承于Sericve 优先级又高于Serivce,内部封装了HandlerThread 和Hander ,它是一个继承并处理异步请求的一个类,在IntentService内有一个工作线程处理耗时的操作,启动IntentService的方式和启动传统的Service一样当任务执行完毕后,IntentService会自动停止,而不需要我们手动控制 stopSelf(),另外,可以启动IntentService多次,而每一个耗时的操作都已工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完第一个在执行第二个。
- 本质就是一种特殊的Service,继承于Service并且本身就是一个抽象类
- 它的内部就是 通过 handlerThread 和Handler实现异步的操作
代码实例:
intentservice
//IntentService
public class MyIntentService extends IntentService {
public static final String DOWNLOAD_URL = "url";
private static final String INDEX_FLAG = "index";
private static UpdateUI mUpdateUI = null;
public MyIntentService(String name) {
super(name);
}
/**
* 实现异步的方法,
*
* @param intent activity传递过来的Intent,数据封装在intent中
*/
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Bitmap bitmap = downloadUrlBitmap(intent.getStringExtra(DOWNLOAD_URL));
Message msg = Message.obtain();
msg.what = intent.getIntExtra(INDEX_FLAG, 0);
msg.obj = bitmap;
if (null != mUpdateUI) {
mUpdateUI.updateUI(msg);
}
}
public static void setUpdateUI(UpdateUI updateUI) {
mUpdateUI = updateUI;
}
private Bitmap downloadUrlBitmap(String stringExtra) {
//下载图片
return null;
}
public interface UpdateUI {
void updateUI(Message message);
}
}
activity中:
public class IntentServiceActivity extends AppCompatActivity implements MyIntentService.UpdateUI {
public static final String DOWNLOAD_URL = "url";
private static final String INDEX_FLAG = "index";
private static ImageView mImageView;
private String[] img_res = {
};
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mImageView.setImageBitmap((Bitmap) msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_service);
mImageView = findViewById(R.id.iv_intentservice);
Intent intent = new Intent(this, MyIntentService.class);
for (int i = 0; i <= img_res.length; i++) {
intent.putExtra(DOWNLOAD_URL, img_res[i]);
intent.putExtra(INDEX_FLAG, i);
//即使开启的多次,但是实例就只有一个,虽然有多个任务但是IntentService自己会处理,自己维护着消息的队列
startService(intent);
}
MyIntentService.setUpdateUI(this);
}
@Override
public void updateUI(Message message) {
mHandler.sendMessageDelayed(message, message.what * 1000);
}
}