偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Android 的進(jìn)程與線程總結(jié)

移動(dòng)開(kāi)發(fā) Android
當(dāng)一個(gè)Android應(yīng)用程序組件啟動(dòng)時(shí)候,如果此時(shí)這個(gè)程序的其他組件沒(méi)有正在運(yùn)行,那么系統(tǒng)會(huì)為這個(gè)程序以單一線程的形式啟動(dòng)一個(gè)新的Linux 進(jìn)程。 默認(rèn)情況下,同一應(yīng)用程序下的所有組件都運(yùn)行再相同的進(jìn)程和線程(一般稱(chēng)為程序的“主”線程)中。如果一個(gè)應(yīng)用組件啟動(dòng)但這個(gè)應(yīng)用的進(jìn)程已經(jīng)存在了(因?yàn)?這個(gè)應(yīng)用的其他組件已經(jīng)在之前啟動(dòng)了),那么這個(gè)組件將會(huì)在這個(gè)進(jìn)程中啟動(dòng),同時(shí)在這個(gè)應(yīng)用的主線程里面執(zhí)行。然而,你也可以讓你的應(yīng)用里面的組件運(yùn)行在 不同的進(jìn)程里面,也可以為任何進(jìn)程添加額外的線程。

本文翻譯自Android官方文檔

當(dāng)一個(gè)Android應(yīng)用程序組件啟動(dòng)時(shí)候,如果此時(shí)這個(gè)程序的其他組件沒(méi)有正在運(yùn)行,那么系統(tǒng)會(huì)為這個(gè)程序以單一線程的形式啟動(dòng)一個(gè)新的Linux 進(jìn)程。 默認(rèn)情況下,同一應(yīng)用程序下的所有組件都運(yùn)行再相同的進(jìn)程和線程(一般稱(chēng)為程序的“主”線程)中。如果一個(gè)應(yīng)用組件啟動(dòng)但這個(gè)應(yīng)用的進(jìn)程已經(jīng)存在了(因?yàn)檫@個(gè)應(yīng)用的其他組件已經(jīng)在之前啟動(dòng)了),那么這個(gè)組件將會(huì)在這個(gè)進(jìn)程中啟動(dòng),同時(shí)在這個(gè)應(yīng)用的主線程里面執(zhí)行。然而,你也可以讓你的應(yīng)用里面的組件運(yùn)行在 不同的進(jìn)程里面,也可以為任何進(jìn)程添加額外的線程。

這片文章討論了Android程序里面的進(jìn)程和線程如何運(yùn)作的。

進(jìn)程

默認(rèn)情況下,同一程序的所有組件都運(yùn)行在相同的進(jìn)程里面,大多數(shù)的應(yīng)用都是這樣的。然而,如果你發(fā)現(xiàn)你需要讓你的程序里面的某個(gè)組件運(yùn)行在特定的進(jìn)程里面,你可以在manifest 文件里面設(shè)置。

manifest 文件里面為每一個(gè)組件元素—<activity><service><receiver>, 和<provider>—提供了 android:process 屬 性。通過(guò)設(shè)置這個(gè)屬性你可以讓組件運(yùn)行在特定的進(jìn)程中。你可以設(shè)置成每個(gè)組件運(yùn)行在自己的進(jìn)程中,也可以讓一些組件共享一個(gè)進(jìn)程而其他的不這樣。你還可以 設(shè)置成不同應(yīng)用的組件運(yùn)行在同一個(gè)進(jìn)程里面—這樣可以讓這些應(yīng)用共享相同的Linux user ID同時(shí)被相同的證書(shū)所認(rèn)證。

<application> 元素也支持 android:process 屬性,設(shè)置這個(gè)屬性可以讓這個(gè)應(yīng)用里面的所有組件都默認(rèn)繼承這個(gè)屬性。

