异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。
一、使用的优点:
结构清晰,功能定义明确 对于多个后台任务时,简单,清晰 使用的缺点:在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
二、Handler 、 Looper 、Message 这三者的关系总结:1、首先Looper.PRepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。好了,总结完成,大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢,这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。
三、Looper主要作用: 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。 private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); } 在构造方法中,创建了一个MessageQueue(消息队列)。 public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(true)); } 这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例。
四、在子线程中创建handler:
其实Handler不仅可以更新UI,你完全可以在一个子线程中去创建一个Handler,然后使用这个handler实例在任何其他线程中发送消息,最终处理消息的代码都会在你创建Handler实例的线程中运行。 new Thread(){ private Handler handler; public void run() { Looper.prepare(); handler = new Handler() { public void handleMessage(android.os.Message msg) { Log.e("TAG",Thread.currentThread().getName()); }; };
一、使用的优点: 简单,快捷 、过程可控 使用的缺点:在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
二、主要方法介绍:
doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。 onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回 onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。 onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。 onCancelled() 用户调用取消时,要做的操作
三、使用AsyncTask类,以下是几条必须遵守的准则: Task的实例必须在UI thread中创建; execute方法必须在UI thread中调用; 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法; 该task只能被执行一次,否则多次调用时将会出现异常;
四、实例说明:
创建一个asynctask:
/** * 执行的顺序: * onPreExecute() ---> doInBackground() ---> publishProgress() ---> onProgressUpdate() ....---> onPostExecute() * ...表示:publishProgress() ---> onProgressUpdate() */public class MyAsyncTask extends AsyncTask<Integer , Object , String>{ private TextView tv; public MyAsyncTask(TextView textView){ Log.e(TAG , "调用到了构造函数"); this.tv = textView; } /** * 这里的Integer参数对应AsyncTask中的第一个参数 * 这里的String返回值对应AsyncTask的第三个参数 * 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改 * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作 */ @Override protected String doInBackground(Integer[] params) { int i; for (i = 0; i <= 100; i++) { publishProgress(i); //会将这个值传递给onProgressUpdate()方法 SystemClock.sleep(1000); } Log.e(TAG , "调用到了doInBackground i = " + i ); return i + ""; } /** * 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。 */ @Override protected void onPreExecute() { Log.e(TAG , "调用到了onPreExecute"); super.onPreExecute(); tv.setText("开始执行异步操作了"); } /** * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值) * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置 */ @Override protected void onPostExecute(String result) { Log.e(TAG , "调用到了onPostExecute result = " + result ); super.onPostExecute(result); tv.setText(result); } /** * 这里的Intege参数对应AsyncTask中的第二个参数 * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行 * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作 */ @Override protected void onProgressUpdate(Object... values) { Log.e(TAG , "调用到了onProgressUpdate value = " + values); super.onProgressUpdate(values); tv.setText(values[0] + ""); }}执行异步操作:
MyAsyncTask task = new MyAsyncTask(tv_show);task.execute();
新闻热点
疑难解答