android基础学习之AsyncTask


AsyncTask是 Android用来实现异步操作的一个类,因为被 Android创造时加入了android的平台特性,因此, AsyncTask的异步操作相对于 Thread来说,更安全、方便和实用。但其实质上也是对 Thread的一个封装。与Handler很相似,都是为了使一些耗时操作不会堵塞android主线程并解决android的非主线程不能进行UI操作,而诞生的。

AsyncTask可以很方便的执行异步操作(doinBackground()),又能很方便的与主线程进行通讯,而且其又有很好的封装性,所以能够进行取消(cancel())操作。


下面给出示例代码:通过网络下载一张图片并显示。

package com.cao.asynctasktest;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;

/**
 * @author caohuize
 * AysncTaskDemo 通过网络下载一个图片的状态来学习AysncTask
 */
public class MainActivity extends Activity {
    private static final String ImageUrl = "http://i1.cqnews.net/sports/attachement/jpg/site82/2011-10-01/2960950278670008721.jpg";
    private ProgressBar mProgressBar;
    private ImageView mImageView;
    private Button mGetImage;
    private Button mAbort;
    
    @Override
    public void onCreate(Bundle icicle) {
	super.onCreate(icicle);
	setContentView(R.layout.activity_main);
	mProgressBar = (ProgressBar) findViewById(R.id.async_task_progress);
	mImageView = (ImageView) findViewById(R.id.async_task_displayer);
	final ImageLoader loader = new ImageLoader();
	mGetImage = (Button) findViewById(R.id.async_task_get_image);
	mGetImage.setOnClickListener(new View.OnClickListener() {
	    public void onClick(View v) {
	    	/*开启异步线程操作*/
	    	Log.i("cao", "user call execute!");
	    	loader.execute(ImageUrl);
	    }
	});
	mAbort = (Button) findViewById(R.id.asyc_task_abort);
	mAbort.setOnClickListener(new View.OnClickListener() {
	    public void onClick(View v) {
	    	/*取消这个异步线程操作,销毁线程*/
	    	loader.cancel(true);
	    }
	});
	mAbort.setEnabled(false);
    }
    
    private class ImageLoader extends AsyncTask<String, Integer, Bitmap> {
	private static final String TAG = "ImageLoader";

