读了很多文章,又一次想深刻理解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。
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;
}
}
运行效果如下:
实现在子线程定时通知UI线程更新UI的任务,同时没有使用Handler机制。虽说是实现了,当然这种方式肯定不好,总有一天倒计时结束就更新不了UI了,还是要用handler,我写这个的目的只是为了加强对handler消息机制的理解。