说明
在Android中我们可以通过Thread+Handler实现多线程通信,一种经典的使用场景是:在新线程中进行耗时操作,当任务完成后通过Handler向主线程发送Message,这样主线程的Handler在收到该Message之后就可以进行更新UI的操作。上述场景中需要分别在Thread和Handler中编写代码逻辑,为了使得代码更加统一,我们可以使用AsyncTask类。
Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。
Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。
AsyncTask定义
AsyncTask直接继承于Object类,位置为android.os.AsyncTask。
要使用AsyncTask工作我们要提供三个泛型参数。
AsyncTask定义了三种泛型类型 Params,Progress和Result:
AsyncTask执行过程
AsyncTask有四个重要的回调方法,分别是:onPreExecute、doInBackground, onProgressUpdate 和 onPostExecute。
AsyncTask使用示例:
我们在网上获取一个网页,在一个TextView中将其源代码显示出来,并用一个ProgressBar
显示进度。
布局文件:activity.xml:
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BUTTON"/>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="0"
android:visibility="gone"/>
<ScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="@color/colorPrimary"
android:textSize="18sp"
android:text="HELLO"/>
</ScrollView>
MainActivity.java:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private String textUrl = "http://www.baidu.com";
private ImageLoader imageLoader;
private Button button;
private TextView showText;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindView();
}
private void bindView() {
button = (Button)this.findViewById(R.id.button);
showText = (TextView)this.findViewById(R.id.textView);
progressBar = (ProgressBar)this.findViewById(R.id.progressBar);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button:
//在MainActivity中创建AsyncTask实例
imageLoader = new ImageLoader(this,button,progressBar,showText);
//启动异步任务,这个方法调用后,会执行AsyncTask的doInBackground()方法
imageLoader.execute(textUrl);
break;
}
}
}
自定义AsyncTask:
public class ImageLoader extends AsyncTask<String,Integer,String> {
private static final String TAG = "ImageLoader";
private Button button;
private Context mContext;
private TextView textView;
private ProgressBar progressBar;
public ImageLoader(Context context,Button button,ProgressBar progressBar,TextView textView){
this.mContext = context;
this.button = button;
this.progressBar = progressBar;
this.textView = textView;
}
//在這里我们可以对控件进行初始化操作,通常可以在该方法中显示一个进度条,从而告知用户后台任务即将开始。
@Override
protected void onPreExecute() {
progressBar.setProgress(0);
progressBar.setVisibility(View.VISIBLE);
}
//该方法不运行在UI线程中,主要用于异步操作,通过调用publishProgress()方法
//触发onProgressUpdate对UI进行操作
@Override
protected String doInBackground(String... params) {
String html = null;
URL textUrl;
HttpURLConnection connection = null;
InputStream is = null;
OutputStream os = null;
try {
textUrl = new URL(params[0]);
connection = (HttpURLConnection) textUrl.openConnection();
//要想得到文件的真实大小,必须加上这行代码
connection.setRequestProperty("Accept-Encoding", "identity");
is = connection.getInputStream();
int total = connection.getContentLength();
Log.i("Total",""+total);
int current = 0;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while((len = is.read(buffer)) != -1)
{
outStream.write(buffer,0,len);
Log.i("Fuck",""+len);
current+=len;
int progress = (int)((float)current/total*100);
if (total ==0){
publishProgress(-1);
}else{
//调用AsyncTask的publishProgress(Progress…)将阶段性的处理结果发布出去,阶段性处理结果是Progress泛型类型。
publishProgress(progress);
}
Log.i(TAG,""+progress);
Thread.sleep(1000);
}
html = new String(outStream.toByteArray(), "UTF-8");
return html;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return html;
}
//在doInBackground方法中,每次调用publishProgress方法都会触发该方法
//运行在UI线程中,可对UI控件进行操作,我们在这里进行进度的显示
@Override
protected void onProgressUpdate(Integer... values) {
Log.i(TAG,""+values[0]);
int currentProgress = values[0];
if (currentProgress!=-1) {
progressBar.setProgress(currentProgress);
}
progressBar.setProgress(values[0]);
}
//该方法是在主线程中被调用的。当doInBackgroud方法执行完毕后,就表示任务完成了,doInBackgroud方法的返回值就会作为参数在主线程中传入到onPostExecute方法中,这样就可以在主线程中根据任务的执行结果更新UI。
protected void onPostExecute(String str) {
if (str != null) {
Log.i(TAG,"fuck");
textView.setText(str);
progressBar.setProgress(100);
progressBar.setVisibility(View.GONE);
}
}
}
别忘记加上网络权限哦~
<uses-permission android:name="android.permission.INTERNET"/>