天天看点

再次理解handler,自己写一个小例子替代handler

读了很多文章,又一次想深刻理解handler,但总是有不解。感觉handler、messageQueue、looper搞的这么高深,不就是定义了一个全局的集合(主线程定义的)变量messgeList,子线程拿到这个全局集合变量messageList,往里面放Messae,主线程写一个死循环遍历这个集合吗?这样的话,我为什么要用什么handler,我自己随便写几行代码不就可以替代handler吗?

代码如下:

import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;

/**
 * handler没什么大不了的,自己写一个小例子替代handler,messageQueue,Looper
 *
 * @date 2019/12/2 16:13
 */
public class MainActivity extends AppCompatActivity {

    private TextView tv_hello;
    private static  LinkedList<MyMessage> messageList = new LinkedList<>();
    private OnMessageOperator operator = new OnMessageOperator() {
        @Override
        public void operateMessage(MyMessage message) {
            tv_hello.setText(message.name);
        }
    };

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

        while (true){
            if(!messageList.isEmpty()){
                MyMessage message = messageList.pop();
                operator.operateMessage(message);
            }
        }
    }

    private void refresh() {
        if (!messageList.isEmpty()) {
            MyMessage myMessage = messageList.pop();
            operator.operateMessage(myMessage);
        }
    }


    public static  class SubThread extends Thread {
        @Override
        public void run() {
            super.run();

            new Timer().schedule(new TimerTask() {
                int i = 1;

                @Override
                public void run() {
                    MyMessage message = new MyMessage();
                    message.name = "更新数字" + (i++);
                    message.type = 1;
                    message.param1 = "10";

                    messageList.push(message);
                }
            }, 1000, 1000);
        }

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        messageList.clear();
        messageList = null;
    }
}
           
public class MyMessage {
    public String name;
    public int type;
    public String param1;
}
           
public interface OnMessageOperator {

    void operateMessage(MyMessage message);

}
           

代码就是这样,模仿handler的的集成方式,是不是很像啊。

但是调试发现,operateMessage 执行了,但UI就是不刷新。思考了一下才发现onCreate里面的while死循环会让onCreate方法一直执行,Activity生命周期后面的代码比如onResume啊之类的都执行不到,所以UI当然不能显示了。但是Looper也执行了死循环,为什么能够刷新UI呢,这就是Looper的特别之处。因为系统在UI线程提供的Looper的循环体里包含了对整个Activity的生命周期的执行过程。这是一个大的循环,Activity的执行,UI的刷新都在这个大循环里,这个循环执行一次UI就刷新了一次,所以这个循环不会阻塞UI线程,不会导致ANR。

再次理解handler,自己写一个小例子替代handler
public static final void loop() {
        Looper me = myLooper();  
        MessageQueue queue = me.mQueue;  
        // 开始了死循环
        while (true) {  
            Message msg = queue.next(); // might block  
            if (msg != null) {
                if (msg.target == null) {  
                    return;  
                }  
                if (me.mLogging!= null){
               me.mLogging.println(   ">>>>> Dispatching to " + msg.target + " "    + msg.callback + ": " + msg.what   );  
            }
                msg.target.dispatchMessage(msg);  
                if (me.mLogging!= null) {
               me.mLogging.println(    "<<<<< Finished to    " + msg.target + " "   + msg.callback);  
            }
                msg.recycle();  
            }
        }
    }
           
public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                case RELAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;
                    handleRelaunchActivity(r);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                case PAUSE_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2, (msg.arg1&2) != 0);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case PAUSE_ACTIVITY_FINISHING:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, true, (msg.arg1&1) != 0, msg.arg2, (msg.arg1&1) != 0);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case STOP_ACTIVITY_SHOW:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
                    handleStopActivity((IBinder)msg.obj, true, msg.arg2);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case STOP_ACTIVITY_HIDE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
                    handleStopActivity((IBinder)msg.obj, false, msg.arg2);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SHOW_WINDOW:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow");
                    handleWindowVisibility((IBinder)msg.obj, true);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case HIDE_WINDOW:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");
                    handleWindowVisibility((IBinder)msg.obj, false);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case RESUME_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
                    handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SEND_RESULT:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
                    handleSendResult((ResultData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

            ...........
}
           

Looper在循环的时候,调用了Activity的生命周期方法,就不会像我们自己写的while循环一样,会让Activity生命周期对应的方法不能完整执行,当然UI就显示不出来了。

虽然系统提供的Handler,Looper比较特殊,能很好的刷新UI,但到了这里我们也不能认怂了,毕竟我们对handler,messageQueue,looper的理解思路是对的啊。我们现在遇到的问题就是怎么样在主线程中隔一段时间遍历一次messageList集合,取出一个message,现在不能用while了,用Timer,TimerTask也不行,因为Task也是个子线程。多方尝试,最后发现用CountDownTimer可以。

import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;

/**
 * handler没什么大不了的,自己写一个小例子替代handler,messageQueue,Looper
 *
 * @author [email protected]
 * @date 2019/12/2 16:13
 */
public class MainActivity extends AppCompatActivity {

    private TextView tv_hello;
    private static  LinkedList<MyMessage> messageList = new LinkedList<>();
    private OnMessageOperator operator = new OnMessageOperator() {
        @Override
        public void operateMessage(MyMessage message) {
            tv_hello.setText(message.name);
        }
    };

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

//        while (true){
//            if(!messageList.isEmpty()){
//                MyMessage message = messageList.pop();
//                operator.operateMessage(message);
//            }
//        }

        new CountDownTimer(1000000000, 100) {
            @Override
            public void onTick(long millisUntilFinished) {
                refresh();
            }

            @Override
            public void onFinish() {

            }
        }.start();
    }

    private void refresh() {
        if (!messageList.isEmpty()) {
            MyMessage myMessage = messageList.pop();
            operator.operateMessage(myMessage);
        }
    }


    public static  class SubThread extends Thread {
        @Override
        public void run() {
            super.run();

            new Timer().schedule(new TimerTask() {
                int i = 1;

                @Override
                public void run() {
                    MyMessage message = new MyMessage();
                    message.name = "更新数字" + (i++);
                    message.type = 1;
                    message.param1 = "10";

                    messageList.push(message);
                }
            }, 1000, 1000);
        }

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        messageList.clear();
        messageList = null;
    }
}
           

运行效果如下:

再次理解handler,自己写一个小例子替代handler

实现在子线程定时通知UI线程更新UI的任务,同时没有使用Handler机制。虽说是实现了,当然这种方式肯定不好,总有一天倒计时结束就更新不了UI了,还是要用handler,我写这个的目的只是为了加强对handler消息机制的理解。