android开发笔记之网络编程—异步加载(AsyncTask)
2016-06-03 16:28
549 查看
看了前面的文章我们知道请求网络的几种方式:
1.使用TCP协议和URL进行网络编程
2.使用Http协议进行网络编程
我们知道这些网络请求都应该在子线程中,不能在主线程中(因为耗时操作会阻塞主线程,造成ANR)。但是在子线程中请求的数据需要传递给主线程来更新UI。我们经常使用的一种方式应该是借助于 Handler机制。
是的,这是一种方式,今天我们来讲解另外一种方式来更新UI—–AsyncTask(异步加载).
这个AsyncTask(异步加载)将访问网络和更新UI放在了一起,其实究其根源也是使用了Handler机制,只不过帮我们把Handler机制和访问网络封装起来罢了。
那这两种方式做个比较:
Handler VS AsyncTask
AsyncTask实现的原理:AsyncTask的本质是一个线程池,所有提交的异步任务都会在这个线程池中的工作线程内执行,当工作线程需要跟UI线程交互时,工作线程会通过向在UI线程创建的Handler传递消息的方式,调用相关的回调函数,从而实现UI界面的更新。
优点:
①简单快捷
②过程可控
缺点:
在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
Handler实现的原理:在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message- àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。
优点:
①结构清晰,功能定义明确
②对于多个后台任务时,简单清晰
缺点:
在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
既然这样我们就来讲下AsyncTask(异步加载)吧。
AsyncTask定义了三种泛型类型 Params,Progress和Result。(也是可以指定为空的,如 AsyncTask <Void, Void, Void>)
使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:
doInBackground(Params…)
说明:
onPostExecute(Result)
说明:
有必要的话你还得重写以下这三个方法,但不是必须的:
onProgressUpdate(Progress…)
说明:
onPreExecute()
说明:
onCancelled() 用户调用取消时,要做的操作
使用AsyncTask类,以下是几条必须遵守的准则:
Task的实例必须在UI thread中创建
execute方法必须在UI thread中调用
不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法;
该task只能被执行一次,否则多次调用时将会出现异常
流程:
实例-excute(Params)-doInBackground的参数
Progress-publishProgress的参数-onProgressUpdate的参数
Result-doInBackground返回值-onPostExcute的参数
这里举个例子说明一下:
假设Params 为Integer
Progress 为Integer
Result 为String
则AsyncTask<Integer,Integer,String>
示意图:
这幅图可以知道各个方法的执行顺序,以及各个参数的来源和流向。这应该很清楚了,我就不解释了。
这里写个示例代码模拟下:
效果:
首先一个异步的下载的类DownloadTask.java
doInBackground中用个for循环来模拟耗时操作。
参数传了一个睡眠数
activity_main.xml
MainActivity.java
看起来感觉很复杂,但是学会了用起来是很方便的。小伙伴赶紧试试吧。
源码下载:http://download.csdn.net
1.使用TCP协议和URL进行网络编程
a)基于TCP协议:ServerSocket,Socket b)基于URL:URL 和 URLConnection
2.使用Http协议进行网络编程
a)HttpURLConnection b)HttpClient
我们知道这些网络请求都应该在子线程中,不能在主线程中(因为耗时操作会阻塞主线程,造成ANR)。但是在子线程中请求的数据需要传递给主线程来更新UI。我们经常使用的一种方式应该是借助于 Handler机制。
是的,这是一种方式,今天我们来讲解另外一种方式来更新UI—–AsyncTask(异步加载).
这个AsyncTask(异步加载)将访问网络和更新UI放在了一起,其实究其根源也是使用了Handler机制,只不过帮我们把Handler机制和访问网络封装起来罢了。
那这两种方式做个比较:
Handler VS AsyncTask
AsyncTask实现的原理:AsyncTask的本质是一个线程池,所有提交的异步任务都会在这个线程池中的工作线程内执行,当工作线程需要跟UI线程交互时,工作线程会通过向在UI线程创建的Handler传递消息的方式,调用相关的回调函数,从而实现UI界面的更新。
优点:
①简单快捷
②过程可控
缺点:
在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
Handler实现的原理:在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message- àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。
优点:
①结构清晰,功能定义明确
②对于多个后台任务时,简单清晰
缺点:
在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
既然这样我们就来讲下AsyncTask(异步加载)吧。
AsyncTask定义了三种泛型类型 Params,Progress和Result。(也是可以指定为空的,如 AsyncTask <Void, Void, Void>)
- Params 启动任务执行的输入参数。比如Http请求的URL - Progress 后台任务执行的进度百分比。 - Result 后台执行任务最终返回的结果。比如String
使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:
doInBackground(Params…)
说明:
doInBackground有返回值,并且返回值由Result决定 参数列表首先是一个可变长参数,是由Params决定 执行时机:在onPreExecute()方法之后立马执行 作用:主要负责执行那些很耗时的后台操作,在后台执行 跟之前在子线程写的代码是一样的 在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
onPostExecute(Result)
说明:
onPostExecute(Result)没有返回值 参数是doInBackground的返回值 执行时机:doInBackground执行完 相当于Handler 处理UI的方式 此方法在主线程执行
有必要的话你还得重写以下这三个方法,但不是必须的:
onProgressUpdate(Progress…)
说明:
没返回值,不会主动回调,而是需要publishProgress()去间接调用 onProgressUpdate的参数由Progress决定 执行时机:这个函数在doInBackground调用publishProgress()之后 作用:在界面上展示任务的进度情况,可以使用进度条增加用户体验度 跟之前handleMessesg中的代码一样 此方法在主线程执行
onPreExecute()
说明:
没有返回值也没有参数 执行时机:这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法 作用:可以在该方法中做一些准备工作及一些初始化的操作,这个方法可以不用实现
onCancelled() 用户调用取消时,要做的操作
使用AsyncTask类,以下是几条必须遵守的准则:
Task的实例必须在UI thread中创建
execute方法必须在UI thread中调用
不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法;
该task只能被执行一次,否则多次调用时将会出现异常
流程:
实例-excute(Params)-doInBackground的参数
Progress-publishProgress的参数-onProgressUpdate的参数
Result-doInBackground返回值-onPostExcute的参数
这里举个例子说明一下:
假设Params 为Integer
Progress 为Integer
Result 为String
则AsyncTask<Integer,Integer,String>
示意图:
这幅图可以知道各个方法的执行顺序,以及各个参数的来源和流向。这应该很清楚了,我就不解释了。
这里写个示例代码模拟下:
效果:
首先一个异步的下载的类DownloadTask.java
doInBackground中用个for循环来模拟耗时操作。
参数传了一个睡眠数
/** * 流程: * 实例-excute(Params)-doInBackground的参数 * Progress-publishProgress的参数-onProgressUpdate的参数 * Result-doInBackground返回值-onPostExcute的参数 */ /** * 三个泛型 第一个参数Params:后台处理时需要传递过来的数据类型,比如URL ---String 第二个参数Progress:进度百分比 * 第三个参数Result:后台处理完成返回数据类型 * * @author Administrator * */ public class DownloadTask extends AsyncTask<Integer, Integer, String> { TextView tv; ProgressBar pb; public DownloadTask(TextView tv, ProgressBar pb) { this.tv = tv; this.pb = pb; } // 执行时机:在执行实际的后台操作前,被UI线程调用 // 可以在该方法中做一些准备工作,这个方法可以不用实现 @Override protected void onPreExecute() { System.out.println("准备"); super.onPreExecute(); } // doInBackground有返回值,并且返回值由Result决定 // 参数列表首先是一个可变长参数,是由Params决定 // 执行时机:在onPreExecute()方法之后立马执行 // 作用:主要负责执行那些很耗时的后台操作 // 跟之前在子线程写的代码是一样的 @Override protected String doInBackground(Integer... params) { try { for (int i = 0; i < 101; i++) { Thread.sleep(params[0]); publishProgress(i); } } catch (InterruptedException e) { e.printStackTrace(); return "下载失败"; } return "下载完成"; } // 没返回值,不会主动回调,而是需要publishProgress()去间接调用 // onProgressUpdate的参数由Progress决定 // 执行时机:这个函数在doInBackground调用publishProgress()之后 // 作用:在界面上展示任务的进度情况 // 跟之前handleMessesg中的代码一样 @Override protected void onProgressUpdate(Integer... values) { tv.setText("当前下载了" + values[0] + "%"); pb.setProgress(values[0]); super.onProgressUpdate(values); } // 没有返回值,参数是doInBackground的返回值 // 执行时机:doInBackground执行完 @Override protected void onPostExecute(String result) { tv.setText(result); super.onPostExecute(result); } }
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.asynctask.MainActivity" > <Button android:layout_width="match_parent" android:onClick="onClick" android:text="开始加载" android:layout_height="wrap_content"/> <ProgressBar android:id="@+id/pb" android:layout_width="match_parent" android:layout_height="wrap_content" style="@android:style/Widget.ProgressBar.Horizontal"/> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </LinearLayout>
MainActivity.java
public class MainActivity extends Activity { private ProgressBar pb; private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); pb = (ProgressBar) findViewById(R.id.pb); tv = (TextView) findViewById(R.id.tv); } public void onClick(View view) { DownloadTask downloadTask = new DownloadTask(tv, pb); downloadTask.execute(1000); } }
看起来感觉很复杂,但是学会了用起来是很方便的。小伙伴赶紧试试吧。
源码下载:http://download.csdn.net
相关文章推荐
- BP神经网络
- BP神经网络
- linux使用tcpdump抓包工具抓取网络数据包,多示例演示
- UNIX网络编程笔记(4)—TCP客户/服务器程序示例
- 使用 Netty 进行 UDP 网络编程
- FCN(全卷积神经网络)
- 网络制式
- WebUtils-网络请求工具类
- 使用httpclient实现上传下载(javaWeb系统数据传输http实现)
- 新手教程之:循环网络和LSTM指南 (A Beginner’s Guide to Recurrent Networks and LSTMs)
- Android apache httpClient
- 报错:The type javax.servlet.http.HttpServletRequest cannot be resolved
- 网络爬虫介绍
- HTTPS对谷歌百度SEO的影响
- TCP中 recv和sendf函数
- iOS笔记—NSURLConnection怎么把http改为https
- Unable to enable crypto on TCP connection make sure the sslcafile or sslcapath option are properly
- MVC中HttpContext, HttpContextBase, HttpContextWrapper联系
- java TCP/IP网络编程(2)
- HttpClientUtil工具类,发送get请求和post请求