Thread
public class MyThread extends Thread {
@Override
public void run ( ) {
}
}
new MyThread ( ) . start ( ) ;
Runnable
private class MyRunnable implements Runnable {
@Override
public void run ( ) {
}
}
new Thread ( new MyRunnable ( ) ) . start ( ) ;
button. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
Process. setThreadPriority ( Process. THREAD_PRIORITY_BACKGROUND) ;
try {
. . .
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
} ) . start ( ) ;
}
} ) ;
AsyncTask
button. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View view) {
data = null;
data = new ArrayList < String> ( ) ;
adapter = null;
new ProgressTask ( ) . execute ( data) ;
}
} ) ;
private class ProgressTask extends AsyncTask < ArrayList< String> , Void, Integer> {
@Override
protected void onPreExecute ( ) {
showDialog ( PROGRESS_DIALOG) ;
}
@Override
protected Integer doInBackground ( ArrayList< String> . . . datas) {
ArrayList< String> data = datas[ 0 ] ;
for ( int i= 0 ; i< 8 ; i++ ) {
data. add ( "ListItem" ) ;
}
return STATE_FINISH;
}
@Override
protected void onProgressUpdate ( Void. . . values) {
}
@Override
protected void onPostExecute ( Integer result) {
int state = result. intValue ( ) ;
switch ( state) {
case STATE_FINISH:
dismissDialog ( PROGRESS_DIALOG) ;
Toast. makeText ( getApplicationContext ( ) , "加载完成!" , Toast. LENGTH_LONG) . show ( ) ;
adapter = new ArrayAdapter < String> ( getApplicationContext ( ) ,
android. R. layout. simple_list_item_1,
data ) ;
setListAdapter ( adapter) ;
break ;
case STATE_ERROR:
dismissDialog ( PROGRESS_DIALOG) ;
Toast. makeText ( getApplicationContext ( ) , "处理过程发生错误!" , Toast. LENGTH_LONG) . show ( ) ;
adapter = new ArrayAdapter < String> ( getApplicationContext ( ) ,
android. R. layout. simple_list_item_1,
data ) ;
setListAdapter ( adapter) ;
break ;
default :
}
}
ProgressTask
中4个方法都不能手动调用。而且除了 doInBackground(Params...)
方法,其余3个方法都是被UI线程所调用的,所以要求:
AsyncTask的实例必须在UI thread中创建; AsyncTask.execute方法必须在UI thread中调用; 该task只能被执行一次,否则多次调用时将会出现异常。而且是不能手动停止的,这一点要注意,看是否符合需求 在使用过程中,AsyncTask的构造函数的参数设置需要了解AsyncTask< Params, Progress, Result>
Params对应doInBackground ( Params. . . ) 的参数类型
而new AsyncTask ( ) . execute ( Params. . . params) ,就是传进来的Params数据
可以execute ( data) 来传送一个数据,或者execute ( data1, data2, data3) 这样多个数据
Progress对应onProgressUpdate ( Progress. . . ) 的参数类型,表示进度显示单位;
Result对应onPostExecute ( Result) 的参数类型,表示执行结果的类型
当以上的参数类型都不需要指明某个时,则使用Void,注意不是void
和使用Thread()不同的是,多了几处API回调来严格规范工作线程与UI线程之间的交互。我们大部分的业务场景几乎都符合这种规范,比如去磁盘读取图片,缩放处理需要在工作线程执行,最后绘制到ImageView控件需要切换到UI线程。 AsyncTask的几处回调都给了我们机会去中断任务,在任务状态的管理上较之Thread()方式更为灵活。值得注意的是AsyncTask的cancel()方法并不会终止任务的执行,开发者需要自己去检查cancel的状态值来决定是否中止任务。 AsyncTask也有隐式的持有外部类对象引用的问题,需要特别注意防止出现意外的内存泄漏。 AsyncTask由于在不同的系统版本上串行与并行的执行行为不一致,被不少开发者所诟病,这确实是硬伤,绝大部分的多线程场景都需要明确任务是串行还是并行。 线程优先级为background,对UI线程的执行影响极小
Message Queue
在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍 Message
Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。 Handler
Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。 Message Queue
Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。 每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post 。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。 Looper
Message机制的大概流程
在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用该Message的target指向的Hander的dispatchMessage函数对Message进行处理。在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:
Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作; Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理; 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。 由此可见,我们实现的handleMessage方法是优先级最低的! Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收
Handler
概念
Handler, 它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue 中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler 的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出 Message或Runnable,进而操作它们 Handler可以给线程队列发消息 一个Handler对象只能和一个线程(创造它的线程)关联 创建
使用默认的构造方法:new Handler() 使用带参的构造方法,参数是一个Runnable对象或者回调对象 压入消息队列方法
Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)
、postAtTime(Runnable,long)
、postDelayed(Runnable,long)
sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法 有:sendEmptyMessage(int)
、sendMessage(Message)
、 sendMessageAtTime(Message, long)
、sendMessageDelayed(Message, long)
使用Handler的 post
方法
对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作 在Handler中,关于Post方式的方法有:
boolean post(Runnable r)
:把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行。boolean postAtTime(Runnable r, long uptimeMillis)
:把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。boolean postDelayed(Runnable r, long delayMillis)
:把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟delayMills秒执行void removeCallbacks(Runnable r)
:从消息队列中移除一个Runnable对象 package com. bgxt. datatimepickerdemo;
import android. app. Activity;
import android. os. Bundle;
import android. os. Handler;
import android. view. View;
import android. widget. Button;
import android. widget. TextView;
public class HandlerPostActivity1 extends Activity {
private Button btnMes1, btnMes2;
private TextView tvMessage;
private static Handler handler= new Handler ( ) ;
@Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate ( savedInstanceState) ;
setContentView ( R. layout. message_activity) ;
btnMes1= ( Button) findViewById ( R. id. btnMes1) ;
btnMes2= ( Button) findViewById ( R. id. btnMes2) ;
tvMessage= ( TextView) findViewById ( R. id. tvMessage) ;
btnMes1. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
handler. post ( new Runnable ( ) {
@Override
public void run ( ) {
tvMessage. setText ( "使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。" ) ;
}
} ) ;
}
} ) . start ( ) ;
}
} ) ;
btnMes2. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
handler. postDelayed ( new Runnable ( ) {
@Override
public void run ( ) {
tvMessage. setText ( "使用Handler.postDelayed在工作线程中发送一段执行到消息队列中,在主线程中延迟3S执行。" ) ;
}
} , 3000 ) ;
}
} ) . start ( ) ;
}
} ) ;
}
}
使用Handler的 Message
方法
Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重 写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上 Message是一个final类,所以不可被继承。Message封装了线程中传递的消息,如果对于一般的数据,Message提供了 getData()
和 setData()
方法来获取与设置数据,其中操作的数据是一个Bundle对象,这个Bundle对象提供一系列的getXxx()和setXxx()方法用于传递基本数据类型的键值对,对于基本数据类型,使用起来很简单,这里不再详细讲解。而对于复杂的数据类型,如一个对象的传递就要相对复杂一些。在Bundle中提供了两个方法,专门用来传递对象的,但是这两个方法也有相应的限制,需要实现特定的接口,当然,一些Android自带的类,其实已经实现了这两个接口中的某一个,可以直接使用。方法如下:
putParcelable(String key, Parcelable value)
:需要传递的对象类实现Parcelable接口。pubSerializable(String key, Serializable value)
:需要传递的对象类实现Serializable接口。 还有另外一种方式在Message中传递对象,那就是使用Message自带的obj属性传值,它是一个Object类型,所以可以传递任意类型的对象,Message自带的有如下几个属性:
int arg1:参数一,用于传递不复杂的数据,复杂数据使用setData()传递。 int arg2:参数二,用于传递不复杂的数据,复杂数据使用setData()传递。 Object obj:传递一个任意的对象。 int what:定义的消息码,一般用于设定消息的标志。 对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用 Message.obtain()
这个静态的方法或者 Handler.obtainMessage()
获取。Message.obtain()
会从消息池中获取一个Message对象,如果消息池中是空的, 才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。 Handler.obtainMessage()
具有多个重载方法,如果查看源码,会发现其实 Handler.obtainMessage()
在内部也是 调用的 Message.obtain()
public class HandlerMessageActivity1 extends Activity {
private Button btnDown;
private ImageView ivImage;
private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg" ;
private ProgressDialog dialog;
private static int IS_FINISH = 1 ;
@Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate ( savedInstanceState) ;
setContentView ( R. layout. asynctask_activity) ;
btnDown = ( Button) findViewById ( R. id. btnDown) ;
ivImage = ( ImageView) findViewById ( R. id. ivSinaImage) ;
dialog = new ProgressDialog ( this ) ;
dialog. setTitle ( "提示信息" ) ;
dialog. setMessage ( "正在下载,请稍后..." ) ;
dialog. setCancelable ( false ) ;
btnDown. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new MyThread ( ) ) . start ( ) ;
dialog. show ( ) ;
}
} ) ;
}
private Handler handler = new Handler ( ) {
@Override
public void handleMessage ( Message msg) {
if ( msg. what== IS_FINISH) {
byte [ ] data= ( byte [ ] ) msg. obj;
Bitmap bmp= BitmapFactory. decodeByteArray ( data, 0 , data. length) ;
ivImage. setImageBitmap ( bmp) ;
dialog. dismiss ( ) ;
}
}
} ;
public class MyThread implements Runnable {
@Override
public void run ( ) {
HttpClient httpClient = new DefaultHttpClient ( ) ;
HttpGet httpGet = new HttpGet ( image_path) ;
HttpResponse httpResponse = null;
try {
httpResponse = httpClient. execute ( httpGet) ;
if ( httpResponse. getStatusLine ( ) . getStatusCode ( ) == 200 ) {
byte [ ] data = EntityUtils. toByteArray ( httpResponse
. getEntity ( ) ) ;
Message msg = Message. obtain ( ) ;
msg. obj = data;
msg. what = IS_FINISH;
handler. sendMessage ( msg) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
}
}
Message.obtain()
方法具有多个重载方法,大致可以分为两类,一类是无需传递Handler对象,对于这类的方法,当填充好消息后,需要调用 Handler.sendMessage()
方法来发送消息到消息队列中。第二类需要传递一个Handler对象,这类方法可以直接使用 Message.sendToTarget()
方法发送消息到消息队列中,这是因为在Message对象中有一个私有的Handler类型的属性 Target
,当时obtain方法传递进一个Handler对象的时候,会给Target属性赋值,当调用 sendToTarget()
方法的时候,实际在它内部还是调用的 Target.sendMessage()
方法。在Handler中,也定义了一些发送空消息的方法,如:sendEmptyMessage(int what)
、sendEmptyMessageDelayed(int what,long delayMillis)
,看似这些方法没有使用Message就可以发送一个消息,但是如果查看源码就会发现,其实内部也是从 Message.obtain()方法中获取一个Message对象,然后给属性赋值,最后使用sendMessage()发送消息到消息队列中。 Handler中,与Message发送消息相关的方法有
Message obtainMessage()
:获取一个Message对象。boolean sendMessage(Message)
:发送一个Message对象到消息队列中,并在UI线程取到消息后,立即执行。boolean sendMessageDelayed(Message, long)
:发送一个Message对象到消息队列中,在UI线程取到消息后,延迟执行。boolean sendEmptyMessage(int what)
:发送一个空的Message对象到队列中,并在UI线程取到消息后,立即执行。boolean sendEmptyMessageDelayed(int what, long delayMillis)
:发送一个空Message对象到消息队列中,在UI线程取到消息后,延迟执行。void removeMessage()
:从消息队列中移除一个未响应的消息 package com. bgxt. datatimepickerdemo;
import android. app. Activity;
import android. os. Bundle;
import android. os. Handler;
import android. os. Message;
import android. view. View;
import android. widget. Button;
import android. widget. TextView;
public class HandlerMessageActivity2 extends Activity {
private Button btn1, btn2, btn3, btn4, btn5;
private static TextView tvMes;
private static Handler handler = new Handler ( ) {
@Override
public void handleMessage ( android. os. Message msg) {
if ( msg. what == 3 || msg. what== 5 ) {
tvMes. setText ( "what=" + msg. what + ",这是一个空消息" ) ;
} else {
tvMes. setText ( "what=" + msg. what + "," + msg. obj. toString ( ) ) ;
}
} ;
} ;
@Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate ( savedInstanceState) ;
setContentView ( R. layout. message_activity2) ;
tvMes = ( TextView) findViewById ( R. id. tvMes) ;
btn1 = ( Button) findViewById ( R. id. btnMessage1) ;
btn2 = ( Button) findViewById ( R. id. btnMessage2) ;
btn3 = ( Button) findViewById ( R. id. btnMessage3) ;
btn4 = ( Button) findViewById ( R. id. btnMessage4) ;
btn5 = ( Button) findViewById ( R. id. btnMessage5) ;
btn1. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
Message msg = Message. obtain ( ) ;
msg. what = 1 ;
msg. obj = "使用Message.Obtain+Hander.sendMessage()发送消息" ;
handler. sendMessage ( msg) ;
}
} ) . start ( ) ;
}
} ) ;
btn2. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
Message msg = Message. obtain ( handler) ;
msg. what = 2 ;
msg. obj = "使用Message.sendToTarget发送消息" ;
msg. sendToTarget ( ) ;
}
} ) . start ( ) ;
}
} ) ;
btn3. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
handler. sendEmptyMessage ( 3 ) ;
}
} ) . start ( ) ;
}
} ) ;
btn4. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
Message msg = Message. obtain ( ) ;
msg. what = 4 ;
msg. obj = "使用Message.Obtain+Hander.sendMessage()发送延迟消息" ;
handler. sendMessageDelayed ( msg, 3000 ) ;
}
} ) . start ( ) ;
}
} ) ;
btn5. setOnClickListener ( new View. OnClickListener ( ) {
@Override
public void onClick ( View v) {
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
handler. sendEmptyMessageDelayed ( 5 , 3000 ) ;
}
} ) . start ( ) ;
}
} ) ;
}
}
runOnUiThread
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate ( savedInstanceState) ;
setContentView ( R. layout. activity_main) ;
new Thread ( new Runnable ( ) {
@Override
public void run ( ) {
try {
Thread. sleep ( 2000 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
runOnUiThread ( new Runnable ( ) {
@Override
public void run ( ) {
Toast. makeText ( MainActivity. this , "hah" , Toast. LENGTH_SHORT) . show ( ) ;
}
} ) ;
}
} ) . start ( ) ;
}
}
HandlerThread
特点
HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。 但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。 HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。 对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着 退出循环
quit
方法或 quitSafely
方法相同点
将不再接受新的事件加入消息队列 无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息。即在调用了Looper的quit或quitSafely方法之后,消息循环就终结了,这时候再通过Handler调用sendMessage或post等方法发送消息时均返回false,表示消息没有成功放入消息队列MessageQueue中,因为消息队列已经退出了。 不同点
当我们调用Looper的quit方法时,实际上执行了 MessageQueue
中的 removeAllMessagesLocked
方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过 sendMessageDelayed
或通过 postDelayed
等方法发送的需要延迟执行的消息)还是非延迟消息。 当我们调用Looper的 quitSafely
方法时,实际上执行了MessageQueue中的 removeAllFutureMessagesLocked
方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。 需要注意的是Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来
public class MainActivity extends Activity {
private final static String TAG = "MainActivity" ;
private Button mGet;
private TextView mResult;
protected final int MSG_GET = 1 ;
protected final int MSG_RESULT = 2 ;
private HandlerThread mHandlerThread;
private Handler mSubThreadHandler;
private Handler mUiHandler = new Handler ( ) {
public void handleMessage ( Message msg) {
Log. i ( TAG, "mUiHandler handleMessage thread:" + Thread. currentThread ( ) ) ;
switch ( msg. what) {
case MSG_RESULT:
mResult. setText ( ( String) msg. obj) ;
break ;
default :
break ;
}
} ;
} ;
@Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate ( savedInstanceState) ;
setContentView ( R. layout. activity_main) ;
Log. i ( TAG, "onCreate thread:" + Thread. currentThread ( ) ) ;
mGet = ( Button) findViewById ( R. id. get) ;
mGet. setOnClickListener ( new OnClickListener ( ) {
@Override
public void onClick ( View v) {
mSubThreadHandler. sendEmptyMessage ( MSG_GET) ;
}
} ) ;
mResult = ( TextView) findViewById ( R. id. result) ;
initHandlerThraed ( ) ;
}
private void initHandlerThraed ( ) {
mHandlerThread = new HandlerThread ( "handler_thread" ) ;
mHandlerThread. start ( ) ;
Looper loop = mHandlerThread. getLooper ( ) ;
mSubThreadHandler = new Handler ( loop) {
public void handleMessage ( Message msg) {
Log. i ( TAG, "mSubThreadHandler handleMessage thread:" + Thread. currentThread ( ) ) ;
switch ( msg. what) {
case MSG_GET:
try {
Thread. sleep ( 1000 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
double number = Math. random ( ) ;
String result = "number:" + number;
Message message = new Message ( ) ;
message. what = MSG_RESULT;
message. obj = result;
mUiHandler. sendMessage ( message) ;
break ;
default :
break ;
}
} ;
} ;
}
@Override
protected void onDestroy ( ) {
super . onDestroy ( ) ;
Log. i ( TAG, "onDestroy" ) ;
mHandlerThread. quit ( ) ;
}
}
ThreadPoolExecutor
IntentService