Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的 事件流----淺析安卓中的動與靜(三) 線程間通訊

Android中的 事件流----淺析安卓中的動與靜(三) 線程間通訊

編輯:關於Android編程

任何程序都是靜態代碼,我們把這些靜態代碼打包好,然後放到運行環境當中,通過事件流的驅動使這些代碼運行起來。Android的環境也不例外。

靜態的代碼,在動態事件的驅動下,才會有效的運轉起來。

驅動Android程序運行起來的事件大致可以分為以下幾種:

用戶事件
:如點擊屏幕,滑動等各種手勢;

系統事件:如屏幕方向的轉變;

線程通訊事件:線程之間互發消息,程序根據消息內容進行相應的響應;

進程通訊事件:這裡的進程包括本程序開啟的進程,也包括其他應用程序的進程。

下面來介紹動態事件驅動的第三種:線程通訊事件流

線程通訊事件流

線程通訊也是造成Android動態化的一個重要方面,當一個UI主線程收到其他線程發過來的消息,可以動態更改自己的頁面。

下面總結下線程之間通訊的幾種方式

(從重要性和實用角度排序)

1.使用Handler實現

2.使用AsyncTask

3.Activity.runOnUiThread(Runnbale)

4.View.post(Runnbale)

5.View.postDelayed(Runnalbe,long)

2-5其實內部實現都是Handler。

下面一一介紹用法:

1.使用Handler實現

先來講Handler的實現,因為後邊的四個都是基於Handler的實現的,談到Handler的運行機制,不得不提Looper、Message、MessagerQueue了,它們之間的關系,下邊這個圖片描述的很清楚了。

\

用一句話總結就是在主線程中定義Handler對象,然後在子線程中調用這個Handler對象將封裝好的Message對象發送到主線程中Looper管理的MessageQueue中。上邊兩句話是說在子線程中向主線程發送消息。那我如果想從主線程向子線程發送消息呢?或者子線程之間發送消息呢?其實還是一個道理。線程A要想給線程B發送消息,就要獲取線程B中的Handler對象,然後通過此對象向線程B中的Looer中的MessageQueue中發送消息。注意,Looper和Handler是一一對應的。一個handler只能向其所在的線程發送Message消息。只不過UI線程的Looper是自動啟動好的,其他線程要想享受到Looper的服務,必須通過Looper.prepare()和Looper.loop();自行啟動。下邊寫了一個demo,以後可以學習參考:

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
	    final Handler mHandler=new Handler();
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final MyButton er=(MyButton) findViewById(R.id.ddd);
		Log.v("onCreate",	 "onCreate");
		er.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Log.v("onClick",	 v.toString());
				Intent sub= new Intent(MainActivity.this, SubActivity.class);
				startActivity(sub);
				
			}
		});


        final Myrunnable murMyrunnable=new Myrunnable();

        new Thread(murMyrunnable).start();
        
        
        
        new Thread(new Runnable() {

 
            


                //延遲兩秒


            	 public Handler mHandler;

                 public void run() {

                                 Looper.prepare();
                                 Looper.loop();

                                 mHandler = new Handler() {

                                                 public void handleMessage(Message msg) {

                                                	 Toast.makeText(MainActivity.this, "wewe"+msg.what, Toast.LENGTH_SHORT).show();
                                                 }

                                 };

                             


            }

        }).start();

        //創建一個線程

        new Thread(new Runnable() {

 

            @Override

            public void run() {

 

                //延遲兩秒


                try {

                    Thread.sleep( 5000 );

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

 

             
                 mHandler.post(new Runnable() {
                	 //
                   @Override

                   public void run() {
                   	er.setText("變了");
                       Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();
                       //創建一個線程
                       Message sdfMessage=new Message();
                       sdfMessage.what=12 ;
                       murMyrunnable.mHandler.sendMessage(sdfMessage);
                   }

               });

                 

            }

        }).start();
	
		//er.setClickable(false);
	}
	
	
	class Myrunnable implements Runnable{




            //延遲兩秒


        	 public Handler mHandler;

             public void run() {

                             Looper.prepare();

                             mHandler = new Handler() {

                                             public void handleMessage(Message msg) {

                                            	 Toast.makeText(MainActivity.this, "wewe"+msg.what, Toast.LENGTH_SHORT).show();
                                             }

                             };

                             Looper.loop();


        }

   
	}		
		
		
	}

 

2.使用AsyncTask

關於AsyncTask的使用網上已經有很多資料這裡不再詳述,只是簡單介紹下用法,以及其內部與handler的關系。

AsyncTask屏蔽了很多多線程的實現細節,很適合初學者使用,現在通過代碼來介紹:

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
	    final Handler mHandler=new Handler();
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final MyButton er=(MyButton) findViewById(R.id.ddd);
		Log.v("onCreate",	 "onCreate");
		er.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v){MyAsyncTask myAsyncTask = new MyAsyncTask(MainActivity.this);
			      myAsyncTask.execute(20);
				
			}
		});


}
/*
 * integer:啟動任務執行的輸入參數,integer:後台任務完成的進度值的類型;String:後台執行任務完成後返回結果的類型
 * 這三個參數可以根據需要進行設定
 */
