導航:首頁 > 操作系統 > AndroidUI線程安全

AndroidUI線程安全

發布時間:2022-09-21 17:19:07

1. UI為什麼不是線程安全的

很好理解,先說說什麼是線程安全,線程安全就是多個線程同時運行一段代碼,運行結果不能存在二義性和不確定性,和單線程結果一樣,就是線程安全的。 否則就不是,就需要考慮線程同步。

UI 就好比畫板, 假如兩個畫家同時畫, 你想畫這樣畫,我想那樣畫,那如何的了。所以操作系統保證,一個界面同一時間只能有一個操作,其他操作將被阻塞。 包括windows, linux, android 所有UI肯定都不是線程安全的。

2. 在android中使用service時,需要注意哪些事項

我們都知道Android是單線程模型,這意味著Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行,所以你單純的new一個Thrad並且start()不行的,因為這違背了Android的單線程模型。
很幸運的是Android為我們提供了在其他線程中訪問UI線程的方法,相信大家都見過,這幾個就是Activity的runOnUiThread方法,View的post和postDelayed方法,以及最常用的Hanlder和AsyncTask,這里我推薦使用Hanlder和AsyncTask,尤其是AsyncTask,因為使用他們你會發現你的代碼很容易被理解,因為他們都有一些具有特定職責的方法,尤其是AsyncTask,有預處理的方法onPreExecute,有後台執行任務的方法doInBackground,有更新進度的方法publishProgress,有返回結果的方法onPostExecute等等,這就不像post這些方法,把所有的操作都一大坨的寫在一個Runnable里。
有了Android為我們提供了這些方法我們就可以很好的解決一些長時間處理的任務了,但是在使用的時候我們還必須注意以下幾點:

這些方法或者類必須在在UI線程中創建和調用
其實這些方法和類最終的實現都是Android的Message、MessageQueue和Looper的機制,所以不要期待你會馬上看到結果(效果),因為這是一個Loop一直循環出MessageQueue中的Message執行的過程,如果你沒有看到效果,那麼等等吧,因為還沒有輪到你。
有線程(多個)的地方就會有並發,會有資源共享沖突,所以在使用的時候謹慎點吧,說不準你的一個線程中使用的變數已經被另一個線程改的面目全非了

3. Android進程和線程的區別

Android進程和線程的區別

下面我先介紹下Android進程和線程各是什麼,然後再一一比較區別下

  1. Android進程基本知識:

    當一個程序第一次啟動的時候,Android會啟動一個LINUX進程和一個主線程。默認的情況下,所有該程序的組件都將在該進程和線程中運行。 同時,Android會為每個應用程序分配一個單獨的LINUX用戶。Android會盡量保留一個正在運行進程,只在內存資源出現不足時,Android會嘗試停止一些進程從而釋放足夠的資源給其他新的進程使用, 也能保證用戶正在訪問的當前進程有足夠的資源去及時地響應用戶的事件。

    我們可以將一些組件運行在其他進程中,並且可以為任意的進程添加線程。組件運行在哪個進程中是在manifest文件里設置的,其中<Activity>,<Service>,<receiver>和<provider>都有一個process屬性來指定該組件運行在哪個進程之中。我們可以設置這個屬性,使得每個組件運行在它們自己的進程中,或是幾個組件共同享用一個進程,或是不共同享用。<application>元素也有一個process屬性,用來指定所有的組件的默認屬性。


    Android中的所有組件都在指定的進程中的主線程中實例化的,對組件的系統調用也是由主線程發出的。每個實例不會建立新的線程。對系統調用進行響應的方法——例如負責執行用戶動作的View.onKeyDown()和組件的生命周期函數——都是運行在這個主線程中的。這意味著當系統調用這個組件時,這個組件不能長時間的阻塞主線程。例如進行網路操作時或是更新UI時,如果運行時間較長,就不能直接在主線程中運行,因為這樣會阻塞這個進程中其他的組件,我們可以將這樣的組件分配到新建的線程中或是其他的線程中運行。

    Android會根據進程中運行的組件類別以及組件的狀態來判斷該進程的重要性,Android會首先停止那些不重要的進程。按照重要性從高到低一共有五個級別:


    1.1前台進程

    前台進程是用戶當前正在使用的進程。只有一些前台進程可以在任何時候都存在。他們是最後一個被結束的,當內存低到根本連他們都不能運行的時候。一般來說, 在這種情況下,設備會進行內存調度,中止一些前台進程來保持對用戶交互的響應。

    1.2可見進程

    可見進程不包含前台的組件但是會在屏幕上顯示一個可見的進程是的重要程度很高,除非前台進程需要獲取它的資源,不然不會被中止。

    1.3服務進程

    運行著一個通過startService() 方法啟動的service,這個service不屬於上面提到的2種更高重要性的。service所在的進程雖然對用戶不是直接可見的,但是他們執行了用戶非常關注的任務(比如播放mp3,從網路下載數據)。只要前台進程和可見進程有足夠的內存,系統不會回收他們。


    1.4後台進程

    運行著一個對用戶不可見的activity(調用過 onStop() 方法).這些進程對用戶體驗沒有直接的影響,可以在服務進程、可見進程、前台進 程需要內存的時候回收。通常,系統中會有很多不可見進程在運行,他們被保存在LRU (least recently used) 列表中,以便內存不足的時候被第一時間回收。如果一個activity正 確的執行了它的生命周期,關閉這個進程對於用戶體驗沒有太大的影響。


    1.5空進程

    未運行任何程序組件。運行這些進程的唯一原因是作為一個緩存,縮短下次程序需要重新使用的啟動時間。系統經常中止這些進程,這樣可以調節程序緩存和系統緩存的平衡。


  2. 單線程模型

    線程在代碼是使用標準的java Thread對象來建立,那麼在Android系統中提供了一系列方便的類來管理線程——Looper用來在一個線程中執行消息循環,Handler用來處理消息,HandlerThread創建帶有消息循環的線程。具體可以看下面的詳細介紹。

    當一個程序第一次啟動時,Android會同時啟動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,如用戶的按鍵事件,用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。

    在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。


2.1 子線程更新UI Android的UI是單線程(Single-threaded)的。

為了避免拖住GUI,一些較費時的對象應該交給獨立的線程去執行。如果幕後的線程來執行UI對象,Android就會發出錯誤訊息 。以後遇到這樣的異常拋出時就要知道怎麼回事了!

2.2 Message Queue

在單線程模型下,為了解決類似的問題,Android設計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue並結合Handler和Looper組件進行信息交換。下面將對它們進行分別介紹:


2..3 Message 消息

理解為線程間交流的信息,處理數據後台線程需要更新UI,則發送Message內含一些數據給UI線程。

2.4. Handler 處理者

是Message的主要處理者,負責Message的發送,Message內容的執行處理。後台線程就是通過傳進來的Handler對象引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message) 方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。


2.5. Message Queue 消息隊列

用來存放通過Handler發布的消息,按照先進先出執行。 每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法發送消息:sendMessage或post。這兩種消息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法發送的消息執行的方式略有不同:通過sendMessage發送的是一個message對象,會被Handler的handleMessage()函數處理;而通過post方法發送的是一個runnable對象,則會自己執行。

2.6 Looper Looper是每條線程里的Message Queue的管家。

Android沒有Global的Message Queue,而Android會自動替主線程(UI線程)建立Message Queue,但在子線程里並沒有建立Message Queue。所以調用Looper.getMainLooper()得到的主線程的Looper不為NULL,但調用Looper.myLooper()得到當前線程的Looper就有可能為NULL。


從以上幾點,不難看出Android進程和線程的二者的區別所在。

4. android 中Bn 和Bp的區別

Bn意味著Binder Native 端
Bp是Binder Proxy端,
這兩端會實現相同的介面,但Proxy端只是通過binder ipc發送一個binder transaction,
native端是真正做事情,再將結果返回。
Android用此機制實現高效的遠程調用。

5. 為什麼還說Android的UI操作並不是線程安全的

看到題主的問題,就明白了。是因為性能考慮。線程安全性能較差,線程不安全性能較好。
所以Android選擇線程不安全。
Android主線程要注意的兩點:
1.不要阻塞主線程
2.不要在其他線程調用UI操作方法(Android UI toolkit)
大概也就是這樣

6. Android:在一個非主線程內直接調用UI線程的Handler實例,這樣沒問題嗎

