Handler相关拓展

基本概述:Handler就是解决线程与线程间的通信。

Handler是Android提供的用来更新UI的一套机制,也是一套消息处理机制,我们可以通过它发送消息,也可以通过它处理消息。

为什么要使用Handler:

Android在设计的时候,就封装了一套消息创建、传递、处理机制,如果不遵循这样的机制就没有办法更新UI信息,就会抛出异常。

为什么Android要设计只能通过Handler机制更新UI:

最根本的目的就是解决多线程并发问题。

如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,那么就会导致更新界面错乱;如果对更新UI的操作都进行加锁处理,又会造成性能下降。

基于对以上目的的考虑,Android给我们提供了一套更新UI的机制,我们只需遵循这样的机制,无需考虑多线程问题。

Handler的原理是什么:

Handler封装了消息的发送:内部会跟Looper关联

Looper(消息封装的载体):内部包含一个消息队列(MessageQueue),所有Handler发送的消息都会走向这个消息队列;

Looper.Looper方法是一个死循环,不断的从MessageQueue取消息,如果有消息就处理消息,没有消息就阻塞

MessageQueue(消息队列):可以添加消息,并处理消息

总结:Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己(handleMessage),MessageQueue就是一个存储消息的容器。

消息处理机制本质:一个线程开启循环模式持续监听并依次处理其他线程给它发的消息。

Handler引起的内存泄漏:

原因:Hndler非静态内部类持有外部类的匿名引用,导致外部类无法被回收;

具体描述:Handler非静态的内部类会持有当前Activity的引用,而Handler又被Message持有,Message被MessageQueue持有,而MessageQueue又被Looper持有,Looper被主线程持有,主线程是不会回收的,通过这条引用链就会导致Activity无法回收。在这之中如果Message在还没处理完成之前,他会一直处在消息队列中,至少等消息处理完才会销毁这个Message,销毁Message才会销毁Handler,进而回收Activity,因此在此期间就会导致内存泄漏。

解决办法:handler内部持有外部Activity的弱引用,并把handler改为静态内部类,然后在onDestroy方法中调用handler的removeCallBack()方法

非UI线程真的不能更新UI吗?

以下代码就能正常执行并且将tvText设置为new value。因为setText操作是在onCreate里面进行的,然后在onResume方法被执行后我们的ViewRootImpl才会被生成,所以并未执行相应的checkThread()操作。

public class MainActivity extends Activity {

    private TextView tvText;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);  

        tvText = (TextView) findViewById(R.id.main_tv);

        new Thread(new Runnable() {

            @Override

            public void run() {

                tvText.setText("new value");

            }

        }).start();

    }

}

Handler组成部分:1.Message 2.Handler 3.Message Queue 4.Looper 5.ThreadLocal

Looper

每一个线程只有一个Looper,每个线程在初始化Looper之后,然后Looper会维护好该线程的消息队列,用来存放Handler发送的Message,并处理消息队列出队的Message。它的特点是它跟它的线程是绑定的,处理消息也是在Looper所在的线程去处理,所以当我们在主线程创建Handler时,它就会跟主线程唯一的Looper绑定,从而我们使用Handler在子线程发消息时,最终也是在主线程处理,达到了异步的效果。

那么就会有人问,为什么我们使用Handler的时候从来都不需要创建Looper呢?这是因为在主线程中,ActivityThread默认会把Looper初始化好,prepare以后,当前线程就会变成一个Looper线程。Looper的创建是通过ThreadLocal,在每个线程都创建独立的Looper。

MessageQueue

MessageQueue是一个消息队列,用来存放Handler发送的消息。每个线程最多只有一个MessageQueue。MessageQueue通常都是由Looper来管理,而主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper。

Message

消息对象,就是MessageQueue里面存放的对象,一个MessageQueue可以包括多个Message。当我们需要发送一个Message时,我们一般不建议使用new Message()的形式来创建,更推荐使用Message.obtain()来获取Message实例,因为在Message类里面定义了一个消息池,当消息池里存在未使用的消息时,便返回,如果没有未使用的消息,则通过new的方式创建返回,所以使用Message.obtain()的方式来获取实例可以大大减少当有大量Message对象而产生的垃圾回收问题(减少内存抖动现象)。Message类本身是一个单向列表,sPool就是通过单向列表实现的复用池的头节点。

  public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