class MyAsyncTask extends AsyncTask{
	
	ProgressDialog pDialog;
	Context mContext;
	public  MyAsyncTask( Context mContext){
		this.mContext=mContext;
	}

     //核心函數,可以理解為在子線程中執行
	@Override
	protected String doInBackground(final Integer... params) {
		
	
			 Integer percent=params[0];
   
				 while (percent<101) {
					 percent++;
					 publishProgress(percent);
					Log.v("percent", percent+"");
				}
				
				  

		return null;
	}
	/*
	 * 上個函數的結果作為參數,傳給result形參,函數內部執行更新UId的更新操作,可以理解為在UI線程中執行
	 * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
	 */
	@Override
	protected void onPostExecute(String result) {
		// TODO Auto-generated method stub
		super.onPostExecute(result);
	}	
	/*
	 * 在執行第一個函數之前執行,做一些准備工作,可以理解為在UI線程中執行
	 * @see android.os.AsyncTask#onPreExecute()
	 */
	@Override
	protected void onPreExecute() {
		
		//這裡的准備工作是顯示進度條
		pDialog=new ProgressDialog(mContext);
		pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
		pDialog.show();
		
	}
	/*
	 * 可以在第一個函數中調用,更新新進度注意是可以,無需求可以不用使用。
	 * @see android.os.AsyncTask#onProgressUpdate(java.lang.Object[])
	 */
	@Override
	protected void onProgressUpdate(Integer... values) {
		
		pDialog.setProgress(values[0]);
	}
}
 

AsyncTask內部實際上new了一個Handler。如下圖:

\

再來看下InternalHandler的定義:

    private static class InternalHandler extends Handler {
        @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
        @Override
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }


顯而易見,InternalHandler繼承自Handler。

重點不是Handler在哪個類中new的,而是只要是new了Handler,就可以通過Handler向創建Handler的那個線程中發送Message消息。

這就是為什麼使用AsyncTask時必須在UI線程中創建的原因。

大概的原來不再贅述,原理與上一部分Handler的運行機制大同小異。

3.Activity.runOnUiThread(Runnbale)

在子線程中調用Activity.runOnUiThread(Runnbale)方法,在傳過來的Runnbale參數的run方法裡更新主線程UI。具體可以參考以下代碼:

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final MyButton er=(MyButton) findViewById(R.id.ddd);		

        //創建一個線程

        new Thread(new Runnable() {

 

            @Override

            public void run() {

 

                //延遲兩秒

                try {

                    Thread.sleep( 5000 );

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

 

                runOnUiThread(new Runnable() {

                    @Override

                    public void run() {
                    	er.setText("變了");
                        Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();

                    }

                });

 

            }

        }).start();
	
		//er.setClickable(false);
	}
}

注意為了保證線程安全,要更改的UI控件必須是final的。為什麼說Activity.runOnUiThread(Runnbale)內部是用Handler實現的呢?我們來看下runOnUiThread(Runnbale)的源碼就清楚了。

    /**
     * Runs the specified action on the UI thread. If the current thread is the UI
     * thread, then the action is executed immediately. If the current thread is
     * not the UI thread, the action is posted to the event queue of the UI thread.
     *
     * @param action the action to run on the UI thread
     */
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

看到mHandler對象了嗎?我們來看下它的定義:

    final Handler mHandler = new Handler();

所以是不是很清楚了。不管Handler在哪個類中new出來,用Handler傳值都會傳到創建Handler的那個線程中,重點的不是在哪個類中new,而是Handler在哪個線程中。

4.View.post(Runnbale)

其實這個的用法和上邊講的很類似。在子線程中調用某個view的post(Runnbale)方法,在傳過來的Runnbale參數的run方法裡更新主線程UI。具體可以參考以下代碼:

        new Thread(new Runnable() {

 

            @Override

            public void run() {

 

                //延遲兩秒


                try {

                    Thread.sleep( 5000 );

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

 

                er.post(new Runnable() {

                    @Override

                    public void run() {
                    	er.setText("變了");
                        Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();

                    }

                });
             
                 
                 

            }

        }).start();

為什麼可以這樣調用,因為View中也定義了Handler的對象,看下邊的源碼:


\

找到mHandler的定義:

\

5.View.postDelayed(Runnalbe,long)

和上邊的類似,無非是延遲一些毫秒數來執行Runnable裡面的方法,如View.postDelayed(Runnalbe,2000)是延遲2秒執行。

 

歡迎大家留言討論。

後邊將介紹造成安卓動態化的第三種因素:進程之間的通訊。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved