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 }
原标题:Android AsyncTask 详解及注意事项
关键词:Android