标签:
Handler mHadler = new Handler(){可以看到,每次要进行下载工作,我们就得先创建出Thread,然后在主线程中写好handler,为了对这个过程进行封装,Android提供了AsyncTask异步任务,AsyncTask对线程和handler进行了封装,使得我们可以直接在AsyncTask中进行UI的更新操作,就好像是在子线程进行UI更新一样。
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 1){
Bitmap bitmap = (Bitmap) msg.obj;
//更新UI...
}
}
};
private void download(){
new Thread(new Runnable() {
@Override
public void run() {
// 这里进行下载操作...获得了图片的bitmap
//下载完后才,向主线程发送Message
Message msg = Message.obtain();
msg.obj = bitmap;
msg.what = 1;//区分哪一个线程发送的消息
mHadler.sendMessage(msg);
}
}).start();
}
public abstract class AsyncTask<Params, Progress, Result>{ ... }其中,三个泛型类型参数的含义如下:
public class MyAsyncTask extends AsyncTask<String, Integer, Bitmap>{上面doInBackground()中获取进度值时,我们只是为了做一个进度值更新调用的演示,实际项目文件下载中,我们可能会对拿到的输入流进行处理,比如读取输入流将文件保存到本地,在读取输入流的时候,我们就可以获取到已经读取的输入流大小作为进度值了,如下:
private ProgressBar mPreogressBar;//进度条
private ImageView mImageView;//图片显示控件
public MyAsyncTask(ProgressBar pb,ImageView iv){
mPreogressBar = pb;
mImageView = iv;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
mPreogressBar.setVisibility(View.VISIBLE);
}
@Override
protected Bitmap doInBackground(String... params) {
String urlParams = params[0];//拿到execute()传过来的图片url
Bitmap bitmap = null;
URLConnection conn = null;
InputStream is = null;
try {
URL url = new URL(urlParams);
conn = url.openConnection();
is = conn.getInputStream();
//这里只是为了演示更新进度的功能,实际的进度值需要在从输入流中读取时逐步获取
for(int i = 0; i < 100; i++){
publishProgress(i);
Thread.sleep(50);//为了看清效果,睡眠一段时间
}
//将获取到的输入流转成Bitmap
BufferedInputStream bis = new BufferedInputStream(is);
bitmap = BitmapFactory.decodeStream(bis);
is.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mPreogressBar.setProgress(values[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
mPreogressBar.setVisibility(View.GONE);
mImageView.setImageBitmap(bitmap);
}
}
//实际项目中如何获取文件大小作为进度值及更新进度值 int totalSize = conn.getContentLength();//获取文件总大小 int size = 0;//保存当前下载文件的大小,作为进度值 int count = 0; byte[] buffer = new byte[1024]; while((count = is.read(buffer)) != -1){ size += count;//获取已下载的文件大小 //调用publishProgress更新进度,它内部会回调onProgressUpdate()方法 publishProgress(size,totalSize); Thread.sleep(100);//为了看清效果,睡眠一段时间 }
public class MainActivity extends AppCompatActivity {
private ImageView mImageView;
private ProgressBar mProgressBar;
private static String URL = "http://c.hiphotos.baidu.com/baike/s%3D220/sign=86442af5a6c27d1ea1263cc62bd4adaf/42a98226cffc1e17d8f914604890f603738de919.jpg";
private MyAsyncTask asyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image);
mImageView = (ImageView) findViewById(R.id.id_image);
mProgressBar = (ProgressBar) findViewById(R.id.pb);
asyncTask = new MyAsyncTask(mProgressBar, mImageView);
asyncTask.execute(URL);//将图片url作为参数传入到doInBackground()中
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/id_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/pb"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="30dp" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/id_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/pb"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="30dp" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:id="@+id/id_btn"
android:text="加载图片"
android:textSize="16sp"
android:layout_alignParentBottom="true"
android:onClick="loadImage"/>
</RelativeLayout>
public class MainActivity extends AppCompatActivity {现象一:在loadImage()方法中,我们直接再次通过asyncTask.execute()执行加载。看看此时效果如何:
private ImageView mImageView;
private ProgressBar mProgressBar;
private static String url = "http://c.hiphotos.baidu.com/baike/s%3D220/sign=86442af5a6c27d1ea1263cc62bd4adaf/42a98226cffc1e17d8f914604890f603738de919.jpg";
private MyAsyncTask asyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image);
mImageView = (ImageView) findViewById(R.id.id_image);
mProgressBar = (ProgressBar) findViewById(R.id.pb);
asyncTask = new MyAsyncTask(mProgressBar, mImageView);
asyncTask.execute(url);
}
public void loadImage(View v){
asyncTask.execute(url);
}
}
public void loadImage(View v){此时效果如下:
Intent i = new Intent(this,MainActivity.class);
startActivity(i);
}
@Override继续修改AsyncTask,在这里面进行任务是否被取消的检测,这里我们只简单修改下doInBackground()和onProgressUpdae()方法,实际项目中开自己的业务逻辑来控制,如下:
protected void onPause() {
super.onPause();
if(asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING){
//cancel只是将对应的任务标记为取消状态
asyncTask.cancel(true);
}
}
@Override在doInBackground()的for循环更新进度过程中,我们持续不断的监听任务十分被取消,一旦取消了,尽快退出doInBackground的执行,现在运行效果如下:
protected Bitmap doInBackground(String... params) {
String urlParams = params[0];//拿到execute()传过来的图片url
Bitmap bitmap = null;
URLConnection conn = null;
InputStream is = null;
try {
URL url = new URL(urlParams);
conn = url.openConnection();
is = conn.getInputStream();
for(int i = 0; i < 100; i++){
if(isCancelled()){//通过isCancelled()判断任务任务是否被取消
break;
}
publishProgress(i);
Thread.sleep(50);//为了看清效果,睡眠一段时间
}
BufferedInputStream bis = new BufferedInputStream(is);
bitmap = BitmapFactory.decodeStream(bis);
is.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if(isCancelled()){//通过isCancelled()判断任务任务是否被取消
return;
}
mPreogressBar.setProgress(values[0]);
}
private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "AsyncTask #" + mCount.getAndIncrement()); } }; private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); /** * 真正用来执行任务的的线程池 */ public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory); /** * 定义一个线程池,在线程池中有一个Runnable任务队列,用来存放、顺序执行任务 */ public static final Executor SERIAL_EXECUTOR = new SerialExecutor(); //AsyncTask内部默认使用的线程池 private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; //自定义的一个Handler private static InternalHandler sHandler;
AsyncTask的execute()交给了executeOnExecutor()方法,将将默认的线程池作为参数传进来,进入executeOnExecutor方法中:@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread上面第一步,先判断当前AsyncTask是否正在运行或已经执行完毕,如果正在执行或执行完毕再次执行将抛出异常,这也正是我们前面在使用的时候谈到,同一个AsyncTask不能多次进行execute()的原因!到了第三步的时候,先去调用一下onPreExecute()方法,因为executeOnExecutor方法本身就是在UI线程中运行的,所以onPreExecute也会在UI线程中运行。第四步,才会开始讲当前AsyncTask任务加入到队列中,我们进入默认的线程池中去看一下:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {//1、这里判断当前AsyncTask是否正在执行或已执行完毕
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;//2、设置正在执行的状态
onPreExecute();//3、回调onPreExecute()方法
mWorker.mParams = params;
exec.execute(mFuture);//4、放到前面默认构造的线程池中去执行
return this;
}
private static class SerialExecutor implements Executor {在第四步执行execute时,实际就是调用的SerialExecutor中的execute方法,在这里面,先创建了一个Runnable对象,然后将这个Runnable对象添加到任务队列mTasks中,在当执行到这个Runnable时调用scheduleNext去队列中取出一个任务,然后交给另一个线程池去真正执行这个任务。
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
private static class InternalHandler extends Handler {每当收到子线程发来的和UI线程进行通信的handler请求时,先从Message中拿到子线程发来的结果参数AsyncTaskResult,AsyncTaskResult里面封装了AsyncTask对象和数据信息,如下:
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
mFuture = new FutureTask<Result>(mWorker) {在上面的postResultIfNotInvoked()中会通过handler进行消息的发送。
@Override
protected void done() {
try {
postResultIfNotInvoked(get());//这里面通过handler往UI线程发送消息
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
标签:
原文地址:http://blog.csdn.net/shakespeare001/article/details/51720548