你的位置:首页 > 操作系统

[操作系统]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     @Override114     protected void onPostExecute(List<Book> result) {115       showResult(result);116       progressDialog.cancel();117     }118   }119 120   @Override121   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 network134   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 inputs146     connection.setDoOutput(true); // allow outputs147     connection.setUseCaches(false); // do not use a cached copy148     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       @Override190       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     @Override210     public int getCount() {211       return bookList.size();212     }213 214     @Override215     public Object getItem(int position) {216       return bookList.get(position);217     }218 219     @Override220     public long getItemId(int position) {221       return bookList.get(position).getId();222     }223 224     @Override225     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) convertView231           .findViewById(R.id.tvBookTitle);232       TextView tvBookDetail = (TextView) convertView233           .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       tvBookDetail240           .setVisibility(bookDetailExpanded[position] ? View.VISIBLE241               : 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   @Override259   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 }