Android AsyncTask 详解及注意事项

AsyncTask是Android提供的轻量级的异步类,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。

AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress 后台任务执行的百分比。
  • Result 后台执行任务最终返回的结果,比如String。
例如:
class RetrieveCategoryTask extends AsyncTask<String, Void, List<String>>

根据AsyncTask源码:

public abstract class AsyncTask<Params, Progress, Result> 

这里的String, Void, List<String>分别对应Params, Progress, Result


一般使用AsyncTask至少需要实现以下2个方法:
protected abstract Result doInBackground(Params... var1);//耗时操作,例如网络请求任务。这里相当于一个子线程
   protected void onPostExecute(Result result) {//可以在这里处理doInBackground得到的数据,能够对UI进行操作,属于UI主线程
        throw new RuntimeException("Stub!");
    }

当然如果有必要的话还可以实现下面几个方法:

  • onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
  • onPreExecute()        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • onCancelled()             用户调用取消时,会调用此方法

使用AsyncTask类,以下是几条必须遵守的准则:

  • Task的实例必须在UI thread中创建;
  • execute方法必须在UI thread中调用;
  • 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
  • 该task只能被执行一次,否则多次调用时将会出现异常;

需要注意的是Android为了安全考虑,不允许在主线程即UI线程进行耗时操作。例如HTTP请求等。

如果在UI中使用了耗时操作的话,Android Studio本身是不会报错的。只有在APP执行到相应的耗时操作位置时才会停止运行。手机或模拟器上会出现“很抱歉,XXX已停止运行”同时Android Studio logcat输出“

E/AndroidRuntime: FATAL EXCEPTION: main
Process:.....

java.lang.RuntimeException.....

