Androidノート--androidのプロセスとスレッド


この文章は私がdev Guideの中でProcesses and Threadsの翻訳と総括に対して、いくつかの個人的な理解を加えたものです.
 
androidでのプロセス
デフォルトでは、同じアプリケーションのすべてのcomponentが同じlinuxプロセスで実行されます.1つのcomponent Aが起動すると、既に実行中のcomponent Bが存在し、AとBが同じアプリケーションに属する場合、component Aはcomponent Bが存在するプロセスで実行される.そうでない場合、Aに新しいlinuxプロセスが作成されます. 
開発者はアプリケーションのcomponentに対して異なる実行プロセスを指定することもできる.manifest.xmlファイルの,,,ラベルはandroid:processプロパティをサポートしています.このプロパティにより、componentの実行プロセスを指定できます.<アプリケーション>ラベルはandroid:processプロパティの設定もサポートする、アプリケーション下のすべてのcomponentにデフォルトの実行プロセスを指定する.
 
プロセス優先度
システムのメモリが不足するとandroidシステムはプロセスの優先度に基づいて重要でないプロセスを殺すことを選択する.プロセスの優先度は、次のとおりです.
1.フロントプロセス次のプロセスはフロントプロセスです.
a.プロセスには、フロントにあるユーザーと対話しているactivityが含まれている.
b.プロセスにはフロントactivityにバインドされたサービスが含まれている.
c.プロセスにはstartForeground()メソッドを呼び出したサービスが含まれている.
d.プロセスには、onCreate()、onStart()、またはonDestroy()メソッドを実行しているサービスが含まれます.
e.プロセスにはonReceive()メソッドを実行しているBroadcastReceiverが含まれている.
システム中のフロントプロセスの数は少なく、フロントプロセスはほとんど殺されない.すべてのフロントプロセスが同時に実行されることを保証できないほどメモリが低い場合にのみ、フロントプロセスを殺すことを選択します.
2.可視プロセス次のプロセスはビジュアルプロセスです.
a.プロセスにはフロントにいないが依然として見えるactivity(activityを呼び出すonPause()メソッドが含まれているが、onStop()メソッドは呼び出されていない).典型的にはactivityを実行するときにダイアログボックスがポップアップされ、このときのactivityはフロントactivityではないが、依然として表示される.
b.プロセスには可視activityにバインドされたサービスが含まれている.
可視プロセスは、フロントプロセスの実行を保証するためにやむを得ない限り、システムによって殺されることはない.
3.サービスプロセスプロセスには起動したサービスが含まれています.
4.バックグラウンドプロセスプロセスには見えないactivity(onStop()メソッド呼び出し後のactivity)が含まれる.バックグラウンドプロセスはユーザー体験に直接影響しない.フロントプロセス/ビジュアルプロセス/サービスプロセスの運行を保証するために、システムはいつでもバックグラウンドプロセスを殺す可能性がある.ライフサイクル法を正しく実現するactivityはバックグラウンドにあるときにシステムによって殺され、ユーザが再起動するときに回復する前の運転状態を回復することができる.
5.空のプロセスアクティブなプロセスを含まないプロセスは空のプロセスです.システムは常に空のプロセスを殺し、これは何の影響も与えない.空のプロセスが存在する唯一の理由は、次回より速く起動できるように、いくつかの起動データをキャッシュすることである. 
 
プロセス優先度の追加説明
1.システムはプロセスにできるだけ高い優先度を与える.例えば、1つのプロセスに起動するサービスとフロントactivityが含まれている場合、このプロセスはフロントプロセスと見なされる. 
2.コンポーネント間の依存性により、プロセスの優先度が向上する可能性がある.プロセスAがプロセスBにサービスする場合、プロセスAの優先度はプロセスBを下回ることができない.例えば、プロセスAのContentProviderコンポーネントがプロセスBのコンポーネントにサービスしている場合、またはプロセスAのサービスコンポーネントとプロセスBのコンポーネントがバインドされている場合、プロセスAの優先度はいずれもプロセスBを下回ることはない(優先度ルールに従って、プロセスAの優先度がプロセスBより確かに低い場合、システムはプロセスAの優先度をプロセスBと同じにすることを選択する).
3.サービスプロセスの優先度がバックグラウンドプロセスより高いため、activityが時間のかかる操作を実行する必要がある場合は、サービスを起動して完了することが望ましい.もちろん、activityでサブスレッドを起動して時間のかかる操作を完了してもよいが、このような欠点は、activityが見えなくなると、activityが存在するプロセスがバックグラウンドプロセスとなり、メモリが不足するとバックグラウンドプロセスはいつでもシステムによって殺される可能性がある(ただし、サービスを起動して時間のかかる操作を完了すると、UIコントロールの状態をリアルタイムで更新する必要があるなど、データのインタラクションの問題が発生し、サービスは良い選択ではない).同様の考慮により、BroadcastReceiverにおいても時間のかかる操作を行うべきではなく、サービスを起動して完了すべきである(もちろん、BroadcastReceiverのライフサイクルが短すぎて、その中で時間のかかる操作を実行できないことも決定する).
 
