- 引入:
还是那个问题:Android的单线程模型原则—只能在主线程更新UI.
如果要在非主线程中更新UI,除了用Handler之外,还有一种封装得很好的机制AsyncTask
源码解释: AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate(操作) threads and/or handlers.
AsyncTask可以帮助我们在后台通过新线程执行操作并且把结果返回给UI线程.比起handlers它的封装性更高.
AsyncTask
参数引入:- Params
传入参数,给后台任务使用.比如我们要加载一个图片Url,则Params可以是String类型. - Progress(进度)
可以作为doInBackground执行的进度反映. - Result
任务执行完成,返回给主线程.
- 使用:
假如要执行耗时操作,例如加载一个网页图片或者登陆验证等
Step 1. 我们可以新建一个类继承自AsyncTask
Step 2. 重写AsyncTask的方法:
- onPreExecute()
该方法用于耗时操作之前所做的准备,例如加载图片或者登陆操作之前显示进度条. - doInBackground(Params…)
该方法主要进行耗时操作,即启动新线程(已经自动封装)执行你要的操作.
注意的是该方法常伴随着publishProgress(Progress…) 语句, 该方法可以调用并且传递参数Progress给第三个方法onProgressUpdate(Progress…) - onProgressUpdate(Progress…) 根据publishProgress传递的参数获取当前耗时操作的进度.
- onPostExecute(Result)
当耗时操作完成的时候,该方法会被调用,
当你执行到这个方法的时候,此时已经处于UI线程了,此时可以放心的进行UI操作,其中Result作为返回结果,完全可以作为UI界面的更新.
- onPreExecute()
简单代码示例:
我们通过一个小程序来测试AsyncTask的处理机制:
利用异步操作处理加载图片,在图片加载完成之后返回给UI线程并执行更新.
新建类ImageLoad继承自Activity
创建内部类MyAsyncTask 继承自AsyncTask
package com.example.asynctask_test;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
public class ImageLoad extends Activity {
private ImageView imageView ;
private ProgressBar progressbar;
private static String url =
"http://img.mp.itc.cn/upload/20160320/3f7f53242afc44cb9e858ddb5a2334c9_th.jpg";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image);
imageView = (ImageView) findViewById(R.id.image);
progressbar = (ProgressBar) findViewById(R.id.progressbar);
//开启异步线程操作
new MyAsyncTask().execute(url);
}
//内部类
class MyAsyncTask extends AsyncTask<String, Void, Bitmap>{
@Override
protected void onPreExecute() {
super.onPreExecute();
//线程开始之前,显示进度条(一直转圈)
progressbar.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
//doInBackground完成之后执行根据返回的图片(result)更新UI
//主线程
progressbar.setVisibility(View.GONE);
imageView.setImageBitmap(result);
}
@Override
protected Bitmap doInBackground(String... params ) {
//取出参数作为URL
String url = params[0];
Bitmap bitmap = null;
URLConnection connection;
InputStream is; //由connection获取InputStream
try {
connection = new URL(url).openConnection();
is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
//通过decodeStream解析输入流
bitmap = BitmapFactory.decodeStream(bis);
is.close();
bis.close();
//为了显示进度条,睡眠3秒
Thread.sleep(3000);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
//返回解析的Bitmap
return bitmap;
}
}
}
ImageLoad布局文件 image.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/image"/>
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"
/>
</RelativeLayout>
一开始我们把进度条设置为GONE(区别于invisible,GONE隐藏并且释放空间),当进入加载活动(doInbackground()执行之前)在onPreExecute()中进度条设置显示progressbar.setVisibility(View.VISIBLE);
在耗时操作完成后(图片加载完毕),在onPreExecute()执行progressbar.setVisibility(View.GONE);
表示图片加载完成
运行结果:
代码来源:
iMooc网教程