Handler的使用

1.常规使用

private  Handler mHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == 1){
                //处理相关业务
            }            
        }
    };

    Message message = Message.obtain();
    message.what = 1;
    mHandler.sendMessageDelayed(message, 2000);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}

2.弱引用方式封装

public class BaseHandler<T extends BaseHandler.BaseHandlerCallBack> extends Handler {
    WeakReference<T> wr;

    public BaseHandler(T t) {
        wr = new WeakReference<>(t);
    }

    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        T t = wr.get();
        if(t != null) {
            t.callBack(msg);
        }
    }

    public interface BaseHandlerCallBack {
        void callBack(Message msg);
    }
}

public class MyActivity extends AppCompatActivity implements BaseHandler.BaseHandlerCallBack {
    private BaseHandler<MyActivity> handler = new BaseHandler(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        handler.sendEmptyMessage(1);
    }

    @Override
    public void callBack(Message msg) {
        if(msg.what == 1){
            //处理消息
        }
    }
}

 Handler相关面试题:Handler消息机制详解_feather(猎羽)-优快云博客

HandlerThread

使用场景

在子线程中的通过Handler接收处理耗时任务,或者说是为了取代下面的这种写法。另外IntentService的实现就是利用了HandlerThread。

class LooperThread extends Thread {
    public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // 这里处理消息
              }
          };

          Looper.loop();
      }

原理

HandlerThread本质是一个线程,继承自Thread,内部有自己的Looper对象进行looper循环,将此Looper和Handler绑定,Handler发送的消息进入消息队列,此looper会不断循环读取来回调给Handler的handleMessage方法处理。

优势

  1. 将loop运行在子线程中处理,减轻了主线程的压力,使主线程更流畅
  2. 串行执行,开启一个线程起到多个线程的作用
  3. 有自己的消息队列,不会干扰UI线程

劣势

  1. 由于每一个任务队列逐步执行,一旦队列耗时过长,消息延时
  2. 对于IO等操作,线程等待,不能并发

源码

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    protected void onLooperPrepared() {
    }

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();    
        Looper.loop();
        mTid = -1;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

使用案例

public class MainActivity extends AppCompatActivity {
    TextView tv;
    Handler handler;
    HandlerThread mHandlerThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = findViewById(R.id.tv);

        mHandlerThread = new HandlerThread("handler-thread");
        mHandlerThread.start();
        handler = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                System.out.println("name="+Thread.currentThread().getName()+";msg="+msg.what);
            }
        };

        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = Message.obtain();
                msg.what = 22;
                handler.sendMessage(msg);
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                handler.sendEmptyMessage(33);
            }
        }).start();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
    }
}

IntentService

IntentService 是 Service 的子类,默认为我们开启了一个工作线程,使用这个工作线程逐一处理所有启动请求,在任务执行完毕后会自动停止服务,使用简单,只要实现一个方法 onHandleIntent,该方法会接收每个启动请求的 Intent,能够执行后台工作和耗时操作。可以启动IntentService 多次,而每一个耗时操作会以队列的方式在 IntentService 的 onHandlerIntent 回调方法中执行,
并且,每一次只会执行一个工作线程,执行完第一个再执行第二个。并且等待所有消息都执行完后才终止服务。IntentService 适用于 APP在不影响当前用户的操作的前提下,在后台默默的做一些操作。

使用场景

在后台处理耗时任务。

原理

内部创建了一个HandlerThread和继承自Handler的ServiceHandler,将HandlerThread的looper传入ServiceHandler进行绑定。IntentService被startService的时候会调用onStartCommand生命周期,此时会发送消息到消息队列,然后被HandlerThread不断循环的looper读取并回调给ServiceHandler的handleMessage方法,然后在handleMessage方法中回调给IntentService的onHandleIntent方法来处理。

核心源码

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {//处理looper读取的消息
            onHandleIntent((Intent)msg.obj);//回调给IntentService的onHandleIntent方法
            stopSelf(msg.arg1);
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);//HandlerThread的looper和ServiceHandler绑定
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);//发送消息到消息队列
    }

使用案例

//1.在AndroidManefest中声明MyIntentService 

//2.继承IntentService,重写onHandleIntent
public class MyIntentService extends IntentService {
    public MyIntentService(){
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        // 模拟耗时操作
        download();
    }