Android 可能在系統(tǒng)剩余內(nèi)存較少,而其他直接服務(wù)用戶的進(jìn)程又要申請(qǐng)內(nèi)存的時(shí)候shut down 一個(gè)進(jìn)程, 這時(shí)這個(gè)進(jìn)程里面的組件也會(huì)依次被kill掉。當(dāng)這些組件有新的任務(wù)到達(dá)時(shí),他們對(duì)應(yīng)的進(jìn)程又會(huì)被啟動(dòng)。

在決定哪些進(jìn)程需要被kill的時(shí)候,Android系統(tǒng)會(huì)權(quán)衡這些進(jìn)程跟用戶相關(guān)的重要性。比如,相對(duì)于那些承載這可見(jiàn)的activities的 進(jìn)程,系統(tǒng)會(huì)更容易的kill掉那些承載不再可見(jiàn)activities的進(jìn)程。決定是否終結(jié)一個(gè)進(jìn)程取決于這個(gè)進(jìn)程里面的組件運(yùn)行的狀態(tài)。下面我們會(huì)討論 kill進(jìn)程時(shí)所用到的一些規(guī)則。

進(jìn)程的生命周期

作為一個(gè)多任務(wù)的系統(tǒng),Android 當(dāng)然系統(tǒng)能夠盡可能長(zhǎng)的保留一個(gè)應(yīng)用進(jìn)程。但是由于新的或者更重要的進(jìn)程需要更多的內(nèi)存,系統(tǒng)不得不逐漸終結(jié)老的進(jìn)程來(lái)獲取內(nèi)存。為了聲明哪些進(jìn)程需要保 留,哪些需要kill,系統(tǒng)根據(jù)這些進(jìn)程里面的組件以及這些組件的狀態(tài)為每個(gè)進(jìn)程生成了一個(gè)“重要性層級(jí)” 。處于***重要性層級(jí)的進(jìn)程將會(huì)***時(shí)間被清楚,接著時(shí)重要性高一點(diǎn),然后依此類(lèi)推,根據(jù)系統(tǒng)需要來(lái)終結(jié)進(jìn)程。

