Androidメッセージ処理-アプリケーションリファレンス編

9655 ワード

二、Androidメッセージ処理-応用参考編
 
1.概要
この文書では、一般的なメッセージ処理方法を収集します.
 
2.ポイント
         A.サブスレッド更新UIのエラー
         B.Handler適用例
         C.AsyncTaskアプリケーションの例
 
3.本文
3.1サブスレッド更新UI(初心者がよく犯すエラー)
プログラムが時間のかかる操作を実行する必要がある場合は、onClickメソッドでGOOGLE APIを呼び出して天気データを取得する新しいサブスレッドを作成する必要があります.Androidに触れたばかりの開発者が最も考えやすい方法は、次のとおりです.
   public void onClick(View v) {
      //                         
      new Thread() {
          @Override
          public void run() {
              //           
              String city = editText.getText().toString();
              //  Google   API             
              String weather =getWetherByCity(city);
              //        title 
              setTitle(weather);
          }
      }.start();
    }

しかし残念なことに、Androidはプログラムが異常で終了したことを示すことに気づきます.なぜ他のプラットフォームで簡単に見えるコードがAndroidで実行されてもエラーが発生するのでしょうか?LogCatで印刷されたログ情報を見ると、次のようなエラーログが表示されます.
android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.
Androidは、UI threadによって作成された試行を更新するために他のサブスレッドを禁止していることがわかります.この例で天気情報を表示するtitleは、実際にはUI threadによって作成されたTextViewなので、サブスレッドでTextViewを変更しようとするとエラーが発生します.これは、Android UI操作はスレッドが安全ではなく、UIスレッドで実行しなければならないという単一スレッドモデルの原則に反していることを示しています.
変更方法最も簡単な方法:Handlerを使用して、メインスレッドにMessageを送信し、メインスレッドでUI更新を処理します.次の例も参考にしてください.
 
 
3.2メインスレッドと他のサブスレッドがどのように相互作用するか
主スレッドと他のサブスレッドがどのように相互作用し、情報を転送し、最終的に誰が処理情報を実行するかなど、個人的な理解が最も簡単な方法であるHandlerオブジェクトの中のLooperオブジェクトがどのスレッドに属しているかを判断するには、そのスレッドによって実行される.
    1. Handlerオブジェクトのコンストラクション関数のパラメータが空の場合、現在のスレッドのLooperになります.
   2. Looper.getMainLooper()はメインスレッドのLooperオブジェクト,Looperを得る.myLooper()は、現在のスレッドのLooperオブジェクトを取得します.
次に、ネットワークからデータを取得し、ListViewにロードするプロセスをシミュレートする例を示します.
1. public class ListProgressDemo extends ListActivity { 
2.  
3.     @Override 
4.     public void onCreate(Bundle savedInstanceState) { 
5.         super.onCreate(savedInstanceState); 
6.         setContentView(R.layout.listprogress); 
7.  
8.         ((Button) findViewById(R.id.load_Handler)).setOnClickListener(new View.OnClickListener(){  
9.                     @Override 
10.             public void onClick(View view) { 
11.                 data = null; 
12.                 data = new ArrayList<String>();  
13.                 adapter = null;  
14.                 showDialog(PROGRESS_DIALOG); 
15.                 new ProgressThread(handler, data).start(); 
16.             } 
17. }); 
18. } 
19.  
20.     @Override 
21.     protected Dialog onCreateDialog(int id) { 
22.         switch(id) { 
23.         case PROGRESS_DIALOG: 
24.                  return ProgressDialog.show(this, "",   "Loading. Please wait...", true);  
25.         default: return null; 
26.         } 
27.     } 
28.  
29.     private class ProgressThread extends Thread {  
30.         private Handler handler; 
31.         private ArrayList<String> data;  
32.         public ProgressThread(Handler handler, ArrayList<String> data) { 
33.             this.handler = handler; 
34.             this.data = data; 
35.         } 
36.  
37.         @Override 
38.         public void run() { 
39.             for (int i=0; i<8; i++) { 
40.                 data.add("ListItem"); //      
41.                 try { 
42.                     Thread.sleep(100); 
43.                 }catch(InterruptedException e) {                      
44.                     Message msg = handler.obtainMessage(); 
45.                     Bundle b = new Bundle(); 
46.                     b.putInt("state", STATE_ERROR); 
47.                     msg.setData(b); 
48.                     handler.sendMessage(msg);                       
49.                 } 
50.             } 
51.             Message msg = handler.obtainMessage(); 
52.             Bundle b = new Bundle(); 
53.             b.putInt("state", STATE_FINISH); 
54.             msg.setData(b); 
55.             handler.sendMessage(msg); 
56.         }          
57.     } 
58.  
59.     //            Looper,  Handler          Looper
60.     private final Handler handler = new Handler(Looper.getMainLooper()) { 
61.         public void handleMessage(Message msg) { //   Message,  ListView
62.             int state = msg.getData().getInt("state"); 
63.             switch(state){ 
64.                 case STATE_FINISH: 
65.                     dismissDialog(PROGRESS_DIALOG); 
66.                     Toast.makeText(getApplicationContext(),     "    !",  Toast.LENGTH_LONG) .show();  
67.                     adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, 
68.                             data );                              
69.                     setListAdapter(adapter);  
70.                     break; 
71.  
72.                 case STATE_ERROR: 
73.                    dismissDialog(PROGRESS_DIALOG); 
74.                    Toast.makeText(getApplicationContext(), "        !",  Toast.LENGTH_LONG).show();  
75.                    adapter = new ArrayAdapter<String>(getApplicationContext(), 
76.                            android.R.layout.simple_list_item_1,  data );                             
77.                       setListAdapter(adapter);  
78.                       break;  
79.                default:  
80.             } 
81.         } 
82.     };  
83.  
84.     private ArrayAdapter<String> adapter; 
85.     private ArrayList<String> data;  
86.     private static final int PROGRESS_DIALOG = 1; 
87.     private static final int STATE_FINISH = 1; 
88.     private static final int STATE_ERROR = -1; 
89. } 