我們開發應用程序的時候,處於線程安全的原因子線程通常是不能直接更新主線程(UI線程)中的UI元素的,那麼在Android開發中有幾種方法解決這個問題,其中方法之一就是利用Handler處理的。

下面說下有關Handler相關的知識。
多線程一些基礎知識回顧:
在介紹Handler類相關知識之前,我們先看看在Java中是如何創建多線程的
方法有兩種:
通過繼承Thread類,重寫Run方法來實現
通過繼承介面Runnable實現多線程

接下來讓我們看看Handler是什麼?如何來用

Handler是這么定義的:
主要接受子線程發送的數據, 並用此數據配合主線程更新UI.

Handler的主要作用:主要用於非同步消息的處理

Handler的運行過程:
當(子線程)發出一個消息之後,首先進入一個(主線程的)消息隊列,發送消息的函數即刻返回,而在主線程中的Handler逐個的在消息隊列中將消息取出,然後對消息進行處理。這樣就實現了跨線程的UI更新(實際上還是在主線程中完成的)。
這種機制通常用來處理相對耗時比較長的操作,如訪問網路比較耗時的操作,讀取文大文件,比較耗時的操作處理等。

在大白話一點的介紹它的運行過程:
啟動應用時Android開啟一個主線程 (也就是UI線程) , 如果此時需要一個耗時的操作,例如: 聯網讀取數據,或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,界面會出現假死現象(這也就是你在主線程中直接訪問網路時會提示你異常的原因,如我們上篇文章所述Android主線程不能訪問網路異常解決辦法
)。
這個時候我們需要把這些耗時的操作,放在一個子線程中,因為子線程涉及到UI更新,Android主線程是線程不安全的,更新UI只能在主線程中更新.。
這個時候,Handler就出現了,來解決這個復雜的問題,由於Handler運行在主線程中(UI線程中), 它與子線程可以通過Message對象來傳遞數據, 這個時候,Handler就承擔著接受子線程傳過來的(子線程用sedMessage()方法傳弟)Message對象,(裡麵包含數據) , 把這些消息放入主線程隊列中,配合主線程進行更新UI。

接下來我們看看關於Handler都有哪些方法(它都能幹什麼):
其中Handler對象的一些主要方法,如下:

post(Runnable) postAtTime(Runnable,long)

postDelayed(Runnable long)

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

正如方法名字中看到的,有兩類方法:

(1)在某個主線程中執行Runnable
(2)在子線程中發送一個消息,在主線程中檢測該消息處理

線程間傳遞Message對象的sendMessage方法和發送Runnable多線程對象的post方法。正對應著上面所說的兩個特性1)、2)

下面開發個Handler實例做說明:
用post的方法執行一個Runnable對象,在該對象中隨機產生一個10-100之間的隨機數,賦值到UI主線程中的TextView中線程,執行5次,每次相隔5秒, 拼接每次的數字, 最後執行結果應該如:10 22 33 44 61

主要代碼如下:
int i = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler.post(run);
}

Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
String s = String.valueOf(msg.what);
TextView tv = (TextView)findViewById(R.id.textView);
tv.setText(tv.getText() + 」 」 + s);
}
};

Runnable run = new Runnable(){
@Override
public void run(){
Random r = new Random();
int rnum = r.nextInt((100 – 10) + 1) + 10;
handler.sendEmptyMessage(rnum);
handler.postDelayed(run, 5000);
i++;
if (i==5){
handler.removeCallbacks(run);
}
}
};

7. 為什麼說Android主線程是線程不安全的,既然不安全為什麼要在主線程中更新UI,有點暈 求大師解答

UI線程及Android的單線程模型原則當應用啟動,系統會創建一個主線程(main thread)。這個主線程負責向UI組件分發事件(包括繪制事件),也是在這個主線程里,應用和Android的UI組件(components from the Android UI toolkit (components from the android.widget and android.view packages))發生交互。

當App做一些比較重(intensive)的工作的時候,除非合理地實現,否則單線程模型的performance會很poor。特別的是,如果所有的工作都在UI線程,做一些比較耗時的工作比如訪問網路或者資料庫查詢,都會阻塞UI線程,導致事件停止分發(包括繪制事件)。對於用戶來說,應用看起來像是卡住了,更壞的情況是,如果UI線程blocked的時間太長(大約超過5秒),用戶就會看到ANR(application not responding)的對話框。