androidのスレッド
プロセス内の各コンポーネントに対して新しいスレッドを開始することはなく、プロセス内のすべてのコンポーネントがUIスレッドでインスタンス化される.Androidのマルチスレッドメカニズムについては、私の別のブログhttp://coolxing.iteye.com/blog/1208371を参照してください.
常に覚えておいてください.
1.UIスレッドをブロックするな.UIスレッド内でブロックや時間のかかる操作を行うと、UIスレッドがユーザの要求に応答できなくなる.
2.androidのUIコントロールはスレッドが安全でないため、非UIスレッド(ワークスレッドとも呼ばれる)でUIを更新することはできない.
以上のように、開発者は、ワークスレッドの実行中にUIの状態を更新する必要がある場合には、ワークスレッドに対して時間のかかる操作やブロック操作を完了するように通知することが多い. 
 
スレッド間通信
次のコードを見てください.
public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
            mImageView.setImageBitmap(b);
        }
    }).start();
}

上のコードは間違っていますsetImageBitmap(b)は第2の準則に違反する--作業スレッドでUIを更新できない. 
スレッド間通信は、作業スレッドがUIスレッド更新制御をどのように通知するかという問題を解決することができる.Androidは3つのスレッド間通信のスキームを提供しています.
1.次のメソッドを呼び出します.
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
この3つのメソッドがワークスレッドで呼び出されると、メソッドにおけるRunnableパラメータのカプセル化操作がUIスレッドで実行する.
この方法を使用して、例のエラーを修正します.
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() {
                // run    UI     
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

2.Handlerメカニズム.Handlerメカニズムにより、開発者は、UIスレッドにバインドhandlerオブジェクトのsendMessage()メソッドを呼び出してUIスレッドのメッセージキューにメッセージを送信することができる、UIスレッドは、適切なタイミングでメッセージキューからメッセージを取り出し、処理を完了する.
3.AsyncTaskクラスを使用する.AsyncTaskクラスのサブクラスを作成し、必要に応じてonPreExecute()、doInBackground()、onProgressUpdate()、onPostExecute()メソッドを上書きする.AsyncTaskクラスの具体的な使用方法については、以下のドキュメントを参照してください.
a.AsyncTaskクラスは一つの汎用クラスであり、三つの汎用パラメータが存在する.1番目のパラメータはexecuteメソッドのパラメータタイプを指定する、2番目のパラメータはonProgressUpdate()メソッドのパラメータタイプを指定し、3番目のパラメータはdoInBackground()メソッドの戻り値タイプとonPostExecute()メソッドのパラメータタイプを指定する.
b.実行プロセス:UIスレッドでAsyncTaskクラスのexecuteメソッドを呼び出す(このステップのみがプログラマによって制御される)-->システム呼び出しonPreExecute()このメソッドはUIスレッドで-->システム呼び出しdoInBackground()メソッドを実行し、このメソッドは作業スレッドで実行-->doInBackground()メソッドでpublishProgress()メソッドを呼び出すたびに、UIスレッドでonProgressUpdate()メソッド-->doInBackground()メソッドの実行が完了すると、onPostExecute()メソッドが呼び出され、doInBackground()メソッドの戻り値がonPostExecute()メソッドのパラメータに渡す.onPostExecute()メソッドはUIスレッドで実行する.
このようにして、例の誤りを修正することもできます.
public void onClick(View v) {
    new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    protected Bitmap doInBackground(String... urls) {
        return loadImageFromNetwork(urls[0]);
    }
    
    protected void onPostExecute(Bitmap result) {
        mImageView.setImageBitmap(result);
    }
}