在這個(gè)重要性層級(jí)里面有5個(gè)等級(jí)。下面的列表按照重要性排序展示了不同類(lèi)型的進(jìn)程(***種進(jìn)程是最重要的,因此將會(huì)在***被kill):

  1. Foreground 進(jìn)程 一個(gè)正在和用戶進(jìn)行交互的進(jìn)程。 如果一個(gè)進(jìn)程處于下面的狀態(tài)之一,那么我們可以把這個(gè)進(jìn)程稱(chēng)為 foreground 進(jìn)程:
    • 進(jìn)程包含了一個(gè)與用戶交互的 Activity  (這個(gè) Activity的 onResume() 方法被調(diào)用)。
    • 進(jìn)程包含了一個(gè)綁定了與用戶交互的activity的 Service 。
    • 進(jìn)程包含了一個(gè)運(yùn)行在”in the foreground”狀態(tài)的 Service —這個(gè) service 調(diào)用了 startForeground()方法。
    • 進(jìn)程包含了一個(gè)正在運(yùn)行的它的生命周期回調(diào)函數(shù) (onCreate()onStart(), oronDestroy())的 Service 。
    • 進(jìn)程包含了一個(gè)正在運(yùn)行 onReceive() 方法的 BroadcastReceiver 。

    一般說(shuō)來(lái),任何時(shí)候,系統(tǒng)中只存在少數(shù)的 foreground 進(jìn)程。 只有在系統(tǒng)內(nèi)存特別緊張以至于都無(wú)法繼續(xù)運(yùn)行下去的時(shí)候,系統(tǒng)才會(huì)通過(guò)kill這些進(jìn)程來(lái)緩解內(nèi)存壓力。在這樣的時(shí)候系統(tǒng)必須kill一些 (Generally, at that point, the device has reached a memory paging state,這句如何翻譯較好呢)foreground 進(jìn)程來(lái)保證 用戶的交互有響應(yīng)。

  2. Visible 進(jìn)程 一個(gè)進(jìn)程沒(méi)有任何 foreground 組件, 但是它還能影響屏幕上的顯示。 如果一個(gè)進(jìn)程處于下面的狀態(tài)之一,那么我們可以把這個(gè)進(jìn)程稱(chēng)為 visible 進(jìn)程:
    • 進(jìn)程包含了一個(gè)沒(méi)有在foreground 狀態(tài)的 Activity ,但是它仍然被用戶可見(jiàn) (它的 onPause() 方法已經(jīng)被調(diào)用)。這種情況是有可能出現(xiàn)的,比如,一個(gè) foreground activity 啟動(dòng)了一個(gè) dialog,這樣就會(huì)讓之前的 activity 在dialog的后面部分可見(jiàn)。
    • 進(jìn)程包含了一個(gè)綁定在一個(gè)visible(或者foreground)activity的 Service 。

    一個(gè) visible 進(jìn)程在系統(tǒng)中是相當(dāng)重要的,只有在為了讓所有的foreground 進(jìn)程正常運(yùn)行時(shí)才會(huì)考慮去kill visible 進(jìn)程。

  3. Service 進(jìn)程 一個(gè)包含著已經(jīng)以 startService() 方法啟動(dòng)的 Service 的 進(jìn)程,同時(shí)還沒(méi)有進(jìn)入上面兩種更高級(jí)別的種類(lèi)。盡管 service 進(jìn)程沒(méi)有與任何用戶所看到的直接關(guān)聯(lián),但是它們經(jīng)常被用來(lái)做用戶在意的事情(比如在后臺(tái)播放音樂(lè)或者下載網(wǎng)絡(luò)數(shù)據(jù)),所以系統(tǒng)也只會(huì)在為了保證所有的 foreground and visible 進(jìn)程正常運(yùn)行時(shí)kill掉 service 進(jìn)程。
  4. Background 進(jìn)程 一個(gè)包含了已不可見(jiàn)的activity的 進(jìn)程 (這個(gè) activity 的 onStop() 已 經(jīng)被調(diào)用)。這樣的進(jìn)程不會(huì)直接影響用戶的體驗(yàn),系統(tǒng)也可以為了foreground 、visible 或者 service 進(jìn)程隨時(shí)kill掉它們。一般說(shuō)來(lái),系統(tǒng)中有許多的 background 進(jìn)程在運(yùn)行,所以將它們保持在一個(gè)LRU (least recently used)列表中可以確保用戶最近看到的activity 所屬的進(jìn)程將會(huì)在***被kill。如果一個(gè) activity 正確的實(shí)現(xiàn)了它的生命周期回調(diào)函數(shù),保存了自己的當(dāng)前狀態(tài),那么kill這個(gè)activity所在的進(jìn)程是不會(huì)對(duì)用戶在視覺(jué)上的體驗(yàn)有影響的,因?yàn)楫?dāng)用戶 回退到這個(gè) activity時(shí),它的所有的可視狀態(tài)將會(huì)被恢復(fù)。查看 Activities 可以獲取更多如果保存和恢復(fù)狀態(tài)的文檔。
  5. Empty 進(jìn)程 一個(gè)不包含任何活動(dòng)的應(yīng)用組件的進(jìn)程。 這種進(jìn)程存在的唯一理由就是緩存。為了提高一個(gè)組件的啟動(dòng)的時(shí)間需要讓組件在這種進(jìn)程里運(yùn)行。為了平衡進(jìn)程緩存和相關(guān)內(nèi)核緩存的系統(tǒng)資源,系統(tǒng)需要kill這些進(jìn)程。

Android是根據(jù)進(jìn)程中組件的重要性盡可能高的來(lái)評(píng)級(jí)的。比如,如果一個(gè)進(jìn)程包含來(lái)一個(gè) service 和一個(gè)可見(jiàn) activity,那么這個(gè)進(jìn)程將會(huì)被評(píng)為 visible 進(jìn)程,而不是 service 進(jìn)程。

