Androidのプロセスとスレッド

7620 ワード

Androidシステムは、アプリケーションコンポーネントが起動し、アプリケーションが他のコンポーネントを起動していない場合、アプリケーションの新しいLinuxプロセスを開始するために単一の実行スレッドを使用します.デフォルトでは、同じアプリケーションのすべてのコンポーネントは、同じプロセスとスレッドで実行されます(プライマリ・プロセスと呼ばれます).アプリケーション・コンポーネントが起動し、アプリケーションがすでに存在する場合(他のコンポーネントが存在するため)、コンポーネントはこのプロセスで起動し、同じ実行スレッドを使用します.ただし、他のコンポーネントを別のプロセスに配置し、任意のプロセスに追加のスレッドを作成できます.
プロセス
コンポーネントが属するプロセスを制御する必要がある場合は、インベントリファイルでこの操作を実行します.
各コンポーネント要素はandroid:processプロパティをサポートします.このプロパティは、コンポーネントがどのプロセスで実行されるべきかを指定します.具体的には
  • は、各コンポーネントがそれぞれのプロセスで
  • を実行するようにする.
  • は、一部のコンポーネントにプロセスを共有させるが、他のコンポーネントは
  • を共有しない.
  • は、同じLinuxユーザIDを共有し、同じ証明書を使用して
  • に署名することを前提として、異なるアプリケーションのコンポーネントを同じプロセスで実行する.
    さらに、要素はandroid:processプロパティをサポートし、すべてのコンポーネントに適用されるデフォルト値を設定します.
    メモリが不足し、他のユーザーにより緊急なサービスを提供するプロセスがメモリを必要とする場合、Androidはある時点でプロセスを閉じることを決定する可能性があります.終了したプロセス内のすべてのコンポーネントも破棄されます.これらのコンポーネントを再実行する必要がある場合、システムはプロセスを再起動します.
    どのプロセスを終了するかを決定すると、Androidシステムはユーザーに対する相対的な重要度を考慮します.
    プロセスライフサイクル
    Androidは、プロセスが中国で実行中のコンポーネントやこれらのコンポーネントの状態に応じて、各プロセスを「重要度階層」に入れ、必要に応じて、まず重要度が最も低いプロセスからシステムリソースを順次回収します.
    重要度階層は全部で5級に分けられ、以下に重要度によって各種類のプロセス(第一に最も重要で、最後に終了)をリストした.
    1.フロントプロセス
                。              ,       :
    -          Activity(   Activity onResume()  )
    -     Service,            Activity
    -     “  ”   Service(     startForegound())
    -               Service(onCreate()、onStart() onDestroy())
    -       onReceive()   BroadcastReceiver
    

    2.表示プロセス
            、                  。        ,       :
    -       、        Activity(    onPause()  )
    -        (   )Activity Service
                               。
    

    3.サービスプロセス
            startService()                        。
    

    4.バックグラウンドプロセス
               Activity   (   Activity onStop()  )。
                   ,      LRU(      )   ,
                Activity          。
    

    5.空のプロセス
                  。                ,
                     。
    

    Androidは、プロセスの現在のアクティブなコンポーネントの重要度に応じて、プロセスを最高レベルに評価します.
    さらに、あるプロセスのレベルは、他のプロセスの依存性によって向上する可能性があります.すなわち、別のプロセスにサービスを提供するプロセスのレベルは、サービスを提供するプロセスよりも決して低くありません.
    サービスを実行するプロセスのレベルが管理バックグラウンドのActivityより高いため、長時間の操作を開始するActivityは、単純に作業スレッドを作成するのではなく、操作がActivityよりも長く続く可能性がある場合に特に、この操作のためにサービスを開始することが望ましい.
    たとえば、Webサイトに画像をアップロードしているActivityは、アップロードを実行するためにサービスを開始する必要があります.これにより、ユーザーがActivityを終了しても、バックグラウンドでアップロード操作を継続できます.サービスを使用すると、Activityがどのような状況であっても、この操作は少なくとも「サービスプロセス」の優先度を備えていることが保証されます.同様に、ブロードキャスト受信機も、単純にスレッドに時間のかかる操作を入れるのではなく、サービスを使用するべきである.
    スレッド
    アプリケーションが起動すると、アプリケーションに「プライマリ・スレッド」という実行スレッドが作成されます.このスレッドは、図面イベントを含む対応するユーザーインタフェースウィジェットに時間を割り当てるため、非常に重要です.また、Android UIキットコンポーネント(android.widgetおよびandroid.viewパッケージからのコンポーネント)とインタラクティブなスレッドも適用されます.したがって、プライマリスレッドはUIスレッドとも呼ばれる場合があります.
    システムは各コンポーネントに個別のスレッドを作成しません.同じプロセスで実行されるすべてのコンポーネントはUIスレッドでインスタンス化され、各コンポーネントのシステムコールはスレッドによって割り当てられます.したがって、onKeyDown()やライフサイクルコールバックメソッドなどのコールバックに応答する方法は、プロセスのUIスレッドで常に実行されます.
    UIスレッドは、時間のかかる操作またはブロックされた操作を実行するべきではありません.UIスレッドが約5秒以上ブロックされている場合、ユーザーはANR(Application Not Response)ダイアログボックスを表示します.
    また、Android UIキットはスレッドセキュリティキットではありません.このため、作業スレッドでUIを操作することはできず、UIスレッドでのみユーザインタフェースを操作することができる.そのため、Androidのシングルスレッドモードは2つのルールを守らなければなりません.
  • UIスレッド
  • をブロックしないでください.
  • UIスレッドの外でAndroid UIキット
  • にアクセスしないでください.
    ワークスレッド
    上記の単一スレッドモードによれば、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番目のルールに違反しています.UIスレッドの外でAndroid UIキットにアクセスしないでください.この例では、UIスレッドではなくワークスレッドからImageViewを変更します.これにより、不明確で予見できない動作が発生する可能性がありますが、この行を追跡するのは困難で時間がかかります.
    この問題を解決するために、Androidは他のスレッドからUIスレッドにアクセスするためのいくつかの方法を提供しています.次のようになります.
  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)

  • 例えば、Viewを利用することができる.Post(Runnable)メソッドは、上記のコードを修復します.
    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();
    }
    

    ここで、上述の実装はスレッドセキュリティに属する:個別のスレッドでネットワーク操作を完了し、UIスレッドでImageViewを操作する.
    しかし、このようなコードはメンテナンスが困難になる可能性があります.より複雑なインタラクションをワークスレッドで処理するには、ワークスレッドでHandler処理を使用してスレッドをUIするメッセージを考慮します.しかし、最良の解決策は、UIとのインタラクションに必要な作業スレッドを簡素化するAsyncTaskクラスを拡張することかもしれない.
    AsyncTaskの使用
    AsyncTaskでは、ユーザーインタフェースに対して非同期操作を実行できます.作業スレッド内の操作が最初にブロックされ、スレッドおよび/またはプロセッサを直接処理することなくUIスレッドで結果が発行されます.
    これを使用するには、AsyncTaskのサブクラスを作成し、バックグラウンドスレッドプールで実行されるdoInBackground()コールバックメソッドを実装する必要があります.UIを更新するには、doInBackground()から返された結果を渡すためにonPostExecute()を実装し、UIスレッドで実行して、UIを安全に更新する必要があります.その後、UIスレッドからexecute()を呼び出すことでタスクを実行できます.
    たとえば、AsyncTaskを使用して、上記の例を実装します.
    public void onClick(View v) {
        new DownloadImageTask().execute("http://example.com/image.png");
    }
    
    private class DownloadImageTask extends AsyncTask {
        /** The system calls this to perform work in a worker thread and
          * delivers it the parameters given to AsyncTask.execute() */
        protected Bitmap doInBackground(String... urls) {
            return loadImageFromNetwork(urls[0]);
        }
    
        /** The system calls this to perform work in the UI thread and delivers
          * the result from doInBackground() */
        protected void onPostExecute(Bitmap result) {
            mImageView.setImageBitmap(result);
        }
    }
    

    上記のコードでは、タスクを2つの部分に分解します.一部は作業スレッド内で完了し、もう一部はUIスレッド内で完了します.
    AsyncTaskの作業方法の概要:
  • は、汎用指定型パラメータ、進捗値、およびタスク最終値
  • を使用することができる.
  • メソッドdoInBackground()は、ワークスレッド上で
  • を自動的に実行します.
  • onPreExecute()、onPostExecute()およびonProgressUpdate()は、UIスレッドで
  • を呼び出す.
  • doInBackground()が返す値はonPostExecute()
  • に送信されます.
  • は、いつでもdoInBackground()でpublishProgress()を呼び出し、UIスレッドでonProgressUpdate()
  • を実行することができる.
  • は、任意のスレッド内のタスク
  • をいつでもキャンセルすることができる.
    注意:作業スレッドを使用すると、実行時の構成変更(ユーザーが画面の方向を変更した場合など)によってActivityが予期せぬ再起動を起こし、作業スレッドが破棄される可能性があるという別の問題が発生する可能性があります.この再起動時にタスクを続行し、Activityが破棄されたときにタスクを正しく取り消す方法については、例を参照してください(http://code.google.com/p/shelves/)ソースコード.
    スレッドのセキュリティ方法
    バインディング・サービスのようなリモート・コール可能なメソッドの場合、IBinderで実装されたメソッドの呼び出しがIBinderを実行する同じプロセスから発生した場合、このメソッドは呼び出し元のスレッドで実行されます.
    ただし、呼び出しが他のプロセスに由来する場合、このメソッドは、プロセスのUIスレッドではなく、スレッドプールから選択されたスレッドで実行され、スレッドプールはシステムによってIBinderと同じプロセスで維持されます.
    たとえば、サービスのonBind()メソッドがサービスプロセスのUIスレッドから呼び出されるとしても、onBind()から返されるオブジェクトで実装されるメソッド(たとえばRPCメソッドを実装するサブクラス)は、スレッドプール内のスレッドから呼び出されます.
    1つのサービスに複数のクライアントがあるため、同じ時間に同じIBinderメソッドを使用する複数のスレッドプールがある可能性があります.したがって,IBinderメソッドはスレッドセキュリティのためのメソッドとして実装されなければならない.
    プロセス間通信
    Androidは、Activityまたは他のアプリケーションコンポーネントによって呼び出されるメソッド(または他のプロセス)がリモートで実行され、すべての結果が呼び出し元に返されるプロセス間通信(IPC)メカニズムを提供します.
  • は、メソッド呼び出しおよびそのデータをオペレーティングシステムが認識できる程度に分解し、ローカルプロセスおよびアドレス空間からリモートプロセスおよびアドレス空間に伝送する、
  • .
  • は、その後、リモートプロセスにおいて再組み立てられ、呼び出され、
  • .
  • の最後の戻り値は、反対方向に転送されます.

  • AndroidはこれらのIPCを実行するために必要なすべてのコードを提供しているので、PRCプログラミングインタフェースの定義と実現に集中すればよい.
    IPCを実行するにはbindService()を使用してアプリケーションをサービスにバインドする必要があります.