第二十三个项目——使用AsyncTask进行网络异步请求
实验目的
掌握AsyncTask进行异步任务处理的基本流程;
能使用AsyncTask、Okhttp网络库实现网络数据异步请求处理;
实验要求
自定义AsyncTask子类NewsListAsyncTask,重载doInBackground()及onPostExecute()方法;
实验内容
在第十四个项目中,使用okhttp网络请求库调用天行数据API新闻接口,并在ListView中显示获取的新闻列表数据。在MainActivity中通过定义okhttp3.Callback回调接口,并使用Call.enqueue(okhttp3.Callback)异步形式进行网络请求。
但由于Android不允许在主线程中进行网络请求操作,因此实际的网络请求必须在子线程中完成。在子线程中获取天行数据API新闻接口返回数据后,再通过runOnUiThread()方法将获取的数据更新。这些步骤看起来十分复杂繁琐,且大量代码堆叠在MainActivity活动中,如果一个活动需要请求多个网络接口的数据,那么会造成该活动的代码十分臃肿也不利于维护。
为了解决上述问题,Android框架提供了AsyncTask异步任务类,AsyncTask封装了子线程创建, 子线程与UI主线程的通信等操作,对开发人员暴露以下方法,以方便使用:
void onPreExecute(),进行异步任务操作前的回调接口,用户可在该接口中进行任务初始化的必要操作,该方法将在UI主线程中执行;
Result doInBackground(Params... params),AsyncTask将doInBackground()方法中的代码放入子线程中执行,Params为子类化AsyncTask时指定的第一个模板参数类型,用于在UI主线程传递参数给doInBackground()方法。Result为子类化AsyncTask时指定的第三个模板参数类型,表示子线程返回给主线程的数据类型;
void onProgressUpdate(Progress ),可以doInBackground()方法内通过publishProgress()更新异步任务进度,onProgressUpdate()方法将在主线程中被执行。通常Progress类型选择为Integer类型;
void onPostExecute(Result result),当子线程返回后,该方法将在UI主线程中被执行,其参数Result为doInBackground()方法的返回值。
通过上述几个方法,AsyncTask封装了子线程启动、通过Handler进行主线程与子线程通信等操作,暴露给调用者的仅仅是AsyncTask的对象构造以及execute(Params... params)方法。从而使得AsyncTask对象的调用者代码更加简洁,也使得代码更便于维护。
步骤一,打开第十四个项目
打开第十四个项目,在该项目的基础上完成本次实验。
步骤二,定义NewsListAsyncTask类
定义NewsListAsyncTask类继承至AsyncTask类,并重写doInBackground()方法及onPostExecute()方法,具体代码如下所示。
doInBackground()方法中的代码是原项目中放在子线程执行网络请求的代码,其参数为Integer类型的变长参数,其实参为实例化NewsListAsyncTask对象后调用execute()方法所传递进来的参数。在此我们将请求天行数据API所需的频道、每页新闻数量、当前页码三个参数传递给doInBackground()方法。
在doInBackground()方法内,还需构造Request请求对象、OkHttpClient请求客户端对象等,最后通过Call.execute()方法执行同步网络请求。 这一点与第十四个项目中使用OkHttpClient的Call.enqueue(Callback)进行异步网络请求略微不同。Call.execute()方法会阻塞当前线程直到Request对应的Response可用为止,因此可以直接在doInBackground()方法中获取Response对象,判断其返回状态再获取其ResponseBody响应体。并将ResponseBody响应体转换为String类型作为doInBackground()方法的返回值。
在介绍AsyncTask异步任务类的几个方法时,我们说过doInBackground()方法的代码将在子线程中执行,而当doInBackground()方法返回后,onPostExecute()方法将被在主线程中执行,而该方法的参数实际对应了doInBackground()方法的返回值。也就是说,doInBackground()方法将子线程处理后的结果交由onPostExecute()方法在主线程中进行进一步处理。其实现机制是Handler异步消息通信机制。
在onPostExecute()方法中,需要将ResponseBody响应体的数据进行解析,并转换成对应的News新闻对象,并添加至ListView绑定的NewsAdapter适配器中。该方法的代码与第十四个项目中okhttp3.Callback接口中的onResponse()方法的代码作用相同。只不过由于onPostExecute()方法本身在UI主线程中执行,因此不在需要runOnUiThread()方法将其切入UI主线程中。
最后NewsListAsyncTask的构造函数接收了两个参数,分别是Context上下文以及NewsAdapter适配器类,主要为了便于在onPostExecute()等方法中更新适配器的数据。
步骤三,修改MainActivity初始化数据代码
完成上述步骤后,最后需要修改MainActivity活动类中进行数据刷新的refreshData()方法的代码,具体代码如下所示。 在该方法中仅需要实例化NewsListAsyncTask对象并调用其execute()方法传递相应的天行数据API新闻频道、每页新闻数量、当前新闻页码参数即可。
而原来在MainActivity中定义的okhttp3.Callback接口可直接删除。如果仔细对比当前MainActivity的代码与第十四个项目的代码,你会发现使用AsyncTask异步任务类封装原来的网络请求代码后,MainActivity的代码更加简洁清晰,也更利于代码维护。如果需要多个接口请求,则再子类化AsyncTask实现特定的业务即可。
步骤四,编译并运行项目
编译并运行项目,其执行效果第十四个项目相同。
实验小结
通过本次实验,你应该掌握了如下知识内容:
掌握子类化AsyncTask异步任务进行异步操作的基本流程;
能使用AsyncTask实现异步任务处理;
Last updated
Was this helpful?