android 线程返回值AsyncTask 怎么返回值给UI线程

博客分类:
虽然使用线程能适用大部分异步的场景,但是代码看起来还是不够简练,在android平台,还有另外一种解决方案----AsyncTask。
首先直接上代码:
private class getRemoteDataTask extends AsyncTask&String, Integer, ArrayList&Hashtable&String, String&&& {
protected void onPostExecute(ArrayList&Hashtable&String, String&& dataList) {
this.cancel(false);
protected ArrayList&Hashtable&String, String&& doInBackground(String... params) {
ArrayList&Hashtable&String, String&& dataList = new ArrayList&Hashtable&String, String&&();
return dataL
下面来解释一下,doInBackground方法类似于在线程中的run方法,这个方法是另一个后台线程中执行,然后执行完会通过回调机制执行onPostExecute,神奇之处就在于,onPostExecute这个方法的执行权限又交回给activity的主进程中执行,也就是说onPostExecute这个方法里面可以操作UI。于是就能实现异步读取数据,并且操作UI,是不是比起自己写线程方便很多?
然后我们来剖析一下,这种方案的几个不太容易理解的地方。
一、AsyncTask&String, Integer, ArrayList&Hashtable&String, String&&& 注意这里几个泛型的定义和意义,第一个代表该方法被调用时传递的参数类型,注意是参数的类型,而不是参数的个数,也就是说如果定义为String,那么,该方法被调用时所传递的参数只能是String类型;然后第二个Integer,资料上说是线程后台执行的百分比,不过我没彻底弄清楚这个的含义,欢迎大家指教,然后泛型里的第三个ArrayList&Hashtable&String, String&,这个和该类的两个方法都有密切联系,该泛型是指后台执行返回的结果的类型。
二、doInBackground这个方法是在后台执行的,然后它的返回结果将提供给onPostExecute,所以,doInBackground的返回值必须和AsyncTask类的第三个泛型定义一致,然后onPostExecute的参数类型必须和doInBackground的返回类型一致。
三、前边我们都一直在解释AsyncTask这个类,但是怎么调用呢?其实很简单
new getRemoteDataTask().execute(String... params);
注意,execute方法里传递的参数的类型必须和AsyncTask第一个泛型的类型一致,然后这个方法传递的参数将在
doInBackground(String... params)
这里面起作用。
第四,AsyncTask还有很多方法,我们仅仅分析了其中两个,它被继承后,必须要重写的一个方法是doInBackground,因为doInBackground的返回值将在onPostExecute中被用来更新UI,所以我们姑且认为这两个方法是最重要。
第五、AsyncTask的实例必须在UI线程中被调用、
execute(String...params)必须在UI线程中调用、
不要手动调用onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)等方法、
AsyncTask只执行一次。
changkunyang
浏览: 21196 次
来自: 北京
/?s=wamp我也 ...
jwangei 写道挺不错的软件,但使用后感觉有几个地方可以再 ...
必须吻一个
挺不错的软件,但使用后感觉有几个地方可以再改进一下下~~
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'& & & & Android的UI是单线程的,所以对于运行时间长的程序必须异步运行。实现异步任务的一个很方便的工具是AsyncTask。它完全隐藏了运行任务的线程的很多详细信息。
& & & & 以一个例子来说明AsyncTask:
& & & & 一个非常简单的应用中,有需要初始化游戏引擎,当加载内容时,显示一些插播广告图形。假设,我们希望在用户等待游戏启动时,显示一个动画背景(类似于Windows Phone 8)上的加载程序的等待界面。
当用户在点击启动按钮以后,会执行多个初始化。
& & & &&问题:如果在UI线程中执行远程服务调用初始化时,整个UI界面无法执行任何其他操作。
& & & &&解决:使用AsyncTask解决这个问题,代码如下:
private final class AsyncInitGame extends AsyncTask&String, void, String&
private final V
private final G
private final TextV
private final D
public AsyncInitGame(View root, Drawable bg, Game game, TextView msg)
this.root =
this.game =
this.message =
//run on the UI thread
//1. 当UI线程调用任务的execute方法时,会首先调用该方法,这里要做的操作时该任务能够对其本身和环境执行初始化,在这个例子中是安装等待启动的背景动画
@Override protected void onPreExecute()
if(0 &= mInFlight++){
root.setBackgroundResouce(R.anim.dots);
((AnimationDrawable)root.getBackground()).start();
//runs on the UI thread
//3. 当doInBackground方法完成时,就删除背景线程,再在UI线程中调用onPostExecute方法。
@Override protected void onPostExecute(String msg){
if(0 &= --mInFlight){
((AndimationDrawable)root.getBackground()).stop();
root.setBackgroundDrawable(bg);
message.setText(msg);
//runs on a background thread
//2. 在onPreExecute方法完成后AsyncTask创建新的背景线程,并发执行doInBackground方法。
@Override protected String doInBackground(String... args){
return (1 != args.length) || (null == args[0])) ? null : game.initialize(args[0]);
}private final class AsyncInitGame extends AsyncTask&String, void, String&
private final V
private final G
private final TextV
private final D
public AsyncInitGame(View root, Drawable bg, Game game, TextView msg)
this.root =
this.game =
this.message =
//run on the UI thread
//1. 当UI线程调用任务的execute方法时,会首先调用该方法,这里要做的操作时该任务能够对其本身和环境执行初始化,在这个例子中是安装等待启动的背景动画
@Override protected void onPreExecute()
if(0 &= mInFlight++){
root.setBackgroundResouce(R.anim.dots);
((AnimationDrawable)root.getBackground()).start();
//runs on the UI thread
//3. 当doInBackground方法完成时,就删除背景线程,再在UI线程中调用onPostExecute方法。
@Override protected void onPostExecute(String msg){
if(0 &= --mInFlight){
((AndimationDrawable)root.getBackground()).stop();
root.setBackgroundDrawable(bg);
message.setText(msg);
//runs on a background thread
//2. 在onPreExecute方法完成后AsyncTask创建新的背景线程,并发执行doInBackground方法。
@Override protected String doInBackground(String... args){
return (1 != args.length) || (null == args[0])) ? null : game.initialize(args[0]);
}& & & 假设AsyncTask的实现是正确的,我们单击按钮“启动”按钮只需要创建一个实例并调用它,如下所示:
((Button)findViewById(R.id.start)).setOnClickListener(
new View.OnClickListener(){
@Override public void onClick(View v){
new AsyncInitGame(root, bg, game, msg).execute(&basic&);
);//注:该文中的代码并不全面,只是为了阐述AsyncTask
& & & & doInBackground是类Game的代理(proxy)。
& & & & 一般来说AsyncTask需要一组参数并返回一个结果。因为需要在线程之间传递该参数并返回结果,所以就需要一些握手机制用来确保线程安全性。
& & & & 1. 通过参数传递调用execute方法来调用AsyncTask。
& & & & 2. 当线程在后台执行时,这些参数最终通过AsyncTask机制传递给doInBackground方法的,doInBackground返回结果。
& & & & 3. AsyncTask把该结果作为参数传递给doPostExecute方法,doPostExecute方法和最初的execute方法在同一个线程中运行。
AsyncTask不但会确保数据流安全也会确保类型安全。该抽象基类(AsyncTask)使用Java反省,使得实现能够制定任务参数和结果的类型,下面以一个例子来说明:
public class AsyncDBReq extends AsyncTask&PreparedStatement, Void, ResultSet&
@Override protected ResultSet doInBackground(PreparedStatement...q){
//implementation.....
@Override protected onPostExecute(ResultSet result){
//implementation
public class AsyncHttpReq extends AsyncTask&HttpRequest, Void, HttpResponse&
@Override protected HeepResponse doInBackground(HttpRequest.....req){
//implementaion.....
@Override protected void onPostExecute(HttpResponse result){
//implementaion
}第一个类,AsyncDBReq实例的execute方法参数是一个或者多个PreparedStatement变量。
该类中AsyncDBReq实例的doInBackground方法会把这些PreparedStatement参数作为其参数,返回结果是ResultSet。onPostExecute方法会把该ResultSet作为其参数使用。
第二个类也是如此。
AsyncTask的一个实例只能运行一次!!!,第二次执行execute方法会抛出IllegalStateException一场。所以每个任务调用都需要一个新的实例。
虽然AsyncTask简化并行处理,但它有很强的限制约束条件且无法自动验证这些条件。注意不要违反这些约束条件是非常有必须要的,
对于这些约束条件,最明显的是doInBackground方法,因为它是在另一个线程上执行的,只能引用作用域内的变量!!!这样才是线程安全的
OK难点来了,如果实际使用中可能还是会发生下面两个这样的错误,所以,可能需要大量的练习来熟悉和理解了。
//易犯错误一、
//....some clas
public void initButton1(Button button){
mCOunt = 0;
button.setonClickListener(
new View.OnClickListener(){
@SuppressWarnings(&unchecked&)
@Override public void onCLick(View v){
new AsyncTask&Void, Void, Void&(){
@Override protected Void doInBackground(Void...args){
mCount++; //!!! not thread safe!!
}.execute();
}& & & & 这里在编译时不会产生编译错误,也没有运行警告,可能甚至在bug被触发时也不会立即失败,但该代码绝对是错误的。有两个不同的线程访问变量mCount,而这两个线程之间却没有执行同步。
& & & & 鉴于这种情况,在本文的第一段代码中的mInFlight的访问执行同步时,你可能会感到奇怪。事实上它是正确的,AsyncTask约束会确保onPreExecute方法和onPostExecute方法在同一个线程中执行,即execute方法被调用的线程。和mCount不同,mInFlight只有一个线程访问,不需要执行同步。
案例二:可能会导致最致命的的并发问题是在用完某个参数变量后,没有释放其引用。如下代码:
//易犯错误二、
public void initButton(Button button, final Map&String, String& vals){
button.setOnClickListener(
new View.OnClickListener(){
@Override public void onClick(View v){
new AsyncTask&Map&String, String&, Void, Void&(){
@Override protected Void doInBackground(Map&String,String&...params){
//implementation, uses the params Map
}.execute(vals);
vals.clear();//this is not thread safe!!!!
}错误原因:initButton的参数valse被并发引用,却没有执行同步!!!当调用AsyncTask时,它作为参数传递给execute方法。syncTask框架可以确保当调用doInBackground方法时,该引用会正确地传递给后台线程。但是对于在initButton方法中所保存并使用的vals引用,却没有办法处理。调用vals.caear修改了在另一个线程上正在使用的状态,但没有执行同步。因此,不是线程安全的。
最佳解决办法:确保AsyncTask的参数是不可变的。如果这些参数不可变,类似String、Integer或只包含final变量的POJO对象,那么它们都是线程安全的,不需要更多的操作。要保证传递给AsyncTask的可变对象是程序安全的唯一办法是确保只有AsyncTask持有引用。
在案例二中参数vals是传递给initButton方法,我们完全无法保证它不存在悬空的引用(dangline references)。即使删掉代码vals.clear,也无法保证该代码正确,因为调用initButton方法的实例可能会保存其参数map的引用,它最终传递的是参数vals。使该代码正确的唯一方式是完全复制(深拷贝)map及其包含的对象!!!
最后还有AsyncTask还有一个方法没有使用到:onProgressUpdate。作用:使长时间运行的任务可以周期性安全地把状态返回给UI线程。
用一个例子来说明并结束本文吧,哎,打字不容易啊,妹子的电脑上没有eclipse,只能用editplus,木有智能提示伤不起的。
该例子说明了如何使用onProgressUpdate方法实现进度条,向用户显示游戏初始化进程还需要多久的时间。
public class AsyncTaskDemoWithProgress extends Activity{
private final class AsyncInit extends AsyncTask&String, Integer, String& implements Game.InitProgressLIstener
private final V
private final G
private final TextV
private final D
public AsyncInit(View root, Drawable bg, Game game, TextView msg){
this.root =
this.game =
this.message =
//run on the UI thread
//1. 当UI线程调用任务的execute方法时,会首先调用该方法
@Override protected void onPreExecute()
if(0 &= mInFlight++){
root.setBackgroundResouce(R.anim.dots);
((AnimationDrawable)root.getBackground()).start();
//runs on the UI thread
//3. 当doInBackground方法完成时,就删除背景线程,再在UI线程中调用onPostExecute方法。
@Override protected void onPostExecute(String msg){
if(0 &= --mInFlight){
((AndimationDrawable)root.getBackground()).stop();
root.setBackgroundDrawable(bg);
message.setText(msg);
//runs on its own thread
//2. 在onPreExecute方法完成后AsyncTask创建新的背景线程,并发执行doInBackground方法。
@Override protected String doInBackground(String... args){
return (1 != args.length) || (null == args[0])) ? null : game.initialize(args[0]);
//runs on its UI thread
@Override protected void onProgressUpdate(Integer... vals){
updateProgressBar(vals[0].intValue());
//runs on the UI thread
@Override public void onInitProgress(int pctComlete){
//为了正确地给UI线程发布进程状态,onInitProgress调用的是AsyncTask的publicProgress。
//AsyncTask处理UI线程的publicProgress调度细节,从而onProgressUpdate可以安全地使用View方法。
publicProgress(Integer.valueOf(pctComplete));
int mInFlight,mC
/** @see android.app.Activity#onCreate(android.os.Bundle) */
@Override public void onCreate(Bundle state){
super.onCreate(state);
setContentView(R.layout.asyncdemoprogress);
final View root = findViewById(R.id.root);
final Drawable bg = root.getBackground();
final TextView msg = ((TextView)findViewById(R.id.msg));
final Game game = Game.newGame();
((Button)findViewById(R.id.start)).setOnClickListener(
new View.OnClickListener(){
@Override public void onCLick(View v){
mComplete=0;
new AsyncInit(root, bg, game, msg).execute(&basic&);
void updateProgressBar(int progress){
if(mComplete & p){
mComplete =
(ProgressBar)findViewById(R.id.progress)).setprogress(p);
}.......嗯,其实还没结束,来个总结:
· Android UI线程是单线程的。为了熟练使用Android UI,开发人员必须对任务队列概念很熟悉。
· 为了保证UI的及时响应,需要运行的任务的执行时间超过几毫秒,或者需要好几百条指令,都不应该在UI线程中执行。
· 并发编程很棘手,容易犯错,并难以找出错误。
· AsyncTask是运行简单、异步任务的很便捷的工具。要记住的是doInBackground运行在另一个线程上。它不能写任何其他线程可见的状态,也不能读任何其他线程可写的状态,这也包括其参数!
· 不可改变的对象时在并线程之间传递信息的重要工具。
Mr.傅:学习笔记
欢迎转载,转载注明出处,谢谢
《Android程序设计》
引用说明:Programming Android by Zigurd Mednieks, Laird Dornin, G.Blake Meike, and Masumi Nakamura. Copyright 2011 O'Reilly Media, Inc., 978-1-449-38969-7
本文已收录于以下专栏:
相关文章推荐
view plaincopy to clipboardprint?
package net.blogjava.mobile.
import org.ksoap2...
view plaincopy to clipboardprint?   view plaincopy to clipboardprint?   &...
作为一个 Android 的新手,他最怕是什么?没错了,就是多线程编程,这坑爹坑出特色的玩意。偏偏 Android 网络编程又不得不使用多线程,所以让很多新手头痛,当然啦大牛转 Android 的可以...
        AsyncTask和ContentProvider相结合的功能会很强大,可以使用各种常见的应用架构。几乎在所有的MVC模式中,视图(View)对模型(Model)的轮询,都可...
一、AsyncTask简介
在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的,并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则: 
如果有操作阻塞UI线程软件可能出现界面无响应错误,所以耗时操作不要放在UI线程中实现。
常用的解决方式是把这类网络操作,加载大文件等等好似操作通过AsyncTask在后台线程中处理。
如何使用As...
从AsyncTask源码的角度,代领读者一步步的分析执行过程,详细的分析了,为什么AsyncTask实例的创建和execute方法的调用需要在UI线程中进行?
进而更好的使用AsyncTask,轻量级...
3个范型参数:
    Params:启动任务执行的输入参数
    Progress:后台任务执行的百分比
    Result,后台计算的结果类型
在一个异步任务里,不是所有的类型总被用。...
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Android中UI线程与后台线程交互设计的5种方法_西西软件资讯
西西软件下载最安全的下载网站、值得信赖的软件下载站!
→ Android中UI线程与后台线程交互设计的5种方法
1.0.6 官方最新版
类型:图像浏览大小:13.0M语言:英文 评分:4.2
我想关于这个话题已经有很多前辈讨论过了。今天算是一次学习总结吧。在android的设计思想中,为了确保用户顺滑的操作体验。一些耗时的任务不能够在UI线程中运行,像访问网络就属于这类任务。因此我们必须要重新开启一个后台线程运行这些任务。然而,往往这些任务最终又会直接或者间接的需要访问和控制UI控件。例如访问网络获取数据,然后需要将这些数据处理显示出来。就出现了上面所说的情况。原本这是在正常不过的现象了,但是android规定除了UI线程外,其他线程都不可以对那些UI控件访问和操控。为了解决这个问题,于是就引出了我们今天的话题。Android中后台线程如何与UI线程交互。据我所知android提供了以下几种方法,用于实现后台线程与UI线程的交互。1、handler2、Activity.runOnUIThread(Runnable)3、View.Post(Runnable)4、View.PostDelayed(Runnabe,long)5、AsyncTask方法一:handlerhandler是android中专门用来在线程之间传递信息类的工具。要讲明handler的用法非常简单,但是我在这里会少许深入的讲一下handler的运行机制。为了能够让handler在线程间传递消息,我们还需要用到几个类。他们是looper,messageQueue,message。这里说的looper可不是前段时间的好莱坞大片环形使者,他的主要功能是为特定单一线程运行一个消息环。一个线程对应一个looper。同样一个looper对应一个线程。这就是所谓的特定单一。一般情况下,在一个线程创建时他本身是不会生产他特定单一的looper的(主线程是个特例)。因此我们需要手动的把一个looper与线程相关联。其方法只需在需要关联的looper的线程中调用Looper.prepare。之后我们再调用Looper.loop启动looper。说了这么多looper的事情,到底这个looper有什么用哪。其实之前我们已经说到了,他是为线程运行一个消息环。具体的说,在我们将特定单一looper与线程关联的时候,looper会同时生产一个messageQueue。他是一个消息队列,looper会不停的从messageQuee中取出消息,也就是message。然后线程就会根据message中的内容进行相应的操作。那么messageQueue中的message是从哪里来的哪?那就要提到handler了。在我们创建handler的时候,我们需要与特定的looper绑定。这样通过handler我们就可以把message传递给特定的looper,继而传递给特定的线程。在这里,looper和handler并非一一对应的。一个looper可以对应多个handler,而一个handler只能对应一个looper(突然想起了一夫多妻制,呵呵)。这里补充一下,handler和looper的绑定,是在构建handler的时候实现的,具体查询handler的构造函数。在我们创建handler并与相应looper绑定之后,我们就可以传递message了。我们只需要调用handler的sendMessage函数,将message作为参数传递给相应线程。之后这个message就会被塞进looper的messageQueue。然后再被looper取出来交给线程处理。这里要补充说一下message,虽然我们可以自己创建一个新的message,但是更加推荐的是调用handler的obtainMessage方法来获取一个message。这个方法的作用是从系统的消息池中取出一个message,这样就可以避免message创建和销毁带来的资源浪费了(这也就是算得上重复利用的绿色之举了吧)。突然发现有一点很重要的地方没有讲到,那就是线程从looper收到message之后他是如何做出响应的嘞。其实原来线程所需要做出何种响应需要我们在我们自定义的handler类中的handleMessage重构方法中编写。之后才是之前说的创建handler并绑定looper。好吧说的可能哟点乱,总结一下利用handler传递信息的方法。假设A线程要传递信息给B线程,我们需要做的就是1、在B线程中调用Looper.prepare和Looper.loop。(主线程不需要)2、 编写Handler类,重写其中的handleMessage方法。3、创建Handler类的实例,并绑定looper4、调用handler的sentMessage方法发送消息。到这里,我们想handler的运行机制我应该是阐述的差不多了吧,最后再附上一段代码,供大家参考。&1&public&class&MyHandlerActivity&extends&Activity&{
&2&&&&&&TextView&textV
&3&&&&&&MyHandler&myH
&5&&&&&&protected&void&onCreate(Bundle&savedInstanceState)&{
&6&&&&&&&&&&super.onCreate(savedInstanceState);
&7&&&&&&&&&&setContentView(R.layout.handler);
&9&&&&&&&&&&//实现创建handler并与looper绑定。这里没有涉及looper与
&&&&&&&&&&&&//线程的关联是因为主线程在创建之初就已有looper
10&&&&&&&&&&myHandler=MyHandler(MyHandlerActivitythis.getMainLooper());
11&&&&&&&&&&textView&=&(textView)&findViewById(R.id.textView);
12&&&&&&&&&
13&&&&&&&&&&MyThread&m&=&new&MyThread();
14&&&&&&&&&&new&Thread(m).start();
18&&&&&&class&MyHandler&extends&Handler&{
19&&&&&&&&&&public&MyHandler()&{
20&&&&&&&&&&}
22&&&&&&&&&&public&MyHandler(Looper&L)&{
23&&&&&&&&&&&&&&super(L);
24&&&&&&&&&&}
26&&&&&&&&&&//&必须重写这个方法,用于处理message
27&&&&&&&&&&@Override
28&&&&&&&&&&public&void&handleMessage(Message&msg)&{
29&&&&&&&&&&&&&&//&这里用于更新UI
30&&&&&&&&&&&&&&Bundle&b&=&msg.getData();
31&&&&&&&&&&&&&&String&color&=&b.getString(&color&);
32&&&&&&&&&&&&&&MyHandlerActivity.this.textView.setText(color);
33&&&&&&&&&&}
36&&&&&&class&MyThread&implements&Runnable&{
37&&&&&&&&&&public&void&run()&{
38&&&&&&&&&&&&&&//从消息池中取出一个message
39&&&&&&&&&&&&&&Message&msg&=&myHandler.obtainMessage();
40&&&&&&&&&&&&&&//Bundle是message中的数据
41&&&&&&&&&&&&&&Bundle&b&=&new&Bundle();
42&&&&&&&&&&&&&&b.putString(&color&,&&我的&);
43&&&&&&&&&&&&&&msg.setData(b);
44&&&&&&&&&&&&&&//传递数据
45&&&&&&&&&&&&&&myHandler.sendMessage(msg);&//&向Handler发送消息,更新UI
46&&&&&&&&&&}
47&&&&&&}方法二:Activity.runOnUIThread(Runnable)&这个方法相当简单,我们要做的只是以下几步1、编写后台线程,这回你可以直接调用UI控件2、创建后台线程的实例3、调用UI线程对应的Activity的runOnUIThread方法,将后台线程实例作为参数传入其中。注意:无需调用后台线程的start方法方法三:View.Post(Runnable)&该方法和方法二基本相同,只是在后台线程中能操控的UI控件被限制了,只能是指定的UI控件View。方法如下1、编写后台线程,这回你可以直接调用UI控件,但是该UI控件只能是View2、创建后台线程的实例3、调用UI控件View的post方法,将后台线程实例作为参数传入其中。方法四:View.PostDelayed(Runnabe,long)该方法是方法三的补充,long参数用于制定多少时间后运行后台进程&方法五:AsyncTaskAsyncTask是一个专门用来处理后台进程与UI线程的工具。通过AsyncTask,我们可以非常方便的进行后台线程和UI线程之间的交流。那么AsyncTask是如何工作的哪。AsyncTask拥有3个重要参数1、Params&2、Progress3、ResultParams是后台线程所需的参数。在后台线程进行作业的时候,他需要外界为其提供必要的参数,就好像是一个用于下载图片的后台进程,他需要的参数就是图片的下载地址。Progress是后台线程处理作业的进度。依旧上面的例子说,就是下载图片这个任务完成了多少,是20%还是60%。这个数字是由Progress提供。Result是后台线程运行的结果,也就是需要提交给UI线程的信息。按照上面的例子来说,就是下载完成的图片。AsyncTask还拥有4个重要的回调方法。1、onPreExecute2、doInBackground3、onProgressUpdate4、onPostExecuteonPreExecute运行在UI线程,主要目的是为后台线程的运行做准备。当他运行完成后,他会调用doInBackground方法。doInBackground运行在后台线程,他用来负责运行任务。他拥有参数Params,并且返回Result。在后台线程的运行当中,为了能够更新作业完成的进度,需要在doInbackground方法中调用PublishProgress方法。该方法拥有参数Progress。通过该方法可以更新Progress的数据。然后当调用完PublishProgress方法,他会调用onProgressUpdate方法用于更新进度。onProgressUpdate运行在UI线程,主要目的是用来更新UI线程中显示进度的UI控件。他拥有Progress参数。在doInBackground中调用PublishProgress之后,就会自动调onProgressUpdate方法onPostExecute运行在UI线程,当doInBackground方法运行完后,他会调用onPostExecute方法,并传入Result。在onPostExecute方法中,就可以将Result更新到UI控件上。明白了上面的3个参数和4个方法,你要做的就是1、编写一个继承AsyncTask的类,并声明3个参数的类型,编写4个回调方法的内容。2、然后在UI线程中创建该类(必须在UI线程中创建)。3、最后调用AsyncTask的execute方法,传入Parmas参数(同样必须在UI线程中调用)。这样就大功告成了。另外值得注意的2点就是,千万不要直接调用那四个回调方法。还有就是一个AsyncTask实例只能执行一次,否则就出错哦。以上是AsyncTask的基本用法,更加详细的内容请参考android官方文档。最后附上一段代码,供大家参考。&1&private&class&DownloadFilesTask&extends&AsyncTask&URL,&Integer,&Long&&
&2&//在这里声明了Params、Progress、Result参数的类型
&4&&&&&//因为这里不需要使用onPreExecute回调方法,所以就没有加入该方法
&6&&&&&//后台线程的目的是更具URL下载数据
&7&&&&&&protected&Long&doInBackground(URL...&urls)&{
&8&&&&&&&&&&int&count&=&urls.//urls是数组,不止一个下载链接
&9&&&&&&&&&&long&totalSize&=&0;//下载的数据
10&&&&&&&&&&for&(int&i&=&0;&i&&&&i++)&{
11&&&&&&&&&&&&&&//Download是用于下载的一个类,和AsyncTask无关,大家可以忽略他的实现
12&&&&&&&&&&&&&&totalSize&+=&Downloader.downloadFile(urls[i]);
13&&&&&&&&&&&&&&publishProgress((int)&((i&/&(float)&count)&*&100));//更新下载的进度
14&&&&&&&&&&&&&&//&Escape&early&if&cancel()&is&called
15&&&&&&&&&&&&&&if&(isCancelled())&
16&&&&&&&&&&}
17&&&&&&&&&&return&totalS
20&&&&&&//更新下载进度
21&&&&&&protected&void&onProgressUpdate(Integer...&progress)&{
22&&&&&&&&&&setProgressPercent(progress[0]);
25&&&&&&//将下载的数据更新到UI线程
26&&&&&&protected&void&onPostExecute(Long&result)&{
27&&&&&&&&&&showDialog(&Downloaded&&&+&result&+&&&bytes&);
30&有了上面的这个类,接下你要做的就是在UI线程中创建实例,并调用execute方法,传入URl参数就可以了。这上面的5种方法各有优点。但是究其根本,其实后面四种方法都是基于handler方法的包装。在一般的情形下后面四种似乎更值得推荐。但是当情形比较复杂,还是推荐使用handler。最后补充一下,这是我的第一篇博客。存在很多问题请大家多多指教。尤其是文中涉及到内容,有严重的技术问题,大家一定要给我指明啊。拜托各位了。
04-2504-2504-2504-2104-1504-1504-1304-1304-1204-08
阅读本文后您有什么感想? 已有23人给出评价!
名称大小下载}

我要回帖

更多关于 线程返回值 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信