另外,一個(gè)進(jìn)程的評(píng)級(jí)可能會(huì)因?yàn)槠渌栏皆谒厦娴倪M(jìn)程而被提升—一個(gè)服務(wù)其他進(jìn)程的進(jìn)程永遠(yuǎn)不會(huì)比它正在服務(wù)的進(jìn)程評(píng)級(jí)低的。比如,如果進(jìn)程A中 的一個(gè) content provider 正在為進(jìn)程B中的客戶端服務(wù),或者如果進(jìn)程A中的一個(gè) service 綁定到進(jìn)程B中的一個(gè)組件,進(jìn)程A的評(píng)級(jí)會(huì)被系統(tǒng)認(rèn)為至少比進(jìn)程B要高。

因?yàn)檫M(jìn)程里面運(yùn)行著一個(gè) service 的評(píng)級(jí)要比一個(gè)包含background activities的進(jìn)程要高,所以當(dāng)一個(gè) activity 啟動(dòng)長(zhǎng)時(shí)操作時(shí),***啟動(dòng)一個(gè) service 來(lái) 做這個(gè)操作,而不是簡(jiǎn)單的創(chuàng)建一個(gè)worker線程—特別是當(dāng)這個(gè)長(zhǎng)時(shí)操作可能會(huì)拖垮這個(gè)activity。比如,一個(gè)需要上傳圖片到一個(gè)網(wǎng)站的 activity 應(yīng)當(dāng)開(kāi)啟一個(gè)來(lái)執(zhí)行這個(gè)上傳操作。這樣的話,即使用戶離開(kāi)來(lái)這個(gè)activity也能保證上傳動(dòng)作在后臺(tái)繼續(xù)。使用 service 可以保證操作至少處于”service process” 這個(gè)優(yōu)先級(jí),無(wú)論這個(gè)activity發(fā)生了什么。這也是為什么 broadcast receivers 應(yīng)該使用 services 而不是簡(jiǎn)單的將耗時(shí)的操作放到線程里面。

線程

當(dāng)一個(gè)應(yīng)用啟動(dòng)的時(shí)候,系統(tǒng)會(huì)為它創(chuàng)建一個(gè)線程,稱(chēng)為“主線程”。這個(gè)線程很重要因?yàn)樗?fù)責(zé)處理調(diào)度事件到相關(guān)的 user interface widgets,包括繪制事件。你的應(yīng)用也是在這個(gè)線程里面與來(lái)自Android UI toolkit (包括來(lái)自 android.widget 和 android.view 包的組件)的組件進(jìn)行交互。因此,這個(gè)主線程有時(shí)候也被稱(chēng)為 UI 線程。

系統(tǒng)沒(méi)有為每個(gè)組件創(chuàng)建一個(gè)單獨(dú)的線程。同一進(jìn)程里面的所有組件都是在UI 線程里面被實(shí)例化的,系統(tǒng)對(duì)每個(gè)組件的調(diào)用都是用過(guò)這個(gè)線程進(jìn)行調(diào)度的。所以,響應(yīng)系統(tǒng)調(diào)用的方法(比如 onKeyDown() 方法是用來(lái)捕捉用戶動(dòng)作或者一個(gè)生命周期回調(diào)函數(shù))都運(yùn)行在進(jìn)程的UI 線程里面。

比如,當(dāng)用戶點(diǎn)擊屏幕上的按鈕,你的應(yīng)用的UI 線程會(huì)將這個(gè)點(diǎn)擊事件傳給 widget,接著這個(gè)widget設(shè)置它的按壓狀態(tài),然后發(fā)送一個(gè)失效的請(qǐng)求到事件隊(duì)列。這個(gè)UI 線程對(duì)請(qǐng)求進(jìn)行出隊(duì)操作,然后處理(通知這個(gè)widget重新繪制自己)。

