Android异步处理特性之AsyncTask

Android异步处理特性之AsyncTask  

2011-07-19 15:43:41|  分类: android|字号 订阅

虽然使用线程能适用大部分异步的场景,但是代码看起来还是不够简练,在android平台,还有另外一种解决方案----AsyncTask。

首先直接上代码:

private class getRemoteDataTask extends AsyncTask<String, Integer, ArrayList<Hashtable<String, String>>> {
    protected void onPostExecute(ArrayList<Hashtable<String, String>> dataList) {
            
        this.cancel(false);
    }

    @Override
    protected ArrayList<Hashtable<String, String>> doInBackground(String... params) {
        ArrayList<Hashtable<String, String>> dataList = new ArrayList<Hashtable<String, String>>();
            
        return dataList;
    }
}

下面来解释一下,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只执行一次。

一个小例子

有一个ListView的小例子,一开始List中没有内容,通过一个AsyncTask逐步在List中加入条目。

1)XML文件:简单的ListView布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... ...>

  <ListView android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" /> 
</LinearLayout>

2)例子代码

public class Chapter15Test3 extends ListActivity{
    //这里是List Item内容,在这个例子中,将在后台任务中逐个加入
    private static String[] items={"lorem", "ipsum", "dolor","sit", "amet", "consectetuer","adipiscing", "elit", "morbi","vel", "ligula", "vitae","arcu", "aliquet", "mollis","etiam", "vel", "erat","placerat", "ante","porttitor", "sodales","pellentesque", "augue","purus"};

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chapter_8_test2);

        //在这个例子中,我们一开始并没有导入items的数据,注意item数据为新建的ArrayList,即无内容
        setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,new ArrayList<String>()));
        //步骤5:创建后台任务的对象,并通过execute()启动后台线程,调用doInBackground()的代码,execute中的参数类型为参数1,这里我们不需要传递任何内容
        new AddStringTask().execute();
    }
  
    //步骤1:创建AsyncTask子类,参数1是Void的范式类型,参数2是String的范式类型,参数3是Void其中参数1:向后台任务的执行方法传递参数的类型;参数2:在后台任务执行过程中,要求主UI线程处理中间状态,通常是一些UI处理中传递的参数类型;参数3:后台任务执行完返回时的参数类型
    private class AddStringTask extends AsyncTask<Void, String,Void>{
       //我们加入一个检测信息的方法,打印当前在哪个线程执行的信息
        private void printInfo(String info){
            Log.d("WEI", info + " : Tread is " + Thread.currentThread().getName());
        }

  
        //步骤2:实现抽象方法doInBackground(),代码将在后台线程中执行,由execute()触发,由于这个例子并不需要传递参数,使用Void...,具体书写方式为范式书写
        protected Void/*参数3*/ doInBackground(Void...params/*参数1*/) {
            for(String item : items){
                //步骤3:通知UI主线程执行相关的操作(在onProgressUpdate中定义)
                publishProgress(item/*参数2*/);
                printInfo("doInBackgound " + item);
                SystemClock.sleep(200);
            }
            return null;

        }

        //步骤3:定义收到pushProgress()触发后,在UI主线程执行的内容,在本例,将item加入list中。方法中的参数为范式方式,实质为数组,由于我们只传递了item一个String,要获取,为values[0]
        protected void onProgressUpdate(String... values/*参数2*/) {
            printInfo("onProgressUpdate  get param " + values[0]);
            ((ArrayAdapter<String>)getListAdapter()).add(values[0]);

        }
      
        //步骤4:定义后台进程执行完后的处理,本例,采用Toast

        protected void onPostExecute(Void result/*参数3*/) {
            printInfo("onPostExecute");
            Toast.makeText(Chapter15Test3.this, "Done!", Toast.LENGTH_SHORT).show();
        }         
    }   
}

我们根据printInfo跟踪各部分代码在哪里执行:doInBackground在后台线程执行,onProgressUpdate()和onPostExecute()在UI主线程执行。main就是UI主线程,而AsyncTask #1为后台线程,名字不一样。

 

需要注意

虽然Android提供后台任务方便我们处理,是否使用后台任务,以及如何使用后台任务,我们要注意下面的内容:

可能在执行后台线程处理中,用户和UI之间存在交互,这些交换可能会对后台任务有重要的影响,因此需要通知后台线程,Android提供很多的类来处理,封装在java.util.concurrent包中,帮助与后台线程的安全通信。可能在执行后台线程处理中,我们的Activity就已经被kill了,例如有一个电话过来,然后发给短信,查看号码本。这时系统可能将你的activity踢走,接着后面我们会学习Activity的生命周期,了解相关的情况。在编程中,出现这种情况,只要有可能,需要将后台进程关闭。可能在执行后台线程处理中,出现某种错误,例如后台在下载URL,而网络连接中断了。这种情况下关闭后台进程可能是最好的处理。此外后台任务是消耗CPU和内存,是有代价的,我们应该确保它处理的时候更为有效。

 

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值