Android AsyncTask 基本使用

我们知道Android的activity如果没有在5秒内处理完某个事件,将会触发一个ANR事件,该事件将会极大地影响用户体验。

使用Android 的AsyncTask可以以后台线程的形式更新用户界面,可在程序中用来处理一些耗时的操作。

比如实现一个从网络上抓取图片显示在一个ImageView中,效果如下图:

布局文件main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    android:id="@+id/btn" 
    android:text="Get Image"
    android:onClick="download"
    />
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:id="@+id/progress" 
    android:text="hello"
    />
<ImageView 
    android:id="@+id/img"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    /> 

</LinearLayout>

Activity文件

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class AndroidServiceActivity extends Activity {
    
    private DownloadTask mDownloadTask;
    private final String TAG = "AndroidService";
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        // 如果切换了配置,比如横竖屏切换,需要重新让contex和AsyncTask建立连接
        if((mDownloadTask = (DownloadTask)getLastNonConfigurationInstance())!=null){
            mDownloadTask.setmContext(this);
            if(mDownloadTask.getStatus() == AsyncTask.Status.FINISHED){
                mDownloadTask.setImageInView();
            }
        }
    }
    
    /**
     * 视图上点击按钮触发的事件
     * @param view
     */
    public void download(View view){
        if(mDownloadTask != null){
            AsyncTask.Status diStatus = mDownloadTask.getStatus();
            if(diStatus!=AsyncTask.Status.FINISHED){
                Log.i("AndroidService", "... no need to start a new task!");
                return;
            }
        }
        mDownloadTask = new DownloadTask(this);
        mDownloadTask.execute("http://10.0.2.2:8088/pamdps/images/icon.png");
        
        
        Log.i("AndroidService", "download");
    }
    
    /**
     * 如果切换了配置,比如横竖屏切换,需要重新让contex和AsyncTask建立连接
     */
    @Override
    public Object onRetainNonConfigurationInstance() {
        Log.i(TAG, "onRetainNonConfigurationInstance");
        return mDownloadTask;
    }
    
}

后台异步线程DownloadTask.java

public class DownloadTask extends AsyncTask<String, Integer, Bitmap>{

    private Context mContext;
    Bitmap downloadedImage = null;
    private final String TAG = "AndroidService";
    
    public DownloadTask(Context context) {
        super();
        this.mContext = context;
    }
    
    /**
     * 供主线程在更改配置后重新设置该Task的context
     * @param mContext
     */
    public void setmContext(Context mContext) {
        Log.v(TAG, "setContext");
        this.mContext = mContext;
    }
    
    @Override
    protected Bitmap doInBackground(String... urls) {
        return downloadImage(urls);
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        if(result!=null){
            downloadedImage = result;
            setImageInView();
        }else{
            Log.e(TAG, "download image error");
        }
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        TextView mText = (TextView) ((Activity)mContext).findViewById(R.id.progress);
        mText.setText("Progress so far:"+values[0]);
        
        super.onProgressUpdate(values);
    }

    /**
     * 执行图片的下载
     * @param urls
     * @return
     */
    private Bitmap downloadImage(String... urls) {
        HttpParams httpParameters;  
        int timeoutConnection = 3000;  
        int timeoutSocket = 5000; 
        httpParameters = new BasicHttpParams();
    // Set the timeout in milliseconds until a connection is established. HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
     // Set the default socket timeout (SO_TIMEOUT) // in milliseconds which is the timeout for waiting for data.
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); HttpGet request = new HttpGet(urls[0]); Log.i(TAG, urls[0]); HttpClient httpClient = new DefaultHttpClient(httpParameters); httpClient.getParams().setParameter("", 5000); HttpResponse response; try { publishProgress(25); response = httpClient.execute(request); Log.i("", response.getStatusLine().getStatusCode()+""); if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ publishProgress(50); //这一句是为了测试横竖屏切换时是否能正常显示下载的图片,预留切换时间 sleepFor(5000); byte[] image = EntityUtils.toByteArray(response.getEntity()); publishProgress(75); Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length); publishProgress(100); return bitmap; }else{ } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } protected void setImageInView(){ ImageView mImage = (ImageView) ((Activity)mContext).findViewById(R.id.img); mImage.setImageBitmap(downloadedImage); } private void sleepFor(long msecs){ try { Thread.sleep(msecs); } catch (InterruptedException e) { Log.v("", e.getMessage()); } } }

需要在清单文件中添加网络访问权限

 <!-- 网络访问权限 -->
 <uses-permission android:name="android.permission.INTERNET" />

 

使用AsyncTask包括4个步骤

1、在onPreExecute中执行设置工作,该方法在主线程中执行。

2、使用doInBackground运行后台线程。线程创建全部在后台完成。

3、publishProgress()和onProgressUpdate()来更新进度,前者在doInBackground()中调用,后缀在主线程中执行,所以用这两个方法可以是后台线程在运行期间和主线程通信。

4、onPostExecute()用来更新用户界面,在主线程中执行。

本实例包含以下知识点:

1、httpclient的基本使用方法

2、httpclient的超时设置

3、AsyncTask的基本使用

4、切换横竖屏后Activity和AsyncTask重新建立连接的方法

 

说明:本文章是参考《精通Android3》第11章写的,权当学习笔记。</

posted on 2012-04-27 17:04  lepfinder  阅读(474)  评论(0编辑  收藏  举报