Android多线程(01)
一、 单线程模型:
Message Queue消息队列,用来存放Handler发布的消息。
Looper扮演着Handler和消息队列之间桥梁的角色;程序组件首先通过Handler把消息传递给Looper,Looper把消息放入队列中;Looper也把消息队列中的消息广播给所有的Handler,Handler接收到消息后调用handleMessage方法进行处理。
二、 多线程实现:
Android是单线程模型,这意味着Android UI操作并不是线程安全的,当某些可能耗时的操作需要执行时,最好将其放入到一个新的线程中。
1. Activity.runOnUiThread(Runnable())
如果当前线程是UI线程,则行动立即执行;否则行动是发布到UI线程的事件队列中。
runOnUiThread(new Runnable() { // 如果是UI线程,操作将立即执行;如果不是UI线程,操作将放到UI线程的事件队列中执行 @Override public void run() { Log.i(tag, "runOnUiThread run method execute."); relativeLayout.setBackgroundResource(R.drawable.bg); updateUIButton.setText(getString(R.string.restore_ui)); updateUI2Button.setText(getString(R.string.restore_ui)); isClick = false; } }); |
2. Handler
在当前UI线程中创建一个新的线程UIThread,将封装的数据Bundle放入到Message中,并通过Handler.sendMessage(Message)将Message放入到消息队列中;使用Handler.handleMessage(Message)获取消息队列中的Message。
@SuppressLint("HandlerLeak") private class UIHandler extends Handler { @Override public void handleMessage(Message msg) { Log.i(tag, "handleMessage method execute."); super.handleMessage(msg); if (isClick) { Bundle bundle = msg.getData(); int bgImage = bundle.getInt("bgImage"); relativeLayout.setBackgroundResource(bgImage); updateUIButton.setText(getString(R.string.restore_ui)); updateUI2Button.setText(getString(R.string.restore_ui)); isClick = false; } else { relativeLayout.setBackgroundDrawable(null); updateUIButton.setText(getString(R.string.update_ui)); updateUI2Button.setText(getString(R.string.update_ui)); isClick = true; } } }
private class UIThread extends Thread { @Override public void run() { Log.i(tag, "UIThread run method execute."); Message message = new Message(); Bundle bundle = new Bundle(); bundle.putInt("bgImage", R.drawable.bg); message.setData(bundle); uiHandler.sendMessage(message); } }
uiHandler = new UIHandler(); UIThread uiThread = new UIThread(); uiThread.start(); |
3. View.post(Runnable())
在当前UI主线程中,将Runnable加入到消息队列中。
updateUI3Button.post(new Runnable() { @Override public void run() { Log.i(tag, "The post method execute."); if (isClick) { relativeLayout.setBackgroundResource(R.drawable.bg); updateUIButton.setText(getString(R.string.restore_ui)); updateUI2Button.setText(getString(R.string.restore_ui)); updateUI3Button.setText(getString(R.string.restore_ui)); updateUI4Button.setText(getString(R.string.restore_ui)); isClick = false; } else { relativeLayout.setBackgroundDrawable(null); updateUIButton.setText(getString(R.string.update_ui)); updateUI2Button.setText(getString(R.string.update_ui)); updateUI3Button.setText(getString(R.string.update_ui)); updateUI4Button.setText(getString(R.string.update_ui)); isClick = true; } } }); |
4. View.postDelayed(Runnable(),longdelayMillis)
在当前UI主线程中,将Runnable加入到消息队列中,在设置的时间间隔delayMillis之后执行。
updateUI4Button.postDelayed(new Runnable() { @Override public void run() { Log.i(tag, "The postDelayed method execute."); if (isClick) { relativeLayout.setBackgroundResource(R.drawable.bg); updateUIButton.setText(getString(R.string.restore_ui)); updateUI2Button.setText(getString(R.string.restore_ui)); updateUI3Button.setText(getString(R.string.restore_ui)); updateUI4Button.setText(getString(R.string.restore_ui)); isClick = false; } else { relativeLayout.setBackgroundDrawable(null); updateUIButton.setText(getString(R.string.update_ui)); updateUI2Button.setText(getString(R.string.update_ui)); updateUI3Button.setText(getString(R.string.update_ui)); updateUI4Button.setText(getString(R.string.update_ui)); isClick = true; } } }, 5000); |
5. AsyncTask<Params,Progress,Result>
AsyncTask比Handler更轻量级,适用于简单的异步处理,其定义了三种泛型参数:
1) Params:启动任务执行的输入参数,比如HTTP的URL;
2) Progress:后台任务执行的百分比;
3) Result:后台任务执行的最终返回结果,比如String。
使用AsyncTask类,必须遵守以下准则:
1) Task的实例必须在UI线程中执行;
2) execute方法必须在UI线程中调用;
3) 不要手动调用onPreExecute(),doInBackground(Integer… params),onProgressUpdate(Integer… values)和onPostExecute(String result);
4) 该Task只能调用一次,否则多次调用会出现异常。
MyAsyncTask myAsyncTask = new MyAsyncTask(textView, progressBar, activity); myAsyncTask.execute(1000,900);
package com.xuwan.android01; import android.app.Activity; import android.os.AsyncTask; import android.util.Log; import android.widget.ProgressBar; import android.widget.TextView;
/** * @author SJC * */ public class MyAsyncTask extends AsyncTask<Integer, Integer, String> { private static String tag = "MyAsyncTask"; private TextView textView; private ProgressBar progressBar; private Activity activity;
/** * 构造方法 * * @param textView * @param progressBar */ public MyAsyncTask(TextView textView, ProgressBar progressBar,Activity activity) { super(); this.textView = textView; this.progressBar = progressBar; this.activity = activity; }
/** 该方法运行于UI主线程中 **/ @Override protected void onPreExecute() { Log.i(tag, "The onPreExecute method execyte."); textView.setText(activity.getString(R.string.on_pre_execute)); }
/** * 后台执行,执行比较耗时的操作 <br/> * 参数params对应AsyncTask中的第一个参数,类型为Integer<br/> * 返回值对应AsyncTask中的第三个参数,类型为String<br/> * 该方法并不运行于UI线程中,主要用于异步操作,在该方法中不能对UI进行操作,<br/> * 但可以调用publishProgress方法触发onProgressUpdate方法对UI进行操作 **/ @Override protected String doInBackground(Integer... params) { Log.i(tag, "The doInBackground method execute."); textView.setText(activity.getString(R.string.do_in_background)); NetOperator netOperator = new NetOperator(); int i = 0; for (i = 10; i <= 100; i += 10) { netOperator.operate(); publishProgress(i); } Log.i(tag, "params:" + params[0] + "|" + params[1]); return i + params[0].intValue() + ""; }
/** * 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 * 此方法在主线程执行,任务执行的结果作为此方法的参数返回 **/ @Override protected void onPostExecute(String result) { Log.i(tag, "The onPostExecute method execute."); textView.setText(activity.getString(R.string.on_post_execute)); Log.i(tag, "result:" + result); }
/** * 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。<br/> * 参数values对应AsyncTask中第二个参数,类型为Integer **/ @Override protected void onProgressUpdate(Integer... values) { Log.i(tag, "The onProgressUpdate method execute."); int value = values[0]; progressBar.setProgress(value); }
/** 用户调用取消的操作 **/ @Override protected void onCancelled() { Log.i(tag, "The onCancelled method execute."); super.onCancelled(); } } |
三、 总结:
1. Android系统是单线程系统,为了实现多线程效果,采用了message queue;
2. 为实现多线程,可采用runOnUiThread、Handler、post、postDelay和AsyncTask技术实现。