下面给出一个范例:

  1 package idv.ron.texttojson_android;
  2
  3 import android.app.ProgressDialog;
  4 import android.content.Context;
  5 import android.net.ConnectivityManager;
  6 import android.net.NetworkInfo;
  7 import android.os.AsyncTask;
  8 import android.os.Bundle;
  9 import android.support.v7.app.ActionBarActivity;
 10 import android.util.Log;
 11 import android.view.LayoutInflater;
 12 import android.view.View;
 13 import android.view.ViewGroup;
 14 import android.widget.AdapterView;
 15 import android.widget.AdapterView.OnItemClickListener;
 16 import android.widget.ArrayAdapter;
 17 import android.widget.BaseAdapter;
 18 import android.widget.ListView;
 19 import android.widget.Spinner;
 20 import android.widget.TextView;
 21 import android.widget.Toast;
 22
 23 import com.google.gson.Gson;
 24 import com.google.gson.JsonObject;
 25 import com.google.gson.reflect.TypeToken;
 26
 27 import java.io.BufferedReader;
 28 import java.io.BufferedWriter;
 29 import java.io.IOException;
 30 import java.io.InputStreamReader;
 31 import java.io.OutputStreamWriter;
 32 import java.lang.reflect.Type;
 33 import java.net.HttpURLConnection;
 34 import java.net.URL;
 35 import java.util.List;
 36
 37 public class SearchActivity extends ActionBarActivity {
 38     private final static String TAG = "SearchActivity";
 39     private ProgressDialog progressDialog;
 40     private AsyncTask retrieveCategoryTask, retrieveBookTask;
 41     private Spinner spCategory;
 42     private ListView lvBook;
 43
 44     class RetrieveCategoryTask extends AsyncTask<String, Void, List<String>> {
 45         @Override
 46         protected void onPreExecute() {
 47             super.onPreExecute();
 48             progressDialog = new ProgressDialog(SearchActivity.this);
 49             progressDialog.setMessage("Loading...");
 50             progressDialog.show();
 51         }
 52
 53         @Override
 54         protected List<String> doInBackground(String... params) {
 55             String url = params[0];
 56             String jsonIn;
 57             JsonObject jsonObject = new JsonObject();
 58             jsonObject.addProperty("param", "category");
 59             try {
 60                 jsonIn = getRemoteData(url, jsonObject.toString());
 61             } catch (IOException e) {
 62                 Log.e(TAG, e.toString());
 63                 return null;
 64             }
 65
 66             Gson gson = new Gson();
 67             Type listType = new TypeToken<List<String>>() {
 68             }.getType();
 69
 70             return gson.fromJson(jsonIn, listType);
 71         }
 72
 73         @Override
 74         protected void onPostExecute(List<String> items) {
 75             ArrayAdapter<String> adapter = new ArrayAdapter<>(SearchActivity.this,
 76                     android.R.layout.simple_list_item_1, items);
 77             adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
 78             spCategory.setAdapter(adapter);
 79             progressDialog.cancel();
 80         }
 81     }
 82
 83     public class RetrieveBookTask extends
 84             AsyncTask<String, Integer, List<Book>> {
 85         @Override
 86         protected void onPreExecute() {
 87             super.onPreExecute();
 88             progressDialog = new ProgressDialog(SearchActivity.this);
 89             progressDialog.setMessage("Loading...");
 90             progressDialog.show();
 91         }
 92
 93         @Override
 94         protected List<Book> doInBackground(String... params) {
 95             String url = params[0];
 96             String category = params[1];
 97             String jsonIn;
 98             JsonObject jsonObject = new JsonObject();
 99             jsonObject.addProperty("param", category);
100             try {
101                 jsonIn = getRemoteData(url, jsonObject.toString());
102             } catch (IOException e) {
103                 Log.e(TAG, e.toString());
104                 return null;
105             }
106
107             Gson gson = new Gson();
108             Type listType = new TypeToken<List<Book>>() {
109             }.getType();
110             return gson.fromJson(jsonIn, listType);
111         }
112
113         @Override
114         protected void onPostExecute(List<Book> result) {
115             showResult(result);
116             progressDialog.cancel();
117         }
118     }
119
120     @Override
121     protected void onCreate(Bundle savedInstanceState) {
122         super.onCreate(savedInstanceState);
123         setContentView(R.layout.search_activity);
124         spCategory = (Spinner) findViewById(R.id.spCategory);
125         lvBook = (ListView) findViewById(R.id.lvBook);
126         if (networkConnected()) {
127             retrieveCategoryTask = new RetrieveCategoryTask().execute(Common.URL);
128         } else {
129             showToast(this, R.string.msg_NoNetwork);
130         }
131     }
132
133     // check if the device connect to the network
134     private boolean networkConnected() {
135         ConnectivityManager conManager =
136                 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
137         NetworkInfo networkInfo = conManager.getActiveNetworkInfo();
138         return networkInfo != null && networkInfo.isConnected();
139     }
140
141
142     private String getRemoteData(String url, String jsonOut) throws IOException {
143         StringBuilder jsonIn = new StringBuilder();
144         HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
145         connection.setDoInput(true); // allow inputs
146         connection.setDoOutput(true); // allow outputs
147         connection.setUseCaches(false); // do not use a cached copy
148         connection.setRequestMethod("POST");
149         connection.setRequestProperty("charset", "UTF-8");
150         BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
151         bw.write(jsonOut);
152         Log.d(TAG, "jsonOut: " + jsonOut);
153         bw.close();
154
155         int responseCode = connection.getResponseCode();
156
157         if (responseCode == 200) {
158             BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
159             String line;
160             while ((line = br.readLine()) != null) {
161                 jsonIn.append(line);
162             }
163         } else {
164             Log.d(TAG, "response code: " + responseCode);
165         }
166         connection.disconnect();
167         Log.d(TAG, "jsonIn: " + jsonIn);
168         return jsonIn.toString();
169     }
170
171     public void onSearchClick(View v) {
172         Object item = spCategory.getSelectedItem();
173         if (item == null || item.toString().trim().length() <= 0) {
174             showToast(this, R.string.msg_NoCategoryFound);
175         } else {
176             String category = item.toString().trim();
177             if (networkConnected()) {
178                 retrieveBookTask = new RetrieveBookTask().execute(Common.URL, category);
179             } else {
180                 showToast(this, R.string.msg_NoNetwork);
181             }
182         }
183     }
184
185     public void showResult(List<Book> result) {
186         final BookListAdapter adapter = new BookListAdapter(this, result);
187         lvBook.setAdapter(adapter);
188         lvBook.setOnItemClickListener(new OnItemClickListener() {
189             @Override
190             public void onItemClick(AdapterView<?> parent, View view,
191                                     int position, long id) {
192                 adapter.expand(position);
193                 lvBook.setItemChecked(position, true);
194             }
195         });
196     }
197
198     private class BookListAdapter extends BaseAdapter {
199         private LayoutInflater layoutInflater;
200         private List<Book> bookList;
201         private boolean[] bookDetailExpanded;
202
203         public BookListAdapter(Context context, List<Book> bookList) {
204             this.layoutInflater = LayoutInflater.from(context);
205             this.bookList = bookList;
206             this.bookDetailExpanded = new boolean[bookList.size()];
207         }
208
209         @Override
210         public int getCount() {
211             return bookList.size();
212         }
213
214         @Override
215         public Object getItem(int position) {
216             return bookList.get(position);
217         }
218
219         @Override
220         public long getItemId(int position) {
221             return bookList.get(position).getId();
222         }
223
224         @Override
225         public View getView(int position, View convertView, ViewGroup parent) {
226             if (convertView == null) {
227                 convertView = layoutInflater.inflate(
228                         R.layout.book_listview_item, parent, false);
229             }
230             TextView tvBookTitle = (TextView) convertView
231                     .findViewById(R.id.tvBookTitle);
232             TextView tvBookDetail = (TextView) convertView
233                     .findViewById(R.id.tvBookDetail);
234             Book book = bookList.get(position);
235
236             tvBookTitle.setText(book.getName() + "  $" + book.getPrice());
237             tvBookDetail.setText("Author: " + book.getAuthor() + "  Type: "
238                     + book.getType());
239             tvBookDetail
240                     .setVisibility(bookDetailExpanded[position] ? View.VISIBLE
241                             : View.GONE);
242             return convertView;
243         }
244
245         public void expand(int position) {
246             // 被點擊的資料列才會彈出內容,其他資料列的內容會自動縮起來
247             // for (int i=0; i<newsExpanded.length; i++) {
248             // newsExpanded[i] = false;
249             // }
250             // newsExpanded[position] = true;
251
252             bookDetailExpanded[position] = !bookDetailExpanded[position];
253             notifyDataSetChanged();
254         }
255
256     }
257
258     @Override
259     protected void onPause() {
260         if (retrieveCategoryTask != null) {
261             retrieveCategoryTask.cancel(true);
262             retrieveCategoryTask = null;
263         }
264
265         if (retrieveBookTask != null) {
266             retrieveBookTask.cancel(true);
267             retrieveBookTask = null;
268         }
269
270         super.onPause();
271     }
272
273     private void showToast(Context context, int messageId) {
274         Toast.makeText(context, messageId, Toast.LENGTH_SHORT).show();
275     }
276 }
时间: 2024-08-08 15:55:27