この例では,自分で書き終わった後も少し乱れているように感じ,スレッド間のインタラクションの過程やデータの前後の変化を少し整理しなければ理解できない.その後AsyncTaskクラスがわかり、それに応じて修正してわかりやすくなりました!
 
3.3 AsyncTask非同期ロードの使用
1. ((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){ 
2.  
3.     @Override 
4.     public void onClick(View view) { 
5.         data = null; 
6.         data = new ArrayList<String>(); 
7.  
8.         adapter = null; 
9.  
10.         //  ProgressDialog  AsyncTask.onPreExecute()  
11.         //showDialog(PROGRESS_DIALOG); 
12.         new ProgressTask().execute(data); 
13.     } 
14. }); 
15.  
16. private class ProgressTask extends AsyncTask<ArrayList<String>, Void, Integer> { 
17.  
18. /*                 UI thread  。              ,            。*/ 
19. @Override 
20. protected void onPreExecute() { 
21.     //    ProgressDialog
22.     showDialog(PROGRESS_DIALOG); 
23. } 
24.  
25. /*               。    publishProgress            。 */ 
26. @Override 
27. protected Integer doInBackground(ArrayList<String>... datas) { 
28.     ArrayList<String> data = datas[0]; 
29.     for (int i=0; i<8; i++) { 
30.         data.add("ListItem"); 
31.     } 
32.     return STATE_FINISH; 
33. } 
34.  
35. /*  doInBackground      ,onPostExecute     UI thread  , 
36.  *                 UI thread. 
37.  */ 
38. @Override 
39. protected void onPostExecute(Integer result) { 
40.     int state = result.intValue(); 
41.     switch(state){ 
42.     case STATE_FINISH: 
43.         dismissDialog(PROGRESS_DIALOG); 
44.         Toast.makeText(getApplicationContext(),    "    !",   Toast.LENGTH_LONG).show(); 
45.  
46.         adapter = new ArrayAdapter<String>(getApplicationContext(),  android.R.layout.simple_list_item_1,  data );                  
47.         setListAdapter(adapter);  
48.         break; 
49.          
50.     case STATE_ERROR: 
51.        dismissDialog(PROGRESS_DIALOG); 
52.        Toast.makeText(getApplicationContext(),"        !", Toast.LENGTH_LONG).show(); 
53.        adapter = new ArrayAdapter<String>(getApplicationContext(),  android.R.layout.simple_list_item_1, data ); 
54.        setListAdapter(adapter);
55.         break;
56.  
57.    default:
58.  
59.    }
60. }

Androidはまた、AsyncTaskというツールクラスを提供しています.UI threadの使用が非常に簡単になります.これにより、スレッドやHandlerを使用することなく、ユーザーインタフェースとインタラクティブに長時間実行する必要があるタスクの作成が簡単になります.
1)サブクラス化AsyncTask
2)AsyncTaskで定義された次の1つまたは複数の方法を実装する
onPreExecute()実行前の準備作業を開始します.
         doInBackground(Params...)バックグラウンド処理を開始し、publishProgressメソッドを呼び出してリアルタイムのタスク進捗を更新できます.
        onProgressUpdate(Progress...) publishProgressメソッドが呼び出されると、UI threadはこのメソッドを呼び出して、タスクの進捗状況をインタフェースに表示します.たとえば、進捗バーで表示します.
onPostExecute(Result)は、完了した操作を実行し、UIスレッドに結果を転送します.
 
この4つのメソッドは、手動で呼び出すことはできません.しかもdoInBackground(Params...)以外はメソッド、残りの3つのメソッドはUIスレッドによって呼び出されるので、次のように要求されます.
1)AsyncTaskのインスタンスはUI threadで作成しなければならない.
        2) AsyncTask.executeメソッドはUI threadで呼び出さなければならない.
        
また、taskは1回しか実行できません.そうしないと、複数回呼び出されると例外が発生します.そして手動で止めることはできません.この点に注意して、あなたのニーズに合っているかどうかを見てください.測定待ち
 
使用中、AsyncTaskのコンストラクション関数のパラメータ設定を確認するには、AsyncTask
Params対応doInBackground(Params...)の双曲線コサインを返します.そしてnew AsyncTask().execute(Params...params)は、転送されたParamsデータであり、execute(data)で1つのデータを転送したり、execute(data 1,data 2,data 3)のような複数のデータを転送したりすることができます.
Progress対応onProgressUpdate(Progress...)のパラメータタイプ;
ResultはonPostExecute(Result)のパラメータタイプに対応します.
上記のパラメータタイプのいずれかを指定する必要がない場合は、voidではないことに注意してVoidを使用します.わからない場合は、上記の例、またはAPI Docの例を参考にしてください.
 
[上記から:http://android.blog.51cto.com/268543/343823]
 
4.結語
Handler部分は、Bundle形式で多くのデータを携帯することもでき、この例は拡張される.
AnyscTaskセクション、なぜ複数回呼び出せないのですか?3つ目の方法も試してみる必要があります.