	/**
	 *这是用户调用execute()方法之后最先调用的方法
	 **/
	@Override
	protected void onPreExecute() {
	    // Initialize progress and image
		Log.i("cao", "call onPreExecute begin!");
	    mGetImage.setEnabled(false);
	    mAbort.setEnabled(true);
	    mProgressBar.setVisibility(View.VISIBLE);
	    mProgressBar.setProgress(0);
	    mImageView.setImageResource(R.drawable.ic_launcher);
	}
	/**
	 *经过 onPreExecute 方法的准备之后,进入耗时操作方法
	 **/
	@Override
	protected Bitmap doInBackground(String... url) {
		Log.i("cao", "call doInBackground begin!");
		//一些网络操作代码,通过网络下载图片保存后并转化为Bitmap
	    try {
		URL u;
		HttpURLConnection conn = null;
		InputStream in = null;
		OutputStream out = null;
		final String filename = "local_temp_image";
		try {
		    u = new URL(url[0]);
		    conn = (HttpURLConnection) u.openConnection();
		    conn.setDoInput(true);
		    conn.setDoOutput(false);
		    conn.setConnectTimeout(20 * 1000);
		    in = conn.getInputStream();
		    out = openFileOutput(filename, Context.MODE_PRIVATE);
		    byte[] buf = new byte[8196];
		    int seg = 0;
		    final long total = conn.getContentLength();
		    long current = 0;
		    /*
		     * Without checking isCancelled(), the loop continues until reading whole image done, i.e. the progress
		     * continues go up to 100. But onPostExecute() will not be called.
		     * By checking isCancelled(), we can stop immediately, i.e. progress stops immediately when cancel() is called.
		     */
		    while (!isCancelled() && (seg = in.read(buf)) != -1) {
			out.write(buf, 0, seg);
			current += seg;
			int progress = (int) ((float) current / (float) total * 100f);
			publishProgress(progress);
			SystemClock.sleep(1000);
		    }
		} finally {
		    if (conn != null) {
			conn.disconnect();
		    }
		    if (in != null) {
			in.close();
		    }
		    if (out != null) {
			out.close();
		    }
		}
		return BitmapFactory.decodeFile(getFileStreamPath(filename).getAbsolutePath());
	    } catch (MalformedURLException e) {
		e.printStackTrace();
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	    return null;
	}
	/**
	 *开始耗时操作之后,开始跟新用户进度的方法 
	 **/
	@Override
	protected void onProgressUpdate(Integer... progress) {
		Log.i("cao", "call onProgressUpdate begin!");
	    mProgressBar.setProgress(progress[0]);
	}
	/**
	 *当耗时操作方法完之后,调用修改UI的方法。 
	 **/
	@Override
	protected void onPostExecute(Bitmap image) {
		Log.i("cao", "call onPostExecute begin!");
	    if (image != null) {
		mImageView.setImageBitmap(image);
	    }
	    mProgressBar.setProgress(100);
	    mProgressBar.setVisibility(View.GONE);
	    mAbort.setEnabled(false);
	}
    }
}

这里是配置文件的代码:

<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"
    tools:context=".MainActivity" >
 	<!-- 分别显示   下载进度的显示-->
    <ProgressBar
        android:id="@+id/async_task_progress"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        style="?android:attr/progressBarStyleHorizontal"
        android:max="100"
        />
    <!-- 分别显示   下载前 下载中  下载后的显示 -->
	<ImageView
	    android:id="@+id/async_task_displayer"
	    android:layout_width="200dp"
	    android:layout_height="200dp"
	    android:layout_marginTop="20dp"
	    android:layout_gravity="center_horizontal"
	    android:background="@drawable/public_head_boy"
	    />
	<LinearLayout 
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content"
	    android:orientation="horizontal"
	    android:layout_marginTop="20dp"
	    android:layout_gravity="center_horizontal"
	    >
	    <Button
	        android:id="@+id/async_task_get_image"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:text="get the image"/>
	    <Button
	        android:id="@+id/asyc_task_abort"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:text="abort"/>
	</LinearLayout>
</LinearLayout>

AsyncTask的方法

  必选方法:

         1.doinBackground(params) 后台操作,程序中耗时的操作可以放在这个方法里面,不能操作UI, Params 是任务执行器需要的数据类型。其Params是可变参数。

       2. onpostexecute(results)相当于handler处理UI的方式,在这里可以使用在doinbackground得到的结果处理操作UI,在此异步操作线程。此方法在主线程执行,任务执行的结果作为此方法的参数返回。results也是可变参数。

 

 可选方法:

         1  onprogressupdate(progress…)可以使用进度条增加用户体验度。此方法在主线程执行,用户显示任务执行的进度。progress也是可变参数,可以用来查看异步线程的进度。
       2
、  onpreExecute()  这里是最新用户调用excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
       3
、  onCancelled()  用户调用取消时,要做的操作。

另外,Google还给AsyncTask制定了一些限制:

       1.AsyncTask的实例必须是在主线程即UI线程中创建

       2. AsyncTask的实例的Execute()方法必须在主线程中调用。(一般是在需要进行异步线程操作时调用)

       3.不要手动调用AsyncTask里面的几个方法。

       4. AsyncTask对象不可重复使用,也就是说一个AsyncTask对象只能execute()一次,否则会有异常抛出"java.lang.IllegalStateException:Cannot execute task: the task is already running"

       5.doInBackground()中要检查isCancelled()的返回值,如果你的异步任务是可以取消的话。

注:cancel()仅仅是给AsyncTask对象设置了一个标识位,当调用了cancel()后,发生的事情只有:AsyncTask对象的标识位变了,和doInBackground()执行完成后,onPostExecute()不会被回调了,而doInBackground()onProgressUpdate()还是会继续执行直到doInBackground()结束。所以要在doInBackground()中不断的检查isCancellled()的返回值,当其返回true时就停止执行,特别是有循环的时候。如上面的例子,如果把读取数据的isCancelled()检查去掉,图片还是会下载,进度也一直会走,只是最后图片不会放到UI(因为onPostExecute()没被回调)!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值