當(dāng)你的應(yīng)用與用戶交互對(duì)響應(yīng)速度的要求比較高時(shí),這個(gè)單線程模型可能會(huì)產(chǎn)生糟糕的效果(除非你很好的實(shí)現(xiàn)了你的應(yīng)用)。特別是,當(dāng)應(yīng)用中所有的事情 都發(fā)生在UI 線程里面,那些訪問(wèn)網(wǎng)絡(luò)數(shù)據(jù)和數(shù)據(jù)庫(kù)查詢等長(zhǎng)時(shí)操作都會(huì)阻塞整個(gè)UI線程。當(dāng)整個(gè)線程被阻塞時(shí),所有事件都不能被傳遞,包括繪制事件。這在用戶看來(lái),這個(gè) 應(yīng)用假死了。甚至更糟糕的是,如果UI 線程被阻塞幾秒(當(dāng)前是5秒)以上,系統(tǒng)將會(huì)彈出臭名昭著的 “application not responding” (ANR) 對(duì)話框。這時(shí)用戶可能選擇退出你的應(yīng)用甚至卸載。

另外,Android的UI 線程不是線程安全的。所以你不能在一個(gè)worker 線程操作你的UI—你必須在UI線程上對(duì)你的UI進(jìn)行操作。這有兩條簡(jiǎn)單的關(guān)于Android單線程模型的規(guī)則:

  1. 不要阻塞 UI 線程
  2. 不要在非UI線程里訪問(wèn) Android UI toolkit

Worker 線程

由于上面對(duì)單一線程模型的描述,保證應(yīng)用界面的及時(shí)響應(yīng)同時(shí)UI線程不被阻塞變得很重要。如果你不能讓?xiě)?yīng)用里面的操作短時(shí)被執(zhí)行玩,那么你應(yīng)該確保把這些操作放到獨(dú)立的線程里(“background” or “worker” 線程)。

比如,下面這段代碼在一個(gè)額外的線程里面下載圖片并在一個(gè) ImageView顯示:

  1. new Thread(new Runnable(){ 
  2.     public void run(){ 
  3.         Bitmap b = loadImageFromNetwork("http://example.com/image.png"); 
  4.         mImageView.setImageBitmap(b); 
  5.     } 
  6. }).start();} 

起先這段代碼看起來(lái)不錯(cuò),因?yàn)樗鼊?chuàng)建一個(gè)新的線程來(lái)處理網(wǎng)絡(luò)操作。然而,它違反來(lái)單一線程模型的第二條規(guī)則: 不在非UI線程里訪問(wèn) Android UI toolkit—這個(gè)例子在一個(gè)worker線程修改了 ImageView 。這會(huì)導(dǎo)致不可預(yù)期的結(jié)果,而且還難以調(diào)試。

為了修復(fù)這個(gè)問(wèn)題,Android提供了幾個(gè)方法從非UI線程訪問(wèn)Android UI toolkit 。詳見(jiàn)下面的這個(gè)列表:

那么,你可以使用 View.post(Runnable) 方法來(lái)修改之前的代碼:

  1. public void onClick(View v){ 
  2.     new Thread(new Runnable(){ 
  3.         public void run(){ 
  4.             final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); 
  5.             mImageView.post(new Runnable(){ 
  6.                 public void run(){ 
  7.                     mImageView.setImageBitmap(bitmap); 
  8.                 } 
  9.             }); 
  10.         } 
  11.     }).start();} 

現(xiàn)在這個(gè)方案的線程安全的:這個(gè)網(wǎng)絡(luò)操作在獨(dú)立線程中完成后,UI線程便會(huì)對(duì)ImageView 進(jìn)行操作。

然而,隨著操作復(fù)雜性的增長(zhǎng),代碼會(huì)變得越來(lái)越復(fù)雜,越來(lái)越難維護(hù)。為了用worker 線程處理更加復(fù)雜的交互,你可以考慮在worker線程中使用Handler ,用它來(lái)處理UI線程中的消息。也許***的方案就是繼承 AsyncTask 類(lèi),這個(gè)類(lèi)簡(jiǎn)化了需要同UI進(jìn)行交互的worker線程任務(wù)的執(zhí)行。

使用 AsyncTask

AsyncTask 能讓你在UI上進(jìn)行異步操作。它在一個(gè)worker線程里進(jìn)行一些阻塞操作然后把結(jié)果交給UI主線程,在這個(gè)過(guò)程中不需要你對(duì)線程或者h(yuǎn)andler進(jìn)行處理。

