AsyncTask就是异步加载网络数据。跟那个new一个子线程加载数据一样。用了这个AsyncTask就不需要再new子线程了,里面有一个线程池,最多开五个线程。。
在Android中提供了一个异步任务的类AsyncTask,简单来说,这个类中的任务是运行在后台线程中的,并可以将结果放到UI线程中进行处理,它定义了三种泛型,分别是Params、Progress和Result,分别表示请求的参数、任务的进度和获得的结果数据。
我之前总结了使用异步任务的原因有三点:
1)是因为AsyncTask使用了线程池技术,而且其中的方法很容易实现调用
2)是因为AsyncTask可以调用相关的方法,在开启子线程前和后,进行界面的更新
3)是因为一旦任务多了,不用每次都new新的线程,可以直接使用
如果我们查看官方文档,异步任务中的方法的执行顺序是这样的:
onPreExecute()【执行前开启】--- > doInBackground() --- > onProgressUpdate() --- > onPostExecute()
具体的来说,当一个异步任务开启后:
首先会调用onPreExecute()方法:
这个方法在异步执行时立即被UI线程调用,这一步通常用来设置任务,作为任务加载的准备工作。通常会在这个方法中弹出一个提示框,提示用户加载的进度。
第二个方法doInBackground():
这个方法是执行在子线程中的。在onPreExecute()执行完后,会立即开启这个方法,在方法中可以执行耗时的操作。需要将请求的参数传递进来,发送给服务器,并将获取到的数据返回,数据会传给最后一步中;这些值都将被放到主线程中,也可以不断的传递给下一步的onProgressUpdate()中进行更新。可以通过不断调用publishProgress(),将数据(或进度)不断传递给onProgressUpdate()方法,进行不断更新界面。
3)、onProgressUpdate():
这个方法是执行在主线程中的。publishProgress()在被调用后,才开启的这个方法,它在何时被开启是不确定的,这个方法用来在后台操作仍在执行的时候在用户界面显示不同形式的进度。比如它可以推动进度条进度或者在文本里显示log信息。
4)、onPostExecute():
这个方法是执行在主线程中的。当后台的子线程执行完毕后才调用此方法。doInBackground()返回的结果会作为参数被传递过来。可以在这个方法中进行更新界面的操作。
最后创建AsyncTask自定义的类,调用execute()方法开启异步任务。
结合项目:
我们在使用异步任务的时候,根据这些原理和步骤就可以了,我们在做项目时会经常使用到异步任务,比如说我在做彩票的这个项目中,有一个部分,是购彩大厅中的销售期号和截止时间,我这里使用异步获取这个彩种的当前的销售信息.
我在实现一个功能的时候总会先想到三个问题,我们要实现什么?我们要怎么实现?我们为什么这样实现?
首先我们要实现什么呢?就是从服务器上获取到当前的销售信息.
那么我们要怎么实现呢?首先我们得在购彩大厅这个类中增加一个获取当前销售信息的方法,这个方法会到服务器中去获取数据.然后我先想到的是在这个方法中开启一个线程,在这个线程中实现访问网络的操作,由于我们做了访问网络的操作,所以在开启这个线程的时候还要判断一下网络。添加判断网络的代码之后,我又发现,每次访问网络的时候,我们都要实现这几行代码。解决这个问题,我是在getCurrentIssueInfo中,只保留了new MyThread().start(),而把判断网络这一步放到MyThread中的start()中去.这时候,当在getCurrentIssueInfo中start的时候,会调用新线程的start()方法,这里的super.start()就是方法中的start,如果联络连接好则执行这个start,然后调用run方法,执行网络的操作;否则,就弹出没有网络的提示信息。
这是实现这个功能的一种方式,但是我有考虑到使用系统提供的AsyncTask比Thread的效率更高,因此我又改用了AsyncTask的方式来实现从服务器上获取当前的销售信息.
创建异步任务类后,先覆写doInBackground方法,这个方法相当于Thread中的run方法,开启异步任务就要调用execute方法,它和Thread的start方法类似.
在异步任务处理中加入execute方法,但是我在查看AsyncTask源代码的时候发现这个方法是final修饰的,因此我们没办法override这个方法,我的处理方式是把这个方法复制过来,既然没办法override,就修改这个方法来使用.我们的目的是判断网络,所以在这个方法中加上网络判断语句就可以了.
然后在这个任务中增加在UI线程的操作:得复写onPreExecute和onPostExecute两个方法,这两个方法是在UI线程中执行的,就避免了使用Handler(因为使用Handler发消息处理,代码很臃肿)。
这样,异步任务处理的壳子就写出来了,下一步要做到就是在里面写任务。
我们创建一个处理公共信息的业务操作接口,在里面定义一个根据期号获取当前销售期的方法。然后把这个接口的实现类给定义出来,获取到服务器中的信息之后,在onPostExecute方法中判断返回的信息是否为空,如果为空就提示用户服务器忙,否则就更新界面,把获取的信息在界面中显示出来。
这样处理我还遇到了个问题,我这个获取当前销售信息的方法是放在购彩大厅类的构造函数中调用的,这个方法就只能被调用一次,而我们要求它时刻变化,这个时候我们就需要做出改变。我想到了两种处理的方案,一种是使用倒计时的方法——每秒刷新一次,第二种是每次进入到购彩大厅的时候,都到服务器端去获取数据。使用第二种比较方便,这时候我想要借鉴activity生命周期的方法,(进来时调用onStart、onResume、出去时调用onPause)。
我在这个界面中增加两个方法onResume和onPause,
对于onResume是在进入到界面的时候,界面内容的修改,处理耗费资源操作,在onPause方法中回收资源
在界面管理的类中,加入界面后,就调用onResume方法进行界面内容的修改。同时,在移除view的之前,要进行耗资源内容的移除。要做的是先判断是不是第一个view,如果不是,则可能会有耗资源的内容,就在onPause中进行耗资源的操作。
这时候就可以把获取销售信息的方法从构造函数中转移到onResume中。这样就完成了获取销售信息的功能。