1.Android UI组件更新简介
Android的UI线程主要负责处理用户的按键事件、用户触屏事件及屏幕绘图事件等,因此开发者的其它操作不应该,也不能阻塞UI线程,否则UI界面将会变的停止响应。Android默认约定当UI线程阻塞超过20秒将会引发ANR异常。不要在UI线程中执行一线耗时的操作。
为了避免UI线程失去响应的问题,Android建议将耗时操作放在新的线程中完成,但是新的线程也可能需要动态更新UI组件:例如需要从网上获取一个页面,然后在TextView中显示,辞职就应该将连接的网络、获取网络数据的操作放在新的线程中,但是获取网络数据以后,新的线程不允许直接更新UI组件。
为了界面新线程无法更新UI组件问题,Android提供了如下几种解决办法:
1.使用Handler实现线程之间的通信
2.Activity.runOnUiThread(Runnable)
3.View.post(Runable)
4.View.postDelayed(Runnable,long)
使用异步新线程更新UI组件时比较简单。
2.Async<>抽象类:
Params:启动任务执行的输入参数的类型。
Progress:后台任务完成的进度值的类型
Result:后台执行任务完成后返回结果的类型。
3.Async子类的使用步骤:
第一步:创建AsyncTask子类(继承AsyncTask的类),并为三个泛型指定类型。如果某个泛型参数不需要指定类型,可将它指定为void。
第二步:根据需要,实现AsyncTask的如下方法
Result doInBackground(Params... params);//后台线程将要完成的任务,该方法可以调用publishProgress(Progress... values)方法更新任务的执行进度
onProgressUpdate(Progress... values);//更新任务的执行进度后,将会处罚该方法
onPreExecute() //在执行后台耗时操作前被调用,一般用于完成一些初始化的工作,例如显示进度条等
onPostExecute(Result result) //当doInBackground()完成后,系统会自动调用该方法,并将doInBackground()的返回值传给该方法。
第三步:调用AsyncTask子类的实例的execute(Params... params)开始执行耗时任务。
4.使用异步的规则:
1.必须在UI线程中创建AsyncTask的实例
2.必须在UI线程中创建AsyncTask的execute()方法
3.AsyncTask的onPreExecute()、onPostExecute(Result result)、doInBackground(Params... params)、onProgressUpdate(Progress... values)方法,由Android系统负责调用。
4.每一个AsyncTask只能被执行一次,多次调用将会引发异常
5.异步任务的示例:
下载一个网络资源显示在TextView中,布局很简单一个TextView和一个Button按钮,下面是Activity的程序代码:
public class AsyncTaskActivity extends Activity { TextView txtHtml ; Button btnDownload; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_asynctask); txtHtml = (TextView)findViewById(R.id.txtHtml); btnDownload = (Button)findViewById(R.id.btnDownload); btnDownload.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { DownTask task = new DownTask(AsyncTaskActivity.this); task.execute(new URL("http://www.ui.cn/"));//http://www.crazyit.org/ethos.php } catch (Exception e){ e.printStackTrace(); } } }); } class DownTask extends AsyncTask<URL,Integer,String>{ ProgressDialog pdialog ;//进度对话框 int hasRead=0; Context mContext; public DownTask(Context ctx){ mContext = ctx; } //重写改方法就是后台线程将要完成的任务。(完成实际的下载任务) @Override protected String doInBackground(URL... params) { StringBuilder sb = new StringBuilder(); try { //创建URL连接对象 URLConnection conn = params[0].openConnection(); //打开conn连接对象的输入流,并将它包装成BufferdReader BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8")); String line = null; while ((line = br.readLine()) !=null){ sb.append(line+"\n"); hasRead++; publishProgress(hasRead); } return sb.toString(); } catch (Exception e){ e.printStackTrace(); } return null; } //当下载完成后,将下载的代码显示出来 @Override protected void onPostExecute(String s) { txtHtml.setText(s); pdialog.dismiss(); } //在下载开始的时候显示一个进度条 @Override protected void onPreExecute() { pdialog = new ProgressDialog(mContext); pdialog.setTitle("任务正在执行中");//设置对话框标题 pdialog.setMessage("任务正在执行中,敬请等待...."); pdialog.setCancelable(false);//设置对话框不能用取消按钮 pdialog.setMax(202); pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pdialog.setIndeterminate(false); pdialog.show(); } //负责随着下载进度的改变更新进度条的进度值 @Override protected void onProgressUpdate(Integer... values) { txtHtml.setText("已经读取了【"+values[0]+"】行!"); pdialog.setProgress(values[0]); } } }
结果图片: