AndroidプロセスずスレッドAsyncTaskを正しく蚘述する

Androidに぀いおの話を続けたす。 そしお今回は、プロセスずスレッドに関する貎重な情報を共有したいず思いたす。これらの情報は、アプリケヌションを蚘述する際の゚ラヌや誀解を避けるために、よく理解され、垞に手元にある必芁がありたす。 蚘事の最埌に、ボタンをクリックするだけで画像をImageViewにロヌドするAsyncTaskの実装䟋を瀺したす。



たず、このガむドのこのトピックに぀いお詳しくお読みいただけたす-developer.android.com/guide/topics/fundamentals/processes-and-threads.html



Androidのプロセスずスレッドに関する泚意



アプリケヌションコンポヌネントが起動し、アプリケヌションで他のコンポヌネントが実行されおいない堎合、Androidは単䞀の実行スレッドでアプリケヌションの新しいプロセスを䜜成したす。 デフォルトでは、1぀のアプリケヌションのすべおのコンポヌネントは、「メむン」ず呌ばれるスレッドの1぀のプロセスで起動されたす。 アプリケヌションコンポヌネントが起動され、特定のアプリケヌションのプロセスが既に存圚する堎合アプリケヌションの䞀郚のコンポヌネントが存圚する堎合、コンポヌネントはこのプロセスで起動され、その実行フロヌを䜿甚したす。 アプリケヌションのコンポヌネントごずに異なるプロセスを蚭定するこずにより、この動䜜を倉曎できたす。 さらに、任意のプロセスにスレッドを远加できたす。



マニフェストファむルを䜿甚しお、コンポヌネントの個別のプロセスを定矩できたす。 各コンポヌネントタグアクティビティ、サヌビス、レシヌバヌ、プロバむダヌは、androidprocess属性をサポヌトしたす。 この属性を䜿甚するず、コンポヌネントを実行するプロセスを指定できたす。 異なるアプリケヌションのコンポヌネントが実行されるプロセスを指定するこずもできたす。 この属性は、すべおのアプリケヌションコンポヌネントに特定のプロセスを指定できるようにするアプリケヌションタグでもサポヌトされおいたす。



Androidは、可胜な限りアプリケヌションプロセスをサポヌトしようずしたすが、リ゜ヌスが必芁な堎合は、重芁な階局に埓っお叀いプロセスが眮き換えられたす。



重芁床の階局には5぀のレベルがありたすリストの最初のレベルのプロセスは最埌に削陀されたす



1.ナヌザヌが察話するプロセスフォアグラりンドプロセス

そのようなプロセスには、たずえば、次のものが含たれたす。 ナヌザヌが察話するサヌビスサヌビスむンスタンス。 startForegroundメ゜ッドによっお起動されたサヌビス。 ラむフサむクルのいずれかの方法を実行するサヌビス。 onReceiveメ゜ッドを実行するBroadcastReceiver。



2.目に芋えるプロセス

パラグラフ1の条件が満たされおいないが、ナヌザヌが画面に衚瀺するものに圱響するプロセス。 たずえば、アクティベヌションのonPauseメ゜ッドが呌び出されたす。



3.サヌビスプロセス

startServiceによっお開始されたサヌビス



4.バックグラりンドプロセス

バックグラりンドで実行され、ナヌザヌには芋えないプロセス。



5.空のプロセス



アプリケヌションコンポヌネントにはonLowMemoryメ゜ッドが存圚したすが、onDestroyメ゜ッドに100䟝存できないのず同様に、このメ゜ッドの呌び出しに䟝存するこずはできないので、デヌタや蚭定を保存するロゞックをメ゜ッドに実装できたすonStop、これは圌らが保蚌する正確に呌び出されたす。



アプリケヌションが起動するず、システムはこのアプリケヌションの実行の「メむン」スレッドを䜜成したす。これはUIスレッドずも呌ばれたす。 このストリヌムは、りィゞェットボタン、リストが描画され、アプリケヌションのむベントが凊理されるため、非垞に重芁です。 システムは、コンポヌネントのむンスタンスごずに個別のスレッドを䜜成したせん。 1぀のプロセスで実行されおいるすべおのコンポヌネントは、UIスレッドで䜜成されたす。 Androidナヌザヌむンタヌフェむスラむブラリはスレッドセヌフではないため、次の2぀の重芁なルヌルがありたす。



1UIスレッドをブロックしない

2非UIスレッドからUIコンポヌネントにアクセスしないでください



ここで、ネットワヌクからImageViewに画像をアップロヌドしおすぐに衚瀺するずいうタスクがあったずしたす。 どうする 論理的には、次のような、すべおの䜜業を実行する別のスレッドを䜜成したす。

public void onClick(View v) { new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork("http://example.com/image.png"); mImageView.setImageBitmap(b); } }).start(); }
      
      





画像をロヌドする操䜜を別のストリヌムに移動したため、信じられないように芋えたす。 問題は、ルヌル番号2に違反したこずです。 次の方法を䜿甚しお、この問題を修正できたす。



Activity.runOnUiThread実行可胜

View.post実行可胜

View.postDelayed実行可胜、長い



たずえば、最初のものを䜿甚したす。

 public void onClick(View v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bitmap); } }); } }).start(); }
      
      





珟圚、実装はスレッドセヌフです。ネットワヌク操䜜は別のスレッドで実行され、ImageViewはUIストリヌムからアクセスされたす。

幞いなこずに、これらの操䜜はHandlerクラスの継承を䜿甚しお必芁なロゞックを実装するこずで組み合わせるこずができたすが、最善の解決策はAsyncTaskクラスを継承するこずです。



AsyncTaskを䜿甚するず、非同期䜜業を実行し、ナヌザヌむンタヌフェむスを曎新できたす。

アップグレヌドするには、onPostExecuteメ゜ッドを実装し、すべおのバックグラりンド䜜業をdoInBackgroundメ゜ッドで囲みたす。 独自のタスクを実装したら、executeメ゜ッドで実行する必芁がありたす。



画像の読み蟌みず衚瀺のタスクを実装する、玄束されたAsyncTaskの䟋を玹介したす泚釈付きのオプションず暙準ダむアログプロトコルの䜿甚からの逞脱。

 @EActivity(R.layout.main) public class DownloadImageActivity extends Activity { ProgressDialog progress; @ViewById ImageView image; @ViewById Button runButt; String pictUrl = "http://www.bigfoto.com/sites/main/churfirsten_switzerland-xxx.JPG"; @BeforeCreate void getProgressDialog(){ progress = new ProgressDialog(this); progress.setMessage("Loading..."); } @Click(R.id.runButt) void runClick(){ new DownloadImageTask().execute(pictUrl); } class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { @Override protected Bitmap doInBackground(String... params) { publishProgress(new Void[]{}); //or null String url = ""; if( params.length > 0 ){ url = params[0]; } InputStream input = null; try { URL urlConn = new URL(url); input = urlConn.openStream(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return BitmapFactory.decodeStream(input); } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); progress.show(); } @Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); progress.dismiss(); image.setImageBitmap(result); } } }
      
      







次に、ダむアログの操䜜の芳点から最も正しいオプションを怜蚎したす。

 public class DownloadImageActivity extends Activity { ImageView image; Button runButt; final static String PICT_URL = "http://www.bigfoto.com/sites/main/churfirsten_switzerland-xxx.JPG"; final int PROGRESS_DLG_ID = 666; final static String DEBUG_TAG = "+++ImageDownloader+++"; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); loadViews(); } private void loadViews(){ runButt = (Button)findViewById(R.id.runButt); image =(ImageView)findViewById(R.id.image); } @Override protected Dialog onCreateDialog(int dialogId){ ProgressDialog progress = null; switch (dialogId) { case PROGRESS_DLG_ID: progress = new ProgressDialog(this); progress.setMessage("Loading..."); break; } return progress; } public void runButtonHandler(View button){ if(button.getId() == R.id.runButt) new DownloadImageTask().execute(PICT_URL); } class DownloadImageTask extends AsyncTask<String, Void, Bitmap> { @Override protected Bitmap doInBackground(String... params) { publishProgress(new Void[]{}); String url = ""; if( params.length > 0 ){ url = params[0]; } InputStream input = null; try { URL urlConn = new URL(url); input = urlConn.openStream(); } catch (MalformedURLException e) { Log.d(DEBUG_TAG,"Oops, Something wrong with URL..."); e.printStackTrace(); } catch (IOException e) { Log.d(DEBUG_TAG,"Oops, Something wrong with inpur stream..."); e.printStackTrace(); } return BitmapFactory.decodeStream(input); } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); showDialog(PROGRESS_DLG_ID); } @Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); dismissDialog(PROGRESS_DLG_ID); image.setImageBitmap(result); } } }
      
      





より倚くのコヌドがありたすが、ダむアログの操䜜には暙準プロトコルを䜿甚するこずをお勧めしたす。

たた、初心者がこのコヌドを簡単に詊せるように、すべおの泚釈を削陀したした。



指定した倀を持぀属性をボタンレむアりトに远加するこずを忘れないでくださいandroidonClick = "runButtonHandler"



さらに、公匏ドキュメント Tyts および私の堎合、preExecuteは䜿甚されたせんが、タスクを開始する前にナヌザヌむンタヌフェむスでいく぀かのアクションを実行する必芁がある堎合は、このメ゜ッドを䜿甚しおください。



AsyncTaskに枡されるパラメヌタヌ

1.パラメヌタヌこの堎合、URL。

2.進行状況タスク倉曎の進行状況を指定する単䜍。 私たちの堎合、それは䜿甚されたせん。

3.タスクの結果この堎合、ビットマップオブゞェクト



コヌドは非垞に簡単です。すべおのバックグラりンド䜜業をdoInBackGroundメ゜ッドで行い、publishProgressメ゜ッドを呌び出したす。これにより、onProgressUpdateメ゜ッドが呌び出されたずきに画像がロヌドされるずProgressDialogがスピンしたす。 バックグラりンドの䜜業が完了した埌、onPostExecuteメ゜ッドが呌び出され、doInBackGroundメ゜ッドの結果が転送されたす。この堎合、これはBitmapオブゞェクトであり、そこでImageViewにロヌドしたす。

考慮すべきいく぀かの重芁な点に泚意しおください。



1doInBackGroundメ゜ッドはバックグラりンドスレッドで実行されるため、このメ゜ッド内ではUIストリヌムにアクセスできたせん。

2onPostExecuteおよびonProgressUpdateメ゜ッドはUIスレッドで実行されるため、UIコンポヌネントに安党にアクセスできたす。



おわりに



はい、android-annotationsラむブラリを再床適甚したので、アノテヌションに驚かないでください。



アプリケヌション開発の間違いを防ぐために、Androidのプロセスモデルを理解するこずが重芁です。



この蚘事は、このタスクの実装ずストリヌムの操䜜における利甚可胜な情報ず個人的な経隓の凊理です。



い぀ものように、PMの蚘事の内容に぀いおの垌望ずコメント。 远加たたは補足するものがある堎合は、コメントに自由に蚘入しおください。



UPDこの蚘事は、ダむアログの操䜜に関しおより正確なバヌゞョンを远加するこずにより曎新されたす。



All Articles