android進程與線程詳解


android進程與線程詳解一:進程

當一個應用的組件開始運行,並且這個應用沒有其它的組件在運行,系統會為這個應用啟動一個新的Linux進程,這個進程只有一個線程.默認情況下,一個應用的所有組件都運行在一個進程和線程(主線程)中.如果一個應用的線程開始運行,並且已經存在這個應用的線程了(因為有這個應用程序的另一個組件已經運行了),於是這個組件就會在這個已有的進程中啟動並且運行在同一個線程中.然而,你完全可以安排不同的組件運行於不同的進程,並且你可以為任何程序創建另外的線程.

進程

默認下,同一個程序的所有組件都運行在同一個進程中並且大多數程序不必改變這一狀況.然而,如果你非要與眾不同,也可以通過修改manifest文件實現.

manifest文件中的所有支持android:process屬性的那些項(<activity>,<service>, <receiver>,<provider>)都可以指定一個進程,於是這些組件就會在這個進程中運行.你可以設置這個屬性使每個組件運行於其自己的進程或只是其中一些組件共享一個進程.你也可以設置android:process以使不同應用的組件們可以運行於同一個進程—假如這些應用共享同一個用戶ID並且有相同的數字證書.

<application>元素也支持android:process屬性,用於為所有的組件指定一個默認值.

Android可能在某些時刻決定關閉一個進程,比如內存很少了並且另一個進程更迫切的需要啟動時.進程被關閉時,其中的組件們都被銷毀.如果重新需要這些組件工作時,進程又會被創建出來.

當決定關閉哪些線程時,Android系統會衡量進程們與用戶的緊密程度.例如,比起一個具有可見的activity的進程,那些所含activity全部不可見的進程更容易被關閉.如何決定一個進程是否被關閉,取決於進程中運行的組件們的狀態.決定關閉進程的規則將在下面討論.

進程的生命期

Android系統會盡量維持一個進程的生命,直到最終需要為新的更重要的進程騰出內存空間。為了決定哪個該殺哪個該留,系統會跟據運行於進程內的組件的和組件的狀態把進程置於不同的重要性等級。當需要系統資源時,重要性等級越低的先被淘汰。

重要性等級被分為5個檔。下面列出了不同類型的進程的重要性等級(第一個進程類型是最重要的,也是最后才會被殺的):

1前台進程

用戶當前正在做的事情需要這個進程。如果滿足下面的條件,一個進程就被認為是前台進程:

這個進程擁有一個正在與用戶交互的Activity(這個ActivityonResume() 方法被調用)

這個進程擁有一個綁定到正在與用戶交互的activity上的Service

這個進程擁有一個前台運行的Service — service調用了方法 startForeground().

這個進程擁有一個正在執行其任何一個生命周期回調方法(onCreate(),onStart(), onDestroy())的Service

這個進程擁有正在執行其onReceive()方法的BroadcastReceiver


通常,在任何時間點,只有很少的前台進程存在。它們只有在達到無法調合的矛盾時才會被殺--如果內存太小而不能繼續運行時。通常,到了這時,設備就達到了一個內存分頁調度狀態,所以需要殺一些前台進程來保證用戶界面的反應

2可見進程

一個進程不擁有運行於前台的組件,但是依然能影響用戶所見。滿足下列條件時,進程即為可見:

這個進程擁有一個不在前台但仍可見的Activity(它的onPause()方法被調用)。當一個前台activity啟動一個對話框時,就出了這種情況。

3服務進程

一個可見進程被認為是極其重要的。並且,除非只有殺掉它才可以保證所有前台進程的運行,否則是不能動它的。

這個進程擁有一個綁定到可見activityService

一個進程不在上述兩種之內,但它運行着一個被startService()所啟動的service

盡管一個服務進程不直接影響用戶所見,但是它們通常做一些用戶關心的事情(比如播放音樂或下載數據),所以系統不到前台進程和可見進程活不下去時不會殺它。

4后台進程

一個進程擁有一個當前不可見的activity(activityonStop()方法被調用)

這樣的進程們不會直接影響到用戶體驗,所以系統可以在任意時刻殺了它們從而為前台、可見、以及服務進程們提供存儲空間。通常有很多后台進程在運行。它們被保存在一個LRU(最近最少使用)列表中來確保擁有最近剛被看到的activity的進程最后被殺。如果一個activity正確的實現了它的生命周期方法,並保存了它的當前狀態,那么殺死它的進程將不會對用戶的可視化體驗造成影響。因為當用戶返回到這個activity時,這個activity會恢復它所有的可見狀態。

