Handler使用的整理

作者: 蜡笔小州 | 来源:发表于2017-10-30 15:14 被阅读66次
介绍
  1. Message
    消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。
  2. Message Queue
    消息队列,用来存放通过Handler发布的消息,//按照先进先出执行(这句话是错的!)。
  3. Handler
    有俩用途:1、用于子线程与主线程之间的通讯 2、用于向子线程发出消息请求。Handler是Message的主要处理者,是Android提供的一套ui处理机制,负责将Message添加到消息队列以及对消息队列中的Message进行处理。
  4. Looper
    循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。
  5. 线程
    UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。
异常
  • Only the original thread that created a view hierarchy can touch its views.
    这个异常就是在子线程中进行更新ui操作抛出的,android的设计的时候,就封装了一套消息创建、传递、处理机制。比如我们不按要求在子线程去更新ui的话就会抛出以上异常。不过我们看一下下面的代码:
public class MyActivity 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("OtherThread");
            }
        }).start();
    }
}

我们知道这段代码中在子线程进行了ui的操作,不过我们的代码是可以运行的,我们看一下定义异常的地方就知道了。

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { ………………………… 
      void checkThread() { 
      if (mThread != Thread.currentThread()) { 
            throw new CalledFromWrongThreadException( "Only the original        thread that created a view hierarchy can touch its views.");
       }
    } 
…………………… 
}

setText在源码中会调用checkforlayout方法然后invalidate。然后在checkThread里面判断thread和uiThread是否相等然后抛异常。
不能更新ui是因为ViewRootImpl的checkThread()的检查,而ViewRootImpl是在onResume()的方法中创建的,所以在onCreate中没有穿件ViewRootImpl,所以不抛异常,如果耗时的话才会抛出异常。比如我们在setText前面加上一个延迟。

  • 内存泄漏
@Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        mHandler.sendMessageDelayed(Message.obtain(), 10000);  
        finish();  
    }  

为什么会泄漏?
Handler 的生命周期与Activity 不一致;
引用 Activity 阻止了GC对Acivity的回收。

如何防止?
静态内部类,外部类
WeakReference

private static class MyHandler extends Handler{
}

然后

mHandler.removeCallbacks(mRunnable);  
//或者
mHandler.removeCallbacksAndMessages(null);
用法

-post

private Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        
                    }
                }))
            }
        }).start();
这里直接使用的post进行处理,run回调下可以进行ui更新,更加轻便,postDelay还可以实现延迟效果。

-sendMessage

        Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
这里使用了handlerMessage的回调,通过msg来传递信息,更加实用。
Message message = new Message();
handler.sendMessage(message);
Message msg = mHandler.obtainMessage();
msg.sendToTarget();

obtainmessage()是从消息池中拿来一个msg 不需要另开辟空间;
new需要重新申请,效率低,obtianmessage可以循环利用;
removeCallback 从队列中移除消息。

子线程间的通讯

在子线程中使用时需要手动添加代码loop,主线程其实也需要,只不过我们的android架构已经帮我们实现了。
handler与子线程的关联:

class Thread extends Thread{
      public Handler handler;
      @Override
      public void run(){
            Looper.prepare();
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                      super.handleMessage(msg);
                  }
             };
            Looper.loop();
      } 
}
private MyThread thread;
thread = new MyTread();
thread.start();
thread.handler.sendEmptyMessage();

handler在哪个线程定义,而looper特殊传入的话,则回调在哪个线程,所以在主线程的handlerMessage不要进行耗时处理。

handlerThread

在子线程定义thead

class Thread extends Thread{
      public Handler handler;
      public Looper looper;
      @Override
      public void run(){
            Looper.prepare();
            looper = Looper.myLooper();
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                      super.handleMessage(msg);
                  }
             };
            Looper.loop();
      } 
}

将loop传递进来:

Handler handler = new Handler(thread.looper){
       @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
       }
};
handler.sendEmptyMessage();

这里涉及到了一个多线程并发的问题,我们主线程中new Handler()中使用子线程的looper而子线程中looper还没有创建成功,而出现没有looper的问题。这时候需要使用handlerThread。handlerThread使用了wait来等待looper的创建。

thread = HandlerThread("handler thread");
thread.start();
handler = new Handler(thread.getlooper()){
      public void handlerMessage(android.os.Message msg){
      }
}
handler.sendEmptyMessage();

用handlerthread线程的话,可以等待looper实例创建好再发送。