另外,Andoid UI toolkit並不是線程安全的,所以不能從非UI線程來操縱UI組件。必須把所有的UI操作放在UI線程里,所以Android的單線程模型有兩條原則:
1.不要阻塞UI線程。
2.不要在UI線程之外訪問Android UI toolkit(主要是這兩個包中的組件:android.widget and android.view)。

8. android 怎麼處理線程安全

UI線程及Android的單線程模型原則當應用啟動,系統會創建一個主線程(main thread)。這個主線程負責向UI組件分發事件(包括繪制事件),也是在這個主線程里,應用和Android的UI組件(components from the Android UI toolkit (components from the android.widget and android.view packages))發生交互。 當App做一些比較重(intensive)的工作的時候,除非合理地實現,否則單線程模型的performance會很poor。特別的是,如果所有的工作都在UI線程,做一些比較耗時的工作比如訪問網路或者資料庫查詢,都會阻塞UI線程,導致事件停止分發(包括繪制事件)。對於用戶來說,應用看起來像是卡住了,更壞的情況是,如果UI線程blocked的時間太長(大約超過5秒),用戶就會看到ANR(application not responding)的對話框。 另外,Andoid UI toolkit並不是線程安全的,所以不能從非UI線程來操縱UI組件。必須把所有的UI操作放在UI線程里,所以Android的單線程模型有兩條原則: 1.不要阻塞UI線程。 2.不要在UI線程之外訪問Android UI toolkit(主要是這兩個包中的組件:android.widget and android.view)。

9. android中Invalidate和postInvalidate的區別

Android中實現view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,其中前者是在UI線程自身中使用,而後者在非UI線程中使用。
Android提供了Invalidate方法實現界面刷新,但是Invalidate不能直接在線程中調用,因為他是違背了單線程模型:Android UI操作並不是線程安全的,並且這些操作必須在UI線程中調用。

1,利用invalidate()刷新界面

實例化一個Handler對象,並重寫handleMessage方法調用invalidate()實現界面刷新;而在線程中通過sendMessage發送界面更新消息。

{
privateViewview;
publicclassHandlerhandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
view.invalidate();//刷新界面
}
}
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
newThread(){
publicvoidrun(){
handler.sendEmptyMessage();
}
}.start();

}


2,使用postInvalidate()刷新界面 ,使用postInvalidate則比較簡單,不需要handler,直接在線程中調用postInvalidate即可。

{
privateViewview;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
newThread(){
publicvoidrun(){
view.postInvalidate();
}
}.start();

}


兩個方法都有重載函數,用於刷新指定區域的內容

public void invalidate(int l, int t, int r, int b) ;

public void invalidate(Rect dirty) ;

public void postInvalidate(int l, int t, int r, int b) ;

public void postInvalidate(Rect dirty) ;

此外postInvalidate還支持延遲刷新,

public void postInvalidateDelayed(long delayMilliseconds)

讓視圖在指定時間後刷新

閱讀全文

與AndroidUI線程安全相關的資料

熱點內容
浙江標准網路伺服器機櫃雲主機 瀏覽:585
設置網路的伺服器地址 瀏覽:600
java圖形界面設計 瀏覽:751
純前端項目怎麼部署到伺服器 瀏覽:538
瓜子臉程序員 瀏覽:505
如何保證伺服器優質 瀏覽:94
小微信aPP怎麼一下找不到了 瀏覽:299
演算法纂要學術價值 瀏覽:975
程序員你好是什麼意思 瀏覽:801
倩女幽魂老伺服器如何玩 瀏覽:561
電子鍾單片機課程設計實驗報告 瀏覽:999
看加密頻道 瀏覽:381
程序員算不算流水線工人 瀏覽:632
三星電視我的app怎麼卸載 瀏覽:44
簡述vi編譯器的基本操作 瀏覽:507
讓程序員選小號 瀏覽:91
加強數字貨幣國際信息編譯能力 瀏覽:584
購買的app會員怎麼退安卓手機 瀏覽:891
程序員的種類及名稱 瀏覽:293
美國程序員薪資 瀏覽:13