5空進程

一個進程不擁有入何active組件。

保留這類進程的唯一理由是高速緩存,這樣可以提高下一次一個組件要運行它時的啟動速度。系統經常為了平衡在進程高速緩存和底層的內核高速緩存之間的整體系統資源而殺死它們。


跟據進程中當前活動的組件的重要性,Android會把進程按排在其可能的最高級別。例如,如果一個進程擁有一個service和一個可見的activity,進程會被定為可見進程,而不是服務進程。

另外,如果被其它進程所依賴,一個進程的級別可能會被提高—一個服務於其它進程的進程,其級別不可能比被服務進程低。

因為擁有一個service的進程比擁有一個后台activitie的進程級別高,所以當一個activity啟動一個需長時間執行的操作時,最好是啟動一個服務,而不是簡單的創建一個工作線程。尤其是當這個操作可能比activity的生命還要長時。例如,一個向網站上傳圖片的activity,應該啟動一個service,從而使上傳操作可以在用戶離開這個activity時繼續在后台執行。使用一個service保證了這個操作至少是在"服務進程"級別,而不用管activity是否發生了什么不幸。這同樣是廣播接收者應該使用service而不是簡單地使用一個線程的理由。

url:
http://greatverve.cnblogs.com/archive/2012/01/20/android-thread.html


android進程與線程詳解二:線程

線程


當一個應用被啟動,系統創建一個執行線程,叫做"main"。這個線程是十分重要的,因為它主管向用戶界面控件派發事件。其中包含繪圖事件。它也是你的應用與界面工具包(android.widget和 android.view包中的組件)交互的地方。於是main線程也被稱為界面線程。


系統不會為每個組件的實例分別創建線程。所有運行於一個進程的組件都在界面線程中被實例化,並且系統對每個組件的調用都在這個線程中派發。 結果,響應系統調用的方法(比如報告用戶動作的onKeyDown()或一個生命周期回調方法)永遠在界面線程中進程。


例如,當用戶觸摸屏幕上的一個按鈕時,你的應用的界面線程把觸摸事件派發給控件,然后控件設置它的按下狀態再向事件隊列發出一個自己界面變得無效的請求,界面線程從隊列中取出這個請求並通知這個控件重繪它自己。


當你的應用在響應用戶交互時需執行大量運算時,這種單線程的模式會帶來低性能,除非你能正確的優化你的程序。特別的,如果所有事情都在界面線程中發生,執行比如網絡連接或數據庫請求這樣的耗時操作,將會阻止整個界面的響應。當線程被阻塞時,就不能派發事件了,包括繪圖事件。從用戶的角度看,程序反應太慢了。甚至更糟的是,如果界面線程被阻塞幾秒鍾(大5秒鍾吧),用戶就戶抱怨說程序沒反應了,用戶可能因而退出並刪掉你的應用。


此外,Andoid界面不是線程安全的。所以你絕不能在一個工作線程中操作你的界面—你只能在界面線程中管理的你的界面。所以,對於單線程模式有兩個簡單的規則:

不要阻塞界面線程

2不要在界面線程之外操作界面。


工作線程

由於上述的單線程模式,不要阻塞你的界面線程以使你的應用的界面保持響應是非常重要的,那么如果你有不能很快完成的任務,你應把它們放在另一個線程中執行(后台線程或工作線程)

例如,下面是的代碼是響應click事件,在另外一個線程中下載一個圖片並在一個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();
}

 

 

第一眼,這看起來能很好的工作,因為它創建了一個新線程來進行網絡操作。然而它違反了第二條規則:不要在界面線程之外操作界面—它簡單的在工作線程中修改了ImageView。這會導至未定義的異常出現,並且難以調試追蹤。


為了能改正這個問題,Android提供了很多從其它線程來操作界面的方法。下面是可用的方法們:

1 Activity.runOnUiThread(Runnable)

2 View.post(Runnable)

3 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();
}

 

現在這個實現終於是線程安全的了:網絡操作在另一個線程中並且 ImageView  在界面線程中改變。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM