`
andy_叶
  • 浏览: 69123 次
  • 性别: 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 }

分享到:
评论

相关推荐

    android 单线程 多线程下载

    首先,我们了解下Android中的线程模型。主线程,也被称为UI线程,主要用于处理用户界面的交互。为了不阻塞主线程,使得用户界面保持流畅,后台任务如文件下载通常会放在其他线程中执行。这就涉及到单线程和多线程的...

    Android开发中的多线程编程技术

    二、Android中的线程模型 1. Handler-Looper-Messenger:通过Handler、Looper和Message对象在主线程和工作线程之间传递消息,进行同步或异步通信。 2. AsyncTask:轻量级的多线程解决方案,适合短时间的后台任务,...

    对Android App UI线程的一点理解

    由于UI线程是单线程模型,因此所有与UI相关的操作都必须在这个线程中进行。这就带来了一个问题:如果UI线程执行了耗时的操作(如网络请求或数据库操作),那么会导致应用无响应,用户体验下降,甚至被系统杀死。 ...

    android多线程高效编程

    3. 单线程与多线程应用的区别:单线程应用是一种简单的执行模型,所有任务按顺序执行,易于理解,但在执行耗时任务时,用户体验差。多线程应用则允许多个任务同时执行,可以提升性能和响应速度,但需要处理线程同步...

    Android 线程更新UI

    在学习和实践中,理解Android线程模型和正确更新UI的方法对于提升应用性能和用户体验至关重要。确保遵循最佳实践,避免主线程阻塞,合理安排任务执行,以及正确处理线程间的通信。通过实践和调试,你将能熟练掌握...

    安卓UI线程机制 ,在子线程中访问UI

    主线程遵循单线程模型,确保UI组件的操作按顺序执行,避免了竞态条件和不必要的同步开销。 2. Looper和MessageQueue:主线程内有一个Looper对象,它维护了一个MessageQueue(消息队列)。当一个任务需要在主线程中...

    Android编程中关于单线程模型的理解与分析

    在Android编程中,单线程模型是一个至关重要的概念,它涉及到UI交互的流畅性和应用程序的性能。当一个Android应用启动时,系统会创建一个主进程(Main Process),在这个进程中运行着一个主线程,也称为UI线程。主线...

    Android多线程处理.pdf

    Android采用单线程模型来管理UI,所有与UI相关的操作都必须在主线程(也称为UI线程或main thread)中完成。 2. Android提供了线程间通信的机制,通过Handler可以将任务分发到其他线程去执行,然后回到主线程更新UI...

    Android环境下主UI线程与子线程通信机制研究.pdf

    在Android中,由于UI单线程模型的限制,只有主线程可以更新UI元素,所以当子线程执行完任务后,如果需要更新UI,它不能直接操作UI元素。它必须通过特定的通信机制来与主线程通信,告知主线程进行相应的UI更新。 ###...

    Android 多线程图片下载开源代码

    在Android开发中,多线程图片下载是一个常见的需求,尤其在大数据量或者高并发的情况下,单线程下载图片会严重影响用户体验,因为这可能导致UI线程阻塞,使得应用显得卡顿。这篇博客“Android 多线程图片下载开源...

    UI线程

    由于Android系统的单线程模型,所有对UI的操作都必须在UI线程中执行,以确保界面操作的同步性和一致性。 当我们谈论UI线程时,有几个关键知识点是必须要理解的: 1. **线程安全**:由于所有与UI相关的操作都在同一...

    Android Thread学习笔记

    #### Android单线程模型的核心原则 在深入探讨Android中的线程使用之前,我们首先需要理解其核心的单线程模型原则,这为后续的多线程操作提供了基础框架: 1. **不要阻塞UI线程**:UI线程(也称为主线程)负责处理...

    android多线程

    **线程通信**是多线程编程中重要的概念,通常涉及到**生产者消费者模型**。在Java中,可以使用`wait()`、`notify()`和`notifyAll()`等方法实现线程间的同步。 **死锁**是多线程环境中常见的问题,当两个或多个线程...

    android 线程间通信显示同步时间

    首先,Android系统是基于单线程模型的,主线程(也称为UI线程)负责处理用户交互和更新UI。由于Android对主线程有严格的限制,不允许在主线程中执行耗时操作,如网络请求或数据库操作,否则会导致应用无响应(ANR)...

    android SDK线程.rar

    Android系统基于Linux内核,因此其线程模型与传统的Linux线程模型相似,但又有针对移动设备的特定优化。以下是关于Android SDK线程的一些关键知识点: 1. **主线程(UI线程)**:每个Android应用都有一个主线程,也...

    Android高级编程.pdf

    4. **多线程与异步处理**:Android主线程(UI线程)不允许执行耗时操作,因此熟悉AsyncTask、Handler、Looper、ThreadPoolExecutor等多线程技术是必要的,它们能确保应用的响应性和流畅性。 5. **数据存储**:了解...

    android:AsyncTask实现异步处理任务.pdf

    在Android应用开发中,由于UI操作必须在主线程(UI线程)中执行,因此需要遵循单线程模型,避免阻塞主线程,确保应用的流畅性。当需要执行耗时操作,如网络请求、数据处理等,需要在子线程中进行。Android为此提供了...

    Android精彩编程200例-全彩版

    《Android精彩编程200例-全彩版》是一本专为Android开发者设计的实践教程,旨在通过200个精心挑选的实例,全面展示Android应用程序开发的各种技术和技巧。这本书覆盖了Android开发的基础到高级主题,是提升Android...

    android 线程详解 各种经典 完整代码

    本文将深入探讨Android线程的概念、类型以及如何有效地利用线程进行编程,包括各种经典用法,并提供完整的代码示例。 一、Android线程基础 在Android系统中,主线程也称为UI线程,负责处理用户界面的所有交互。由于...

    Android2 高级编程中文完整高清版

    书中会介绍如何使用AsyncTask、Handler、Thread和Service来实现多线程,以确保UI的流畅性。 4. **网络通信**:Android应用经常需要与服务器进行数据交换。书里会涵盖HTTP请求、WebSocket、RESTful API交互、JSON...

Global site tag (gtag.js) - Google Analytics