AsyncTask定義了三種泛型類型 Params,Progress和Result。 Params 啟動任務執行的輸入參數,比如HTTP請求的URL。 Progress 後臺任務執行的百分比。 Result 後臺執行任務最終返回的結果,比如String。 Params 啟動任務執行的輸入參數,比如H ...
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 }