Android AsyncTask 详解及注意事项的相关文章

Android AsyncTask详解

(写在前面:文章是看了慕课上的教程之后写的,感谢http://www.imooc.com/learn/377) 一.AsyncTask基本结构介绍 首先,顾名思义,AsyncTask是异步任务. 为什么要异步任务? 因为只有UI线程,即主线程可以对控件进行更新操作.好处是保证UI稳定性,避免多线程对UI同时操作. 同时要把耗时任务放在非主线程中执行,否则会造成阻塞,抛出无响应异常. AsyncTask是安卓封装好的异步机制.(当然也可以自己写new thread,handler) AsyncTa

Android AsyncTask 详解

在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制.关于Handler的相关知识,前面也有所介绍,不清楚的朋友们可以参照一下. 为了简化操作,Android1.5提供了工具类android.os.AsyncTask,它使创建异步任

[gitbook] Android框架分析系列之Android Binder详解

请支持作者原创: https://mr-cao.gitbooks.io/android/content/android-binder.html Android Binder详解 Table of Contents 1. binder简介 2. binder的实现 2.1. IBinder类简介 2.2. IInterface类简介 2.3. BpBinder和BBinder简介 2.4. ProcessState和IPCThreadState简介 2.5. ServiceManager简介 2.

AsyncTask详解

http://blog.csdn.net/liuhe688/article/details/6532519 在Android中实现异步任务机制有两种方式,Handler和AsyncTask. Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制.关于Handler的相关知识,前面也有所介绍,不清楚的朋友们可以参照一

Android Loader详解(官方文档翻译)

装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数据的能力. 它们监视数据源的一将一动并在内容改变时传送新的结果. 当由于配置改变而被重新创建后,它们自动重连到上一个加载器的游标,所以不必重新查询数据. 装载器API概述 在使用装载器时,会涉及很多类和接口们,我们在下表中对它们总结一下: Class/Interface 说明 LoaderManag

android动画详解三 动画API概述

· 属性动画与view动画的不同之处 view动画系统提供了仅动画View 对象的能力,所以如果你想动画非View 对象,你就要自己实现代码. view动画系统实际上还被强制仅能对 View 的少数属性进行动画,比如缩放和旋转,而不能对背景色进行. view动画的另一个坏处是它仅修改View的绘制位置,而不是View的实际位置.例如,如果你动画一个移动穿越屏幕,button的绘制位置是正确的,但实际你可以点击它的位置却没有变,所以你必须去实现你自己的逻辑来处理它. 使用属性动画系统时,这个限制被

android矩阵详解

Matrix,中文里叫矩阵,高等数学里有介绍,在图像处理方面,主要是用于平面的缩放.平移.旋转等操作. 在Android里面,Matrix由9个float值构成,是一个3*3的矩阵.最好记住.如下图: 解释一下,上面的sinX和cosX,表示旋转角度的cos值和sin值,注意,旋转角度是按顺时针方向计算的. translateX和translateY表示x和y的平移量.scale是缩放的比例,1是不变,2是表示缩放1/2,这样子. 在android.graphics.Matrix中有对应旋转的函

Android ProgressBar详解以及自定义

版本:1.0 日期:2014.5.16 版权:© 2014 kince 转载注明出处 这一次主要说一下Android下的进度条,为什么是它呢,因为近期被其各种美轮美奂的设计所倾倒,计划逐渐去实现.另外一个因素也是它也是为数不多的直接继承于View类的控件,从中可以学习到一些自定义控件的知识.下面列举了一些个人觉得还算漂亮的进度条,仅供参考. 是不是很漂亮,其实就像上面图形展示的那样,进度条大体上无非就是这几种形式.这样一来肯定是需要自定义了,所以方向有两个:要么继承于系统的ProgressBar

Android 菜单详解

Android中菜单分为三种,选项菜单(OptionMenu),上下文菜单(ContextMenu),子菜单(SubMenu) 选项菜单 可以通过两种办法增加选项菜单,一是在menu.xml中添加,该种方式参见Android 资源详解(二) 菜单资源,二是在.java中添加 1.覆盖Activity 的 onCreateOptionsMenu(Menu  menu)方法,当我们第一次打开菜单 时该方法被自动调用. 2.调用Menu的 add()方法添加菜单项(Menultem) ,可以调用Men