子线程主线程通讯
Handler threadHandler;
Handler handler = new Handler(){
     @Override
      public void handleMessage(Message msg) {
             super.handleMessage(msg);
              threadHandler.sendMessageDelayed(msg1,1000);
      }
};
HandlerThread thread = new HandlerThread("handler thread");
thread.start();
threadHandler = new Handler(thread.getlooper()){
      @Override
      public void handleMessage(android.os.Message msg){
           handler.sendMessageDelayed(msg1,1000);
      }
}
更新ui的方式
  • handler.post
  • sendMessage
  • runOnUiThread
  • view.post
    这个很实用比如某些动画需要实现,而view没有初始化成功导致动画或者其他效果失效,这里可以使用这个方法。
WeakHandler

weakHandler是一个避免内存泄漏的handler库,使用方法和handler基本一致,但是我们要理解一下weakReference,就是弱引用,我们知道java中我们开发人员虽然不需要在意内存回收,可是在使用方面可以做到尽可量的优化,在我们使用弱引用的时候,我们的这个对象,如果他没有没其他对象引用,就会被gc,反着如果强引用的话就不会gc了。
这里我们拓展一下:

  • 强引用(StrongReference)
    只要引用存在,垃圾回收器永远不会回收,也是我们默认的引用。
  • 软引用(SoftReference)
    非必须引用,内存溢出之前进行回收。
  • 弱引用(WeakReference)
    谷歌更推荐这个使用,这个在垃圾搜索器搜索到这个对象时就会进行回收。
    软引用和弱引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。
  • 虚引用(PhantomReference)
    虚引用用处不详..我理解为gc时候就会把虚引用一起回收了。
    总结为,强引用只要有引用就绝不回收,弱引用是oom前,软引用是垃圾回收的时候回收。

这里再介绍一个消息通知的框架 可以用于换肤等:

public class UIMessageCenter {

    private final static int UI_MSG_CHANFE_SKIN = 1;
    private static UIMessageCenter Intance = null;
    private List<WeakReference<IonMessage>> mOnMsgList = null;
    private WeakHandler mHanderUI = null;

    private UIMessageCenter() {
        mOnMsgList = new ArrayList<WeakReference<IonMessage>>();
        createHandler();
    }

    public static UIMessageCenter getIntance() {
        if (Intance == null) {
            Intance = new UIMessageCenter();
        }
        return Intance;
    }

    private void createHandler() {
        mHanderUI = new WeakHandler() {
            @Override
            public void handleMessage(Message msg) {

                if (mOnMsgList != null && mOnMsgList.size() > 0) {
                    for (int i = 0; i < mOnMsgList.size(); i++) {
                        WeakReference<IonMessage> fun = mOnMsgList.get(i);
                        if (fun != null) {
                            IonMessage ionMsg = fun.get();
                            if (ionMsg != null) {
                                HttpLog.d("handleMessage", "createHandler");
                                ionMsg.onMessage(msg);
                            }
                        }
                    }
                }
            }
        };
    }

    public void registerFun(IonMessage fun) {
        if (mOnMsgList != null && fun != null) {
            mOnMsgList.add(new WeakReference<IonMessage>(fun));
        }
    }

    public void removeFun(IonMessage fun) {
        if (mOnMsgList != null && fun != null) {
            mOnMsgList.remove(new WeakReference<IonMessage>(fun));
        }
    }

    /**
     * 通知换肤
     *
     * @param arg1
     * @param arg2
     * @param obj
     */
    public void notifyChangeSkin(int arg1, int arg2, Object obj) {
        if (mHanderUI != null) {
            mHanderUI.sendMessage(mHanderUI.obtainMessage(UI_MSG_CHANFE_SKIN, arg1, arg2, obj));
        }
    }
    
}
public interface IonMessage {
    void onMessage(Message msg);
}

使用方法:

class MyActivity extend Activity implements IonMessage{
      @Override
       public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          UIMessageCenter.getIntance().registerFun(this);
       }
      @Override
       public void onDestroy() {
          super.onDestroy();
          UIMessageCenter.getIntance().removeFun(this);
       }
      @Override
      public void onMessage(Message msg) {
        switch (msg.what) {
            case UIMessageCenter.UI_MSG_CHANFE_SKIN:
                changeSkin();
                break;
            default:
                break;
        }
    }
}

转载请注明出处:http://www.jianshu.com/p/e3248d737ced

相关文章

网友评论

    本文标题:Handler使用的整理

    本文链接:https://www.haomeiwen.com/subject/hqqppxtx.html