Android AsyncTask异步任务

在上一篇文章 《Android网络编程之使用HttpClient进行Get方式通信》中,我们强制直接在UI线程进行网络操作,在实际的应用开发过程中不能这样做,因为这样很可能会阻塞UI,影响用户体验。为了避免直接在UI线程中进行网络操作,我们可以使用AsyncTask异步处理网络通信和UI更新。通过AysncTask可以很容易的启动后台线程进行网络通信,然后将结果返回到UI线程中。

AsyncTask是Android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。

AsyncTask是为了方便编写后台线程与UI线程交互的辅助类,它的内部实现是一个线程池,每个后台任务会提交到线程池中的线程执行,然后通过向UI线程传递消息的方式调用相应的回调方法实现UI界面的更新。AsyncTask类有三个模板参数:Params(传递给后台任务的参数类型),Progress(后台计算执行过程中,进度单位(progress units)的类型,也就是后台程序已经执行了百分之几)和Result(后台执行返回的结果的类型)。

使用AsyncTask最少要重写以下两个方法:
1、doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
2、onPostExecute(Result) 在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回 。

使用AsyncTask类,以下是几条必须遵守的准则:
1、Task的实例必须在UI Thread中创建;
2、execute()方法必须在UI Thread中调用;
3、不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
4、该Task只能被执行一次,否则多次调用时将会出现异常;

AsyncTask的一般使用步骤:
1、继承AsyncTask类并至少重写doInBackground(Params…)和onPostExecute(Result)方法;
2、实例化AsyncTask的子类;
3、调用该实例的execute()方法以启动任务。

整个流程:
AsyncTask的整个调用过程都是从execute()方法开始的(主线程中调用),一旦在主线程中调用execute方法,就会调用onPreExecute方法,在这里可以做一些准备工作,如在界面上显示一个进度条,或者一些控件的实例化.同样也可以通过onProgressUpdate方法给用户一个进度条的显示更新,增加用户体验;最后通过onPostExecute方法,将在doInBackground得到的结果来处理操作UI。doInBackground任务执行的结果作为此方法的参数返回。

下面同样以聚合数据空气质量城市空气PM2.5指数数据接口为例来演示AsyncTask的使用。

实例:AsyncTaskDemo
运行效果:
Android AsyncTask异步任务_第1张图片

代码清单:
布局文件:activity_main.xml
<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" >

    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:text="城市:"
            android:textSize="23sp" />

        <EditText 
            android:id="@+id/city"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:inputType="text" />
    </LinearLayout>

    <Button
        android:id="@+id/query"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:text="查询" 
        android:textSize="23sp" />
    
    <TextView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Java源代码文件:MainActivity.java
package com.rainsong.asynctaskdemo;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
    EditText et_city;
    Button btn_query;
    TextView tv_result;
    QueryTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        et_city = (EditText)findViewById(R.id.city);
        tv_result = (TextView)findViewById(R.id.result);
        btn_query = (Button)findViewById(R.id.query);

        btn_query.setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                String city = et_city.getText().toString();
                if (city.length() < 1) {
                    Toast.makeText(MainActivity.this, "请输入城市名",
                            Toast.LENGTH_LONG).show();
                    return;
                }
                task = new QueryTask(MainActivity.this, tv_result);
                task.execute(city);
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

Java源代码文件:QueryTask.java
package com.rainsong.asynctaskdemo;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import android.content.Context;
import android.os.AsyncTask;
import android.widget.TextView;
import android.widget.Toast;

public class QueryTask extends AsyncTask<String, Void, String> {
    Context context;
    TextView tv_result;

    private static final String JUHE_URL_ENVIRONMENT_AIR_PM = 
                                    "http://web.juhe.cn:8080/environment/air/pm";
    private static final String JUHE_APPKEY = "你申请的APPKEY值";

    public QueryTask(Context context, TextView tv_result) {
        // TODO Auto-generated constructor stub
        super();
        this.context = context;
        this.tv_result = tv_result; 
    }

    @Override
    protected String doInBackground(String... params) {
        String city = params[0];

        ArrayList<NameValuePair> headerList = new ArrayList<NameValuePair>();
        headerList.add(new BasicNameValuePair("Content-Type", "text/html; charset=utf-8"));

        String targetUrl = JUHE_URL_ENVIRONMENT_AIR_PM;

        ArrayList<NameValuePair> paramList = new ArrayList<NameValuePair>();
        paramList.add(new BasicNameValuePair("key", JUHE_APPKEY));
        paramList.add(new BasicNameValuePair("dtype", "json"));
        paramList.add(new BasicNameValuePair("city", city));

        for (int i = 0; i < paramList.size(); i++) {
            NameValuePair nowPair = paramList.get(i);
            String value = nowPair.getValue();
            try {
                value = URLEncoder.encode(value, "UTF-8");
            } catch (Exception e) {
            }
            if (i == 0) {
                targetUrl += ("?" + nowPair.getName() + "=" + value);
            } else {
                targetUrl += ("&" + nowPair.getName() + "=" + value);
            }
        }

        HttpGet httpRequest = new HttpGet(targetUrl);
        try {
            for (int i = 0; i < headerList.size(); i++) {
                httpRequest.addHeader(headerList.get(i).getName(),
                                        headerList.get(i).getValue());
            }

            HttpClient httpClient = new DefaultHttpClient();

            HttpResponse httpResponse = httpClient.execute(httpRequest);
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                String strResult = EntityUtils.toString(httpResponse.getEntity());
                return strResult;
            } else {
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override  
    protected void onPostExecute(String result) {
        if (result != null) {
            tv_result.setText(result);
        } else {
            Toast.makeText(context, "查询失败",
                                    Toast.LENGTH_LONG).show();
            tv_result.setText("");
        }
    }  
  
}


API知识点
public abstract class
AsyncTask
extends Object

android.os.AsyncTask<Params, Progress, Result>

Class Overview
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.

Public Constructors
AsyncTask()
Creates a new asynchronous task.

static void execute(Runnable runnable)
Convenience version of execute(Object) for use with a simple Runnable object.

abstract Result doInBackground(Params... params)
Override this method to perform a computation on a background thread.

void onCancelled(Result result)
Runs on the UI thread after cancel(boolean) is invoked and doInBackground(Object[]) has finished.

void onCancelled()
Applications should preferably override onCancelled(Object).

void onPostExecute(Result result)
Runs on the UI thread after doInBackground(Params...).

void onPreExecute()
Runs on the UI thread before doInBackground(Params...).

void onProgressUpdate(Progress... values)
Runs on the UI thread after publishProgress(Progress...) is invoked.

final void publishProgress(Progress... values)
This method can be invoked from doInBackground(Params...) to publish updates on the UI thread while the background computation is still running.

你可能感兴趣的:(android,异步,AsyncTask)