`
andy_叶
  • 浏览: 67976 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Android UI 单线程模型的编程原则以及AsyncTask 原理

阅读更多

导读:oInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecut

  在开发Android应用时必须遵守单线程模型的原则:

  UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

  在单线程模型中始终要记住两条法则:

  1. 不要阻塞UI线程
  2. 确保只在UI线程中访问Android UI工具包

  当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

  比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后,是不能直接在网络操作线程中调用

TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员 。

  android提供了几种在其他线程中访问UI线程的方法。
  Activity.runOnUiThread( Runnable )
  View.post( Runnable )
  View.postDelayed( Runnable, long )
  Hanlder

  这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。

  为了解决这个问题,Android 提供了一个工具类:AsyncTask
  它使创建需要与用户界面交互的长时间运行的任务变得更简单。
  相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。
  AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。
  Params 启动任务执行的输入参数,比如HTTP请求的URL。
  Progress 后台任务执行的百分比。
  Result 后台执行任务最终返回的结果,比如String。

  AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。

  1) 子类化AsyncTask
  2) 实现AsyncTask中定义的下面一个或几个方法

  onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

  doInBackground(Params…), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。

  onProgressUpdate(Progress…),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

  onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

  为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
  1) Task的实例必须在UI thread中创建
  2) execute方法必须在UI thread中调用
  3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法
  4) 该task只能被执行一次,否则多次调用时将会出现异常

  doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

  从网上获取一个网页,在一个TextView中将其源代码显示出来

001 package test.list;
002   
003 import java.io.ByteArrayOutputStream;
004   
005 import java.io.InputStream;
006   
007 import java.util.ArrayList;
008   
009 import org.apache.http.HttpEntity;
010   
011 import org.apache.http.HttpResponse;
012   
013 import org.apache.http.client.HttpClient;
014   
015 import org.apache.http.client.methods.HttpGet;
016   
017 import org.apache.http.impl.client.DefaultHttpClient;
018   
019 import android.app.Activity;
020   
021 import android.app.ProgressDialog;
022   
023 import android.content.Context;
024   
025 import android.content.DialogInterface;
026   
027 import android.os.AsyncTask;
028   
029 import android.os.Bundle;
030   
031 import android.os.Handler;
032   
033 import android.os.Message;
034   
035 import android.view.View;
036   
037 import android.widget.Button;
038   
039 import android.widget.EditText;
040   
041 import android.widget.TextView;
042   
043 public class NetworkActivity extends Activity{
044   
045 private TextView message;
046   
047 private Button open;
048   
049 private EditText url;
050   
051 @Override
052   
053 public void onCreate(Bundle savedInstanceState) {
054   
055 super.onCreate(savedInstanceState);
056   
057 setContentView(R.layout.network);
058   
059 message= (TextView) findViewById(R.id.message);
060   
061 url= (EditText) findViewById(R.id.url);
062   
063 open= (Button) findViewById(R.id.open);
064   
065 open.setOnClickListener(new View.OnClickListener() {
066   
067 public void onClick(View arg0) {
068   
069 connect();
070   
071 }
072   
073 });
074   
075   
076 }
077   
078 private void connect() {
079   
080 PageTask task = new PageTask(this);
081   
082 task.execute(url.getText().toString());
083   
084 }
085   
086 class PageTask extends AsyncTask<String, Integer, String> {
087   
088 // 可变长的输入参数,与AsyncTask.exucute()对应
089   
090 ProgressDialog pdialog;
091   
092 public PageTask(Context context){
093   
094 pdialog = new ProgressDialog(context, 0);
095   
096 pdialog.setButton("cancel", new DialogInterface.OnClickListener() {
097   
098 public void onClick(DialogInterface dialog, int i) {
099   
100 dialog.cancel();
101   
102 }
103   
104 });
105   
106 pdialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
107   
108 public void onCancel(DialogInterface dialog) {
109   
110 finish();
111   
112 }
113   
114 });
115   
116 pdialog.setCancelable(true);
117   
118 pdialog.setMax(100);
119   
120 pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
121   
122 pdialog.show();
123   
124 }
125   
126 @Override
127   
128 protected String doInBackground(String... params) {
129   
130 try{
131   
132 HttpClient client = new DefaultHttpClient();
133   
134 // params[0]代表连接的url
135   
136 HttpGet get = new HttpGet(params[0]);
137   
138 HttpResponse response = client.execute(get);
139   
140 HttpEntity entity = response.getEntity();
141   
142 long length = entity.getContentLength();
143   
144 InputStream is = entity.getContent();
145   
146 String s = null;
147   
148 if(is != null) {
149   
150 ByteArrayOutputStream baos = new ByteArrayOutputStream();
151   
152 byte[] buf = new byte[128];
153   
154 int ch = -1;
155   
156 int count = 0;
157   
158 while((ch = is.read(buf)) != -1) {
159   
160 baos.write(buf, 0, ch);
161   
162 count += ch;
163   
164 if(length > 0) {
165   
166 // 如果知道响应的长度,调用publishProgress()更新进度
167   
168 publishProgress((int) ((count / (float) length) * 100));
169   
170 }
171   
172   
173   
174 // 让线程休眠100ms
175   
176 Thread.sleep(100);
177   
178 }
179   
180 s = new String(baos.toByteArray()); }
181   
182 // 返回结果
183   
184 return s;
185   
186 } catch(Exception e) {
187   
188 e.printStackTrace();
189   
190 }
191   
192 return null;
193   
194 }
195   
196 @Override
197   
198 protected void onCancelled() {
199   
200 super.onCancelled();
201   
202 }
203   
204 @Override
205   
206 protected void onPostExecute(String result) {
207   
208 // 返回HTML页面的内容
209   
210 message.setText(result);
211   
212 pdialog.dismiss();
213   
214 }
215   
216 @Override
217 protected void onPreExecute() {
218   
219 // 任务启动,可以在这里显示一个对话框,这里简单处理
220   
221 message.setText(R.string.task_started);
222   
223 }
224   
225 @Override
226   
227 protected void onProgressUpdate(Integer... values) {
228   
229 // 更新进度
230   
231 System.out.println(""+values[0]);
232   
233 message.setText(""+values[0]);
234   
235 pdialog.setProgress(values[0]);
236   
237 }
238   
239 }
240   
241 }

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics