Android 线程间通信之Handler

一:前言
Android为了确保UI操作的线程平安,规定所有的UI操作都必须在主线程(UI线程)中执行,决定了UI线程中不能进行耗时工作,在开发过程中,须要将网络,IO等耗时工作放在工作线程中执行,工作线程中执行实现后须要在UI线程中进行刷新,因而就有了Handler过程内线程通信机制,当然Handler并不是只能用在UI线程与工作线程间的切换,Android中任何线程间通信都能够应用Handler机制。
二:应用Handler实现线程间通信
1.UI线程中应用Handler
UI线程中应用Handler非常简单,因为框架曾经帮咱们初始化好了Looper,只须要创立一个Handler对象即可,之后便能够间接应用这个Handler实例向UI线程发消息(子线程--->UI线程)

 private Handler handler=new Handler(){        @Override        public void handleMessage(@NonNull Message msg) {            super.handleMessage(msg);            //解决音讯        }    };    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_six);    }}

这种形式会导致内存泄露。
咱们通过Handler发送音讯,在Message对象中会持有以后Handler对象的援用,在Java中非动态成员类、外部类、匿名类会持有内部对象的援用(这里在源码中有提到),而Looper是线程局部变量,其生命周期与UI线程雷同,Looper持有MessageQueue的援用,MessageQueue持有Message的援用,当通过Handler发送一个延时音讯未解决之前用户曾经来到以后Activity,会导致Activity不能及时开释而内存透露。
解决思路:
1.官网举荐的一种:

 private Handler handler=new Handler(new Handler.Callback() {       @Override       public boolean handleMessage(@NonNull Message msg) {        switch (msg.what){               case 1:               //解决子线程发过来的音讯                   Toast.makeText(SixActivity.this,(String)msg.obj,Toast.LENGTH_LONG).show();                   Log.d("aa",(String) msg.obj);                   break;           }           return false;       }   });

2.动态外部类

  private MyHandler myHandler=new MyHandler(this);   private static class MyHandler extends Handler{       private WeakReference<Context> reference;       public MyHandler(Context context){           reference=new WeakReference<>(context);                  }       @Override       public void handleMessage(@NonNull Message msg) {                 //do something                      if (reference.get()!=null){               if (msg.what==1){                   Log.d("bb",(String) msg.obj);               }           }       }   }

子线程发送音讯

  new Thread(new Runnable() {            @Override            public void run() {                //Message message=new Message();//能够应用new Message来创立音讯,然而个别不这样应用                 Message message=Message.obtain();//来创立音讯                message.obj="我是子线程音讯";                message.what=1;                // 封装完数据发送给主线程                handler.sendMessage(message);                                //第二种形式                  Message message=Message.obtain();                message.obj="我是子线程动态音讯";                message.what=1;                myHandler.sendMessage(message);            }        }).start();

主线程给子线程发送音讯(UI线程--->子线程)

public class SixActivity extends AppCompatActivity {    // 在子线程中创立音讯Handler    // 子线程创立形式    private Handler handler;    private Button btn;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_six);        new MyOneThread().start();       btn= findViewById(R.id.dian);       btn.setOnClickListener(new View.OnClickListener() {           @Override           public void onClick(View v) {               Message message=Message.obtain();               message.what=1;               message.obj="我是主线程的音讯发送给子线程";               // 封装完数据发送给子线程               handler.sendMessage(message);           }       });     }        class MyOneThread extends Thread{        @Override        public void run() {            //在子线程中解决音讯,子线程中解决音讯,没有默认的Loop            //因为只有主线程成才默认的Looper.prepare(), Looper.loop();            //创立Looper            Looper.prepare();//如果不增加会报错            handler=new Handler(){                @Override                public void handleMessage(@NonNull Message msg) {                    switch (msg.what){                        case 1:                            Log.d("aa",(String) msg.obj);                            break;                    }                }            };            //循环读取messageQueue            Looper.loop();//如果不增加读取不到音讯        }    }}

也能够应用这个形式来获取Looper

   handler=new Handler(Looper.getMainLooper()){                @Override                public void handleMessage(@NonNull Message msg) {                    switch (msg.what){                        case 1:                            Log.d("aa",(String) msg.obj);                            break;                    }                }            };

子线程发送音讯到子线程(子线程----->子线程)

 btn.setOnClickListener(new View.OnClickListener() {           @Override           public void onClick(View v) {            /*   Message message=Message.obtain();               message.what=1;               message.obj="我是主线程的音讯发送给子线程";               // 封装完数据发送给子线程               handler.sendMessage(message);*/               new Thread(new Runnable() {                   @Override                   public void run() {                       Message message=Message.obtain();                       message.obj="我是子线程发送到子线音讯";                       message.what=1;                       handler.sendMessage(message);                   }               }).start();           }       });                      class MyOneThread extends Thread{        @Override        public void run() {            //在子线程中解决音讯,子线程中解决音讯,没有默认的Loop            //因为只有主线程成才默认的Looper.prepare(), Looper.loop();            //创立Looper//            Looper.prepare();            handler=new Handler(Looper.getMainLooper()){                @Override                public void handleMessage(@NonNull Message msg) {                    switch (msg.what){                        case 1:                            Log.d("aa",(String) msg.obj);                            break;                    }                }            };            //循环读取messageQueue//            Looper.loop();        }    }

应用Handler.post()间接更新ui

 private Handler handler=new Handler();  @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_six);       btn= findViewById(R.id.dian);        new Thread(new Runnable() {            @Override            public void run() {             /*   Message message=Message.obtain();                message.obj="我是子线程动态音讯";                message.what=1;                handler.sendMessage(message);*/                handler.post(new Runnable() {                    @Override                    public void run() {                        Log.d("aa","间接更新Ui");                        btn.setText("我是更新的音讯");                    }                });            }        }).start();    }
  1. post和sendMessage实质上是没有区别的,只是理论用法中有一点差异
  2. post也没有独特的作用,post实质上还是用sendMessage实现的,post只是一中更不便的用法而已


面试解答:
1.Looper和Handler肯定要处于一个线程吗?子线程中能够用MainLooper去创立Handler吗?
答:
(1)子线程中Handler handler = new Handler(Looper.getMainLooper());,此时两者就不在一个线程中
(2)能够的。
2.Handler的post办法发送的是同步音讯吗?能够发送异步音讯吗?
答:
用户层面发送的都是同步音讯
不能发送异步音讯
异步音讯只能由零碎发送。
3.Handler.post的逻辑在哪个线程执行的,是由Looper所在线程还是Handler所在线程决定的?
答:
由Looper所在线程决定的
最终逻辑是在Looper.loop()办法中,从MsgQueue中拿出msg,并且执行其逻辑,这是在Looper中执行的,因而有Looper所在线程决定。
4.Handler构造方法中通过Looper.myLooper();是如何获取到以后线程的Looper的?
答:
myLooper()外部应用ThreadLocal实现,因而可能获取各个线程本人的Looper

END:欲穷千里目,更上一层楼