在Android應用程序中,當咱們須要與可能須要時間的外部資源(例如從外部API或數據庫獲取數據)進行交互時,咱們但願主UI保持交互並阻止UI線程在長時間運行的進程中運行很活躍。 另請注意,默認狀況下,不容許在Android的UI線程中運行網絡任務。 若是主線程用 在Android應用程序中,當咱們須要與可能須要時間的外部資源(例如從外部API或數據庫獲取數據)進行交互時,咱們但願主UI保持交互並阻止UI線程在長時間運行的進程中運行很活躍。另請注意,默認狀況下,不容許在Android的UI線程中運行網絡任務。java
若是主線程用於獲取外部數據,則在獲取數據時主UI將不會保持交互,而且若是數據獲取過程遇到異常,則可能顯示異常行爲。在這種狀況下,android的異步任務變得很方便,尤爲是使用後臺線程更新UI的一部分。android
異步任務是將主線程的工做卸載到某個後臺線程的幾種方法之一。雖然AsyncTask不是惟一的選擇,但這是一個簡單並且很是常見的選擇。git
在開始以前,我想訪問谷歌的開發者頁面包含的信息AsyncTask在https://developer.android.com/reference/android/os/AsyncTask審議有關實施一些內容AsyncTask秒。github
這個AsyncTask班是一個abstract班級。實現一般是在UI線程上運行的類的子類。(AsyncTask即子類)的實現將覆蓋至少一種方法,一般是兩種方法。數據庫
執行異步任務時,任務將執行4個步驟,如Android開發人員頁面中所述,網址爲https://developer.android.com/reference/android/os/AsyncTask:bash
onPreExecute,在執行任務以前在UI線程上調用。此步驟用於設置任務,例如經過在用戶界面中顯示微調器。 doInBackground(Params...,在完成執行後當即在後臺線程上調用。此步驟用於執行可能須要很長時間的後臺計算。異步任務的參數將傳遞給此步驟。計算結果必須由此步驟返回,並將傳遞迴最後一步。此步驟還可用於發佈一個或多個進度單位。這些值發佈在UI線程中steponProgressUpdate(Progress...) onProgressUpdate(Progress...,在調用publishProgress(Progress...步驟後在UI線程上調用。執行的時間是不肯定的。此方法用於在後臺計算仍在執行時顯示用戶界面中的任何形式的進度。例如,它可用於爲進度條設置動畫或在文本字段中顯示日誌。 onPostExecute(Result),在後臺計算完成後在UI線程上調用。背景計算的結果做爲參數傳遞給該步驟。 我將經過代碼來講明工做機制。代碼來自我爲Udacity的Android納米學位課程所作的頂點項目。完整代碼可在https://github.com/benktesh/Capstone-Project得到。在本演示中,我使用代碼塊中顯示的輕量級代碼,以下所示:網絡
package benktesh.smartstock;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import java.util.ArrayList;
import benktesh.smartstock.Model.Stock;
import benktesh.smartstock.UI.CommonUIHelper;
import benktesh.smartstock.UI.StockDetailActivity;
import benktesh.smartstock.Utils.MarketAdapter;
import benktesh.smartstock.Utils.NetworkUtilities;
import benktesh.smartstock.Utils.PortfolioAdapter;
import benktesh.smartstock.Utils.SmartStockConstant;
public class MainActivity extends AppCompatActivity implements
MarketAdapter.ListItemClickListener, PortfolioAdapter.ListItemClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
CommonUIHelper mCommonUIHelper;
ArrayList<Stock> mMarketData;
private Toast mToast;
//The following are for market summary
private MarketAdapter mAdapter;
private RecyclerView mMarketRV;
private ProgressBar spinner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
spinner = findViewById(R.id.progressbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent Email = new Intent(Intent.ACTION_SEND);
Email.setType(getString(R.string.label_emailtype));
Email.putExtra(Intent.EXTRA_EMAIL,
new String[]{getString
(R.string.label_developer_contat_email)}); //developer 's email Email.putExtra(Intent.EXTRA_SUBJECT, R.string.label_feedback_subject); // Email 's Subject
Email.putExtra(Intent.EXTRA_TEXT,
getString(R.string.label_address_developer) + ""); //Email 's Greeting text startActivity(Intent.createChooser(Email, getString(R.string.label_send_feedback))); } }); if (mCommonUIHelper == null) { mCommonUIHelper = new CommonUIHelper(this); } mMarketRV = findViewById(R.id.rv_market_summary); LinearLayoutManager layoutManager = new LinearLayoutManager(this); mMarketRV.setLayoutManager(layoutManager); mMarketRV.setHasFixedSize(true); mAdapter = new MarketAdapter(mMarketData, this); mMarketRV.setAdapter(mAdapter); LoadView(); } private void LoadView() { Log.d(TAG, "Getting Market Data Async"); new NetworkQueryTask().execute(SmartStockConstant.QueryMarket); } private void MakeToast(String msg) { Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show(); } public boolean onCreateOptionsMenu(Menu menu) { return mCommonUIHelper.ConfigureSearchFromMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. if (mCommonUIHelper.MakeMenu(item)) return true; return super.onOptionsItemSelected(item); } @Override public void onListItemClick(Stock data) { if (mToast != null) { mToast.cancel(); } Intent intent = new Intent(this.getApplicationContext(), StockDetailActivity.class); intent.putExtra(SmartStockConstant.ParcelableStock, data); Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(this).toBundle(); startActivity(intent, bundle); } /* This is an async task that fetches data from network and new data is applied to adapter. Also makes a long toast message when fails to retrieve information from the network It takes void, void and returns ArrayList<?> */ class NetworkQueryTask extends AsyncTask<String, Integer, ArrayList<Stock>> { private String query; @Override protected void onPreExecute() { if (spinner != null) { spinner.setVisibility(View.VISIBLE); } } @Override protected ArrayList<Stock> doInBackground(String... params) { query = params[0]; ArrayList<Stock> searchResults = null; try { searchResults = NetworkUtilities.getStockData(getApplicationContext(), query); for (int i = 0; i <= 100; i = i + 25) { Thread.sleep(500); publishProgress(i); } } catch (Exception e) { Log.e(TAG, e.toString()); } return searchResults; } @Override protected void onProgressUpdate(Integer... progress) { super.onProgressUpdate(progress); Toast.makeText(getApplicationContext(), "Progress: " + progress[0] + "(%)", Toast.LENGTH_SHORT).show(); } @Override protected void onPostExecute(ArrayList<Stock> searchResults) { super.onPostExecute(searchResults); if (searchResults != null && searchResults.size() != 0) { mAdapter.resetData(searchResults); } if (spinner.getVisibility() == View.VISIBLE) { spinner.setVisibility(View.GONE); } } } } 複製代碼
NetworkQueryTask 做爲子類實現的類MainActivity和子類擴展了Android的AsyncTask abstract類。子類能夠定義以下:app
private class NetworkQueryTask extends AsyncTask<T1, T2, T3> {...}
複製代碼
的T1,T2和T3是參數的數據類型和他們每一個人都有一些特定的含義。異步
上面定義的任務能夠執行以下:async
new NetworkAsyncTask().execute(param1);
複製代碼
它param1的類型與T1。的類型相同。
將MainActivity在UI線程運行。' onCreate(..)'方法確實設置了UI。設置涉及爲回收器視圖等建立適配器,最後調用a LoadView()。在LoadView()方法執行AsyncTask從網絡獲取數據和更新視圖的適配器。
在這樣作的過程當中,咱們建立了一個NetworkQueryTask從中擴展的子類AsyncTask。該類有三個參數string,Void 和ArrayList。股票是一個存儲信息的簡單類Stock。一旦進程開始,咱們但願咱們能夠在doInBackground(..)方法中看到微調器。
在上面的任務中,這三個參數表示用於的輸入參數的類型doInBackground(T1 param1),onProgressUpdate(T2 param2) 和onPostExecute(T3 param3)。當doInBackground步驟完成執行時,param3將是doInBackground步驟的輸出,並將成爲該onPostExecute(param3)方法的輸入。
子類一般至少覆蓋一種方法,最多見的是doInBackground(..)方法,也包括第二種方法,即onPostExecute()。該onProgressUpdate 和onPreExecute()方法是可選的,能夠跳過。所以,若是沒有關於進度更新的任何事情,那麼就不須要覆蓋onProgressUpdate ,而後param2 能夠Void 在類定義自己中使用類型。例如,假設須要將string參數傳遞給doInBackground()而不須要onProgressUpdate()方法,而且該onPostExecute()方法接受一個string參數,那麼類定義將以下所示:
private class NetworkQueryTask extends AsyncTask<String, Void, String> {...}
複製代碼
所以,咱們能夠說這三個參數分別表明輸入doInBackground,輸入onProgressUpdate()和輸入onPostExecute。輸出的參數類型doInBackground與輸入相同onPostExectute()。此外,若是async任務是做爲火災而忘記諸如觸發某事,那麼全部參數均可以void。例如,在這種狀況下,子類的定義以下所示:
private class NetworkQueryTask extends AsyncTask<Void, Void, Void> {...}
複製代碼
上面的類執行以下:
new NetworkAsyncTask().execute();
複製代碼
AsyncTasks不知道應用程序中的其餘活動,所以必須在銷燬活動時正確處理。所以,AsycnTask不適合長時間運行的操做,由於若是應用程序在後臺運行,當Android的終止調用該應用程序AsyncTask時,AsyncTask不被打死,咱們必須管理的如何處理的結果作處理AsyncTask。所以,AsyncTasks在獲取不長時間運行的數據時頗有用。還有其餘替代AyscTask它們IntentServices,Loader和JobScheduler許多基於Java的實現。