    //模拟耗时任务
    private void download(){
        try {
            Thread.sleep(3000);
            System.out.println("下载完成");
            //完成后可以通过EventBus或者广播通知相关页面
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//3.开启服务
startService(new Intent(context, MyIntentService.class));

 AsyncTask

在子线程处理耗时任务回调主线程刷新UI。目前已经启用,被RxJava和Kotlin的协程取代。

原理

内部主要由Handler和两个线程池组成。SERIAL_EXECUTOR是任务队列线程池,用于调度任
务,按顺序排列执行。THREAD_POOL_EXECUTOR是执行线程池,真正执行具体的线程任务。Handler用于工作线程和主线程的异步通信。当执行execute()方法的时候,其实是去调用SERIAL_EXECUTOR的execute()方法。将任务放入队尾,然后从头开始取任务调用THREAD_POOL_EXECUTOR的execute()方法依次执行,直到队列中没有任务。每个AsyncTask任务只能执行一次execute(),因为每个AsyncTask有一个状态,去execute的时候会判断他的状态,如果已经执行过了再去执行就会报错。SERIAL_EXECUTOR和THREAD_POOL_EXECUTOR线程池设计成静态的,让多个AsyncTask的实例对象可以共享这两个线程池,来形成队列。

核心源码

初始化

初始化的时候在主线程创建Handler用来回调主线程刷新UI。WorkerRunnable mWorker实现了Callable接口,在call中做耗时任务doInBackground,再将mWorker放入FutureTask用于丢给线程池去执行。

    public AsyncTask(@Nullable Looper callbackLooper) {
        mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
            ? getMainHandler()
            : new Handler(callbackLooper);

        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
                Result result = null;
                try {
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                } catch (Throwable tr) {
                    mCancelled.set(true);
                    throw tr;
                } finally {
                    postResult(result);
                }
                return result;
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occurred while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

两个线程池

SERIAL_EXECUTOR线程池维护一个有序队列,为了让任务串行执行,真正去执行任务的是THREAD_POOL_EXECUTOR线程池。

//这个线程池里面有一个有序队列,异步任务会在这里排队有序输出到THREAD_POOL_EXECUTOR线程真正执行
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

    private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        //将异步任务存入mTasks
        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            //如果没有任务正在被执行,就取一个队首的任务丢入THREAD_POOL_EXECUTOR线程池去真正执行
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

    private static final int CORE_POOL_SIZE = 1;
    private static final int MAXIMUM_POOL_SIZE = 20;
    //真正去执行任务的线程池
    public static final Executor THREAD_POOL_EXECUTOR;

    //SynchronousQueue表示这个等待队列没有容量,核心线程容量为1,那么当核心线程数量满了的时候就会使用非核心线程去执行任务,当达到最大线程数时就会执行拒绝策略
    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(), sThreadFactory);
        threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

执行方法

execute()用于执行串行任务

executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) 用于并发执行

//串行执行,先进入SERIAL_EXECUTOR线程池中的队列排队等待进入THREAD_POOL_EXECUTOR线程池去真正执行
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

//传入去执行线程池,我们异步跑任务一般使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;
        //准备工作,回调给用户处理
        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);//执行任务

        return this;
    }

使用

 三个泛型参数分别是参数类型,进度类型,结果类型。

AsyncTask<Params, Progress, Result>

        AsyncTask<Integer, Integer, String> asyncTask = new AsyncTask<Integer, Integer, String>() {
            @Override
            protected String doInBackground(Integer... integers) {
                publishProgress(0);//发个消息回调给onProgressUpdate
                //做耗时任务,在子线程
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "总数量:" + 10;
            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                //子线程处理过程中回调主线程做一些UI展示,如下载进度刷新
                System.out.println(values[0]);
            }

            @Override
            protected void onPostExecute(String value) {
                super.onPostExecute(value);
                //得到doInBackground的结果,当前在主线程,可以做UI刷新
                System.out.println(value);
            }
        };
        asyncTask.execute();//串行执行,会进入SERIAL_EXECUTOR线程池中的队列,并排在队尾。每次只从SERIAL_EXECUTOR的队列中取一个队首的任务放入THREAD_POOL_EXECUTOR线程池去执行,等这个任务执行完才会再来取下一个任务
        //asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//直接放入THREAD_POOL_EXECUTOR线程池并发执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值