今天看了一个关于Handler的视频,看的有点迷糊,就决定写一点东西记录下,加深下印象。
----------------------------------------------------------------------------------------------------------------------------------------------
首先,Handler是什么东西,Handler中文翻译为处理器,管理者,或者被叫做句柄,句柄这个词语在很多地方都会出现,java啊,C++等语言中都有这个东西。但是句柄这个词语我是一直不理解是什么意思,然后我就百度啊,百度到一个单词,handle,意思是把手,handler的意思那就是把手的柄了。(英语不好,见谅)
然后就好理解了,来看一Handler的功能是什么, 主要接受子线程发送的数据, 并用此数据配合主线程更新UI。从Handler的功能上来看,子线程到达主线程似乎有一道门,而Handler就是这一道门的把手,子线程想给主线程送点东西,或者想从主线程那拿点东西,必须经过Handler的同意。(感觉这Handler有点像山贼,有“此山是我开,此树是我栽”的气势)
事实上,Handler不是一扇门或者是门的把手,而是两个通道,提到通道,我就不由自主地会想到队列,因为这两个实在是太相似了。Handler里有两个消息队列,一个是只能线程通过的,还有一个是数据通过的,前者一般是带post的方法,后者一般是带getmessage和sendmessage的方法,具体方法后面会介绍一点,想看详细,请查阅API。这里再看Handler,觉得Handler又有点像收费站,小轿车走这通道,货车走那个通道,客运车走自己专用的通道。
介绍到这里,相信各位对Handler的概念十分了解了,不得不说,写点东西真的很有帮助,本来看完视频的我,对Handler十分迷糊,但是写到这里,我就感觉,Handler似乎也就那回事,但是关于Handler只是介绍了一点点,重点还没放出来,但是重点并不难,只是Handler的一些方法以及使用时的一些注意点。
在写Handler怎么用之前,我还要铺一点内容,Handler的功能跟线程有关,所以要写点Android里的线程。Android里的线程分两类,一类只有一个,叫做主线程,另一类是自己新建的,叫做子线程。
第一个问题,哪个是主线程呢?
在一个Android 程序开始运行的时候,会单独启动一个Process,一个Process下可以有许多个Thread。但是在这里面只有一个主线程,这个主线程在程序开始运行就被创建,并且是由Android系统创建的,又由于UI的更新只能由这个线程来更新,所以被称为UI线程。
第二个问题,为什么要创建子线程?
首先我是个菜鸟,所以我会有这样的问题。我平时练习,写代码,都不会用到线程,子线程创建了有什么用?我平时写代码,练习,不用多线程都写的好好的,也没有出现ANR啊,用子线程不是多此一举?然后今天看视频,才想到有耗时操作,主线程5秒未响应就会出现ANR这点我知道,但是平时自己写代码基本不会出现主线程5秒未响应。
现在回到Handler的使用。首先要说明的是Handler是一个类,Object的子类,既然是类,那用它就得创建对象。
Handler handler = new Handler();
简单的让人发指。
然后,然后就有点不妙了,按照我最初的想法,是创建两个按钮,一个用来开始运行子线程,另一个是用来结束子线程的运行。然后在第一个按钮的监听器里利用handler.post方法将子线程启动,但是用到handler.post方法时,我才发现,该方法的参数只能是Runnable,那我想,Runnable没关系啊,要是它是Thread的子类,我可以再把它转上去啊,但是一查API,发现Runnable上头并没有Thread。于是,我只能先将就下,以下是第一次的代码,布局文件太简单不列出:
package com.jsdsm.handler;
import android.os.Bundle;
import android.os.Handler;
import android.R.layout;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button startButton;
private Button endButton;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button)findViewById(R.id.start);
endButton = (Button)findViewById(R.id.end);
startButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getId());
handler.post(runnable);
}
});
endButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
handler.removeCallbacks(runnable);
}
});
}
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getId());
handler.postDelayed(runnable, 3000);
}
};
}
写完我一看,坑爹啊,这算什么Handler,这根本还在主线程里,哪有什么子线程。(这里有一个机制,handler.post不会调用runnable里的star方法,也就是说是直接运行run方法)贴上打印结果,证明该程序只有一个线程。
然后就想啊,Thread里面可以传参数,那就可以把runnable传进去再手动启动不就好了。然后代码就变这样了。
package com.jsdsm.handler;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button startButton;
private Button endButton;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button)findViewById(R.id.start);
endButton = (Button)findViewById(R.id.end);
startButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getId());
// handler.post(runnable);
Thread thread = new Thread(runnable);
thread.start();
}
});
endButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
handler.removeCallbacks(runnable);
}
});
}
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getId());
handler.postDelayed(runnable, 3000);
}
};
}
把原来的handler.post注释掉,加了一个thread.start,很显然,这已经跟Handler关系不大了,而且从打印的结果看来,子线程启动之后也仅仅只运行了一次,然后又回到了主线程。
然后我再找,找到了一个HandlerThread。然后下面是第三次的代码:
package com.jsdsm.handler;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button startButton;
private Button endButton;
private Handler handler = new Handler();
HandlerThread handlerThread = new HandlerThread("thread1");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button) findViewById(R.id.start);
endButton = (Button) findViewById(R.id.end);
startButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getId());
// handler.post(runnable);
// Thread thread = new Thread(runnable);
// thread.start();
handlerThread.start();
Thread1 thread1 = new Thread1(handlerThread.getLooper());
thread1.obtainMessage().sendToTarget();
}
});
endButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// handler.removeCallbacks(runnable);
}
});
}
// Runnable runnable = new Runnable() {
//
// @Override
// public void run() {
// // TODO Auto-generated method stub
// System.out.println(Thread.currentThread().getId());
// handler.postDelayed(runnable, 3000);
// }
// };
}
class Thread1 extends Handler {
public Thread1() {
super();
// TODO Auto-generated constructor stub
}
public Thread1(Looper looper) {
super(looper);
// TODO Auto-generated constructor stub
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
System.out.println(Thread.currentThread().getId());
}
}
然后我就找不到子线程了,我试着将MainActivity中的endButton改为public,然后在Thread1中的方法handleMessage中新建了一个MainActivity的对象,调用mainActivity.endButton.setText("1");运行了一下程序,结果程序报错,那Thread1就应该是子线程了吧。