使用它,你必須繼承 AsyncTask 并實(shí)現(xiàn) doInBackground() 回調(diào)方法,這個(gè)方法運(yùn)行在一個(gè)后臺(tái)線程池里面。如果你需要更新UI,那么你應(yīng)該實(shí)現(xiàn)onPostExecute(),這個(gè)方法從 doInBackground() 取出結(jié)果,然后在 UI 線程里面運(yùn)行,所以你可以安全的更新你的UI。你可以通過(guò)在UI線程調(diào)用 execute()方法來(lái)運(yùn)行這個(gè)任務(wù)。

比如,你可以通過(guò)使用 AsyncTask來(lái)實(shí)現(xiàn)之前的例子:

  1. public void onClick(View v){ 
  2.     new DownloadImageTask().execute("http://example.com/image.png"); 
  3. private class DownloadImageTask extends AsyncTask<String,Void,Bitmap>{ 
  4.     /** The system calls this to perform work in a worker thread and 
  5.       * delivers it the parameters given to AsyncTask.execute() */ 
  6.     protected Bitmap doInBackground(String... urls){ 
  7.         return loadImageFromNetwork(urls[0]); 
  8.     } 
  9.     
  10.     /** The system calls this to perform work in the UI thread and delivers 
  11.       * the result from doInBackground() */ 
  12.     protected void onPostExecute(Bitmap result){ 
  13.         mImageView.setImageBitmap(result); 
  14.     }} 

現(xiàn)在UI是安全的了,代碼也更加簡(jiǎn)單了,因?yàn)锳syncTask把worker線程里做的事和UI線程里要做的事分開(kāi)了。

你應(yīng)該閱讀一下 AsyncTask 的參考文檔以便更好的使用它。下面就是一個(gè)對(duì) AsyncTask 如何作用的快速的總覽:

注意: 你在使用worker線程的時(shí)候可能會(huì)碰到的另一個(gè)問(wèn)題就是因?yàn)?a >runtime configuration change (比如用戶改變了屏幕的方向)導(dǎo)致你的activity不可預(yù)期的重啟,這可能會(huì)kill掉你的worker線程。為了解決這個(gè)問(wèn)題你可以參考 Shelves 這個(gè)項(xiàng)目。

線程安全的方法

在某些情況下,你實(shí)現(xiàn)的方法可能會(huì)被多個(gè)線程所調(diào)用,因此你必須把它寫(xiě)出線程安全的。

[[124306]]

文地址:Android的進(jìn)程與線程

責(zé)任編輯:閆佳明 來(lái)源: greenrobot.me
相關(guān)推薦

2018-07-06 14:00:55

Linux進(jìn)程線程

2018-05-31 10:57:31

Linux系統(tǒng)進(jìn)程線程

2015-09-08 15:13:35

Android進(jìn)程與線程

2009-09-16 08:43:51

linux進(jìn)程線程

2012-05-04 09:49:34

進(jìn)程

2021-05-21 09:36:42

開(kāi)發(fā)技能代碼

2022-06-07 07:37:40

線程進(jìn)程開(kāi)發(fā)

2022-02-07 11:55:00

linux進(jìn)程線程

2022-05-26 08:31:41

線程Java線程與進(jìn)程

2019-06-03 09:13:11

線程進(jìn)程多線程

2013-04-25 09:55:21

進(jìn)程線程

2012-06-20 14:07:28

多線程架構(gòu)單線程

2011-07-25 10:00:59

項(xiàng)目

2019-02-26 11:15:25

進(jìn)程多線程多進(jìn)程

2019-09-18 15:09:50

進(jìn)程線程操作系統(tǒng)

2022-10-12 09:01:52

Linux內(nèi)核線程

2021-06-11 11:28:22

多線程fork單線程

2025-05-06 09:12:46

2023-03-05 16:12:41

Linux進(jìn)程線程

2017-09-11 15:35:43

AndroidInput系統(tǒng)框架
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)