Android面试相关

Handle的使用场景

2019-03-01  本文已影响10人  北国雪WRG

Handler运行机制

Handler的消息机制如下图所示,主要包含两个消息队列,一个是消息的回收队列,另一个是Message Q队列。

        Message message = Message.obtain(); // 从消息回收队列中回收
        Message message1 = new Message(); // 创建新的消息
        handlerUI.sendEmptyMessage(11);//立刻发送空的消息
        handlerUI.sendMessage(message);//立刻发送携带数据的消息
        handlerUI.sendMessageDelayed(message,1000);//延迟1000ms后发送携带数据的消息
        handlerUI.post(runnable);// 切换回主线程执行run方法,注意runnable的run()是可以被单独执行的
handler 机制

使用Handler向主线程发送消息

这个的关键是使用主线程的looper创建Handler

本次以子线程向主线程发送消息为例:

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private static final int HANDLER_UI = 1;

    //运行在主线程的Handler:使用Android默认的UI线程中的Looper
    public Handler handlerUI = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case HANDLER_UI:
                    String strData = (String) msg.obj;
                    textView.setText(strData);    
                    break;

                default:
                    break;
            }
        }
    };

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

        textView = (TextView) findViewById(R.id.tv);
        findViewById(R.id.btn_ui).setOnClickListener(v->{
            new Thread(()->{
                Message message = Message.obtain();
                message.what = HANDLER_UI;
                message.obj = "发送消息的线程名称:" + Thread.currentThread().getName();
                handlerUI.sendMessage(message);
            }).start();
        });
    }
}

运行结果如下:

image

上述代码有一定的隐患,因为如此使用Handler会导致内存泄露,此处是为了举例简洁才如此使用,正常使用Handler时要避免这种方式,解决这种导致内存泄露可通过——WeakReference(弱引用),后面会详细介绍。

使用Handler向子线程发送消息

使用子线程的looper创建handler

    private Handler threadHandler;  
    private static final int HANDLER_THREAD = 2;

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

        createLooperHandler();

        Message message = Message.obtain();
        message.obj = "发送的线程:" + Thread.currentThread().getName();
        threadHandler.sendMessage(message);
    }

    /**
     * 创建一个可以包含looper的子线程,并开启
     */
    private void createLooperHandler() {
        MyThread myThread = new MyThread();
        myThread.start();

        threadHandler = new Handler(myThread.threadLooper) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //添加上当前线程名称
                String thrMsg = (String) msg.obj + "\n 收到的线程:" + Thread
                              .currentThread().getName();
                }
            }
        };
    }

// 创建带有looper的线程,可以用HandlerThread替代
    private class MyThread extends Thread {
        private Looper threadLooper;
        @Override
        public void run() {
            Looper.prepare();
            threadLooper = Looper.myLooper();
            Looper.loop();
        }
    }
}

HandlerThread的使用

HnadlerThread是Thread的子类,是专门向子线程发送消息使用的。使用步骤如下:

 private Handler handlerThreadHandler;
 private static final int HANDLER_THREAD_HANDLER = 3;

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

        createHandlerThread();

        message.obj = "发送的线程:" + Thread.currentThread().getName();
        handlerThreadHandler.sendMessage(message);
    }

    private void createHandlerThread() {
        HandlerThread handlerThread = new HandlerThread("handler_name1");
        handlerThread.start();

        handlerThreadHandler = new Handler(handlerThread.getLooper()) {

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                String thrMsg = (String) msg.obj + "\n 收到的线程:" + Thread.currentThread().getName();
            }
        };
    }

Handler内存泄露

前面说到,使用Handler时最需要注意的就是内存泄露问题,内存泄露通俗来讲就是:对象使用完成将要回收,但是对象的引用还被其他类所持有,导致对象无法被GC回收。当前通用的解决方案是:Handler使用静态类,内部通过弱引用的方式来持有对象的引用。具体如下:

public static class MyHandler extends Handler {
        WeakReference<Activity> mWeakReference;

        public MyHandler(Activity activity) {
            mWeakReference = new WeakReference<Activity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            Activity activity = mWeakReference.get();
            if (activity == null) {
                return;
            }

            switch (msg.what) {
                case 101:
                    adapter.notifyDataSetChanged();
                    break;

                default:
                    break;
            }
        }
    }

Handler 中post和send的区别

有的时候我们想把一个动作传到主线程中执行,比如一个方法。

  1. 我们可以用Handler.post(new Runnable(){})来发送。执行的动作写在run方法中即可。
  2. 如果传入的是runnable,handler会自动将其封装为message
  3. looper获取到了message之后,会判断是否存在runnable对象。如果存在则直接执行runnable.run()。注意这里执行的不是runnable.start()
  4. 所以最后run是在looper所在线程执行的,而不是在子线程中执行。

Android开发中对Handler使用的一些总结 删改自该文

从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露) 引用该文

上一篇 下一篇

猜你喜欢

热点阅读