當前位置:首頁 » 安卓系統 » android更新ui

android更新ui

發布時間: 2023-03-02 11:22:14

⑴ android 怎樣發送廣播更新ui

更新ui 可以直接在主線程里操作。一般用不到廣播。如果非要用廣播,一般都是服務更新線程才這么做。在服務里注冊/發送廣播。然後在ui線程里接受廣播,執行更新操作。

⑵ Android UI線程

思考:

先必須了解下面2個問題
1.顧名思義 UI線程 就是刷新UI 所在線程
2.UI是單線程刷新

1.對Activity 來說 UI線程就是其主線程
2.對View來說 UI線程就是創建ViewRootImpl所在的線程
可以通過 WindowManager 內部會創建ViewRootImpl對象

好了,進入主題。我們來慢慢揭開面紗。
我們可以分別從幾個方面切入

我們可能都有使用過 runOnUiThread 現在來看看的源碼實現。

可以從上面的源碼 看到
不是UI線程 就用Handler切到Handler所在的線程中,如果是UI線程直接就調用run方法。

Activity的創建:
1.Activity創建:mInstrumentation.newActivity
2.創建Context :ContextImpl (r)

我們經常用這個方法乾的事情就是,要麼在onCreate中獲取View寬高的值。要麼就是在子線程中做一些耗時操作 ,然後post切到對應View所在的線程 來繪制UI操作。那麼這個對應的線程就是UI線程了。
那麼這個UI線程就一定是主線程嗎?
接來繼續來看。它的源碼View:post

mAttachInfo 在dispatchAttachedToWindow 中被賦值 ,也就是在ViewRootImpl創建的時候,所以是創建ViewRootImpl所在的線程。
attachInfo 上面時候為null 呢?在ViewRootImpl 還沒來得及創建的時候,ViewRootImpl 創建是在 「onResume" 之後。所以在 Activity 的 onCreate 去View.post 那麼AttachInfo 是為null 。
當 AttachInfo == null 那麼會調用 getRunQueue().post(action) 。
最終這個Runnable 被 緩存到 HandlerActionQueue 中。
直到ViewRootImpl 的 performTraversals 中 調用dispatchAttachedToWindow(mAttachInfo, 0);, 那麼才會去處理 RunQueue() 中的Runnable。

來張圖 便於理解這個流程

我們有時候去子線程操作UI的時候(如:requestLayout),會很經常見到下面的 報錯日誌:
Only the original thread that created a view hierarchy can touch its views

為什麼會報這個錯誤呢?
翻譯一下:只有創建視圖層次結構的原始線程才能接觸到它的視圖。
也就是操作UI的線程要和ViewRootImpl創建的線程是同一個線程才行,並不是只有主線程才能更新UI啊。
ViewRootImpl創建的線程?那麼 ViewRootImpl 在哪裡被創建的呢?

從上圖可以看到ViewRootImpl創建最開始是從 ActivityThread 的HandleResumeActivity中開始 一直 ViewRootImpl 創建,也就是說ViewRootImpl 對應的UI線程和 ActivityThread 在同一個線程 也就是主線程。

好了 通過上面的講解,上面的問題相信你可以自己回答啦~

⑶ android通過Handler使子線程更新UI

在Android項目中經常有碰到這樣的問題,在子線程中完成耗時操作之後要更新UI,下面就自己經歷的一些項目總結一下更新的方法。

一. 引言

首先來看一下android中消息機制:

專業術語:

Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。
Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper。
Thread:線程,負責調度整個消息循環,即消息循環的執行場所。

二. 方法

1. 用Handler

(1)主線程中定義Handler:

java代碼:

[java]view plain

HandlermHandler=newHandler(){

@Override

publicvoidhandleMessage(Messagemsg){

super.handleMessage(msg);

switch(msg.what){

case0:

<spanstyle="color:#009900;">//完成主界面更新,拿到數據</span>

Stringdata=(String)msg.obj;

updateWeather();

textView.setText(data);

break;

default:

break;

}

}

};

(2)子線程發消息,通知Handler完成UI更新:

java代碼:

privatevoipdateWeather(){

newThread(newRunnable(){

@Override

publicvoidrun(){

<spanstyle="color:#009900;">//耗時操作,完成之後發送消息給Handler,完成UI更新;</span>

mHandler.sendEmptyMessage(0);

<spanstyle="color:#33cc00;">//需要數據傳遞,用下面方法;</span>

Messagemsg=newMessage();

msg.obj="數據";<spanstyle="color:#33cc00;">//可以是基本類型,可以是對象,可以是List、map等;</span>

mHandler.sendMessage(msg);

}

}).start();

}

注意:Handler對象必須定義在主線程中,如果是多個類直接互相調用,就不是很方便,需要傳遞content對象或通過介面調用。

2.用Activity對象的runOnUiThread方法更新

在子線程中通過runOnUiThread()方法更新UI:

java代碼:

newThread(){

publicvoidrun(){

<spanstyle="color:#009900;">//這兒是耗時操作,完成之後更新UI;</span>

runOnUiThread(newRunnable(){

@Override

publicvoidrun(){

<spanstyle="color:#009900;">//更新UI</span>

imageView.setImageBitmap(bitmap);

}

});

}

}.start();

如果在非上下文類中,可以通過傳遞上下文實現調用:

java代碼:

Activityactivity=(Activity)imageView.getContext();

activity.runOnUiThread(newRunnable(){

@Override

publicvoidrun(){

imageView.setImageBitmap(bitmap);

}

});

注意:這種方法使用比較靈活,但如果Thread定義在其他地方,需要傳遞Activity對象。


3.
View.post(Runnable r)

java代碼:

imageView.post(newRunnable(){

@Override

publicvoidrun(){

imageView.setImageBitmap(bitmap);

}

});

這種方法更簡單,但需要傳遞要更新的View過去。

總結:UI的更新必須在主線程中完成,所以不管上述那種方法,都是將更新UI的消息發送到了主線程的消息對象,讓主線程做處理。

⑷ Android——消息分發機制

什麼是 Handler 機制 ?
Handler 機制是 Android 中用於 線程間通信 的一套通信機制。

為什麼是 Handler ?Handler 機制為什麼被那麼多次的提及 ?
從Android4.0開始,Android 中網路請求強制不允許在主線程中操作,而更新UI的操作則不允許在子線程中執行。當在子線程中執行網路請求,拿到伺服器返回的數據之後,要更新UI。由於系統的要求,勢必會產生一種矛盾:數據在子線程,更新UI要在主線程。此時我們必須要把數據返回到主線程中才行,Handler機制應運而生。

Android 中針對耗時的操作,放在主線程操作,輕者會造成 UI 卡頓,重則會直接無響應,造成 Force Close。同時在 Android 3.0 以後,禁止在主線程進行網路請求。

針對耗時或者網路操作,那就不能在主線程進行直接操作了,需要放在子線程或者是工作線程中進行操作,操作完成以後,再更新主線程即 UI 線程。這里就涉及到一個問題了,在子線程執行完成以後,怎麼能更新到主線程即 UI 線程呢,針對以上問題,就需要用到 Android 的消息機制了,即: Handler, Message, MessageQueue, Looper 全家桶

Handler機制中最重要的四個對象

Handler的構造方法:

Looper :

Handler的使用:

MessageQueue:

Looper.loop()

Handler.dispatchMessage()

handler導致activity內存泄露的原因:
handler發送的消息在當前handler的消息隊列中,如果此時activity finish掉了,那麼消息隊列的消息依舊會由handler進行處理,若此時handler聲明為內部類(非靜態內部類),我們知道內部類天然持有外部類的實例引用,這樣在GC垃圾回收機制進行回收時發現這個Activity居然還有其他引用存在,因而就不會去回收這個Activity,進而導致activity泄露。

假如在子線程執行了耗時操作,這時用戶操作進入了其他的 acitvity, 那麼 MainActivity 就會被內存回收的,但是這個時候發現 Handler 還在引用著 MainActivity,內存無法及時回收,造成內存泄漏。

Handler 防止內存泄漏常見方法:

為什麼通過 Handler 可以把子線程的結果通知或者攜帶給 UI 線程 ?
這里的 Handler 指的是主線程的 Handler ,同時與 Handler 配套的 Looper , MessageQueue 是在 UI 線程初始化的,所以在子線程中調用 Handler 發送消息可以更新 UI 線程。
Looper 在 UI 線程源碼, 在 ActivityThread 類:

⑸ android中如何實現UI的實時更新

1、在主線程中啟動一個子線程

首先,我們需要在主線程中啟動一個子線程,這個比較簡單,直接在MainActivity的onCreate()方法中調用如下方法即可:

newThread(mRunnable).start();

2、在子線程中發送Message給Handler

在創建子線程時,我們使用了Runnable介面對象mRunnable。這里,只需要實現Runnable介面,並重寫該介面的run()方法,在run()方法中實現每1秒發送一條Message給Handler即可。具體實現方法如下:

/*
*Function:實現run()方法,每1秒發送一條Message給Handler
*/
privateRunnablemRunnable=newRunnable(){
publicvoidrun(){
while(true){
try{
Thread.sleep(1000);
mHandler.sendMessage(mHandler.obtainMessage());
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
};

3、Handler接收Message通知

最後,我們創建一個Handler對象,用來接收Message通知。在收到Message通知後,完成刷新UI的操作即可。具體實現方法如下:

/*
*Function:實現handleMessage()方法,用於接收Message,刷新UI
*/
privateHandlermHandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
refreshUI();
}
};

4、刷新UI

由以上的代碼可以看出,刷新UI的操作,我們是放在refreshUI()方法中來完成的。refreshUI()方法的實現也很簡單,調用HttpUtils工具類中的getInputStream()方法,獲得圖1所示Web工程的頁面內容輸入流,再將該輸入流轉化為字元串,放入TextView控制項中進行顯示即可。具體實現方法如下:

/*
*Function:刷新UI
*/
privatevoidrefreshUI(){
try{
InputStreaminputStream=HttpUtils.getInputStream();
StringresultData=HttpUtils.getResultData(inputStream);
mTextView.setText(resultData);
}catch(IOExceptione){
e.printStackTrace();
}
}

⑹ 如何在Android開發中用AsyncTask非同步更新UI界面

1
本次的非同步處理的一種方式AsyncTask,其實它的本質是一個線程池,所有提交的非同步任務都會在這個線程池中的工作線程內執行,當工作線程需要跟UI線程交互時,工作線程會通過向在UI線程創建的Handler傳遞消息的方式,調用相關的回調函數,從而實現UI界面的更新。

2
AsyncTask抽象出後台線程運行的五個狀態,分別是:1、准備運行,2、正在後台運行,3、進度更新,4、完成後台任務,5、取消任務,對於這五個階段,AsyncTask提供了五個回調函數:其中,准備運行:onPreExecute(),該回調函數在任務被執行之後立即由UI線程調用。這個步驟通常用來建立任務,在用戶介面(UI)上顯示進度條;

3
doInBackground(Params...),該回調函數由後台線程在onPreExecute()方法執行結束後立即調用。通常在這里執行耗時的後台計算。計算的結果必須由該函數返回,並被傳遞到onPostExecute()中。在該函數內也可以使用publishProgress(Progress...)來發布一個或多個進度單位(unitsof progr ess)。這些值將會在onProgressUpdate(Progress...)中被發布到UI線程;

4
完成後台任務:onPostExecute(Result),當後台計算結束後調用。後台計算的結果會被作為參數傳遞給這一函數;

5
最後在程序中啟動該非同步代碼;

⑺ android怎麼更新UI

首先,android的UI刷新是在主線程(UI線程)中完成的。四大組件中,activity和service運行在主線程中。現在總結自己在項目中常用到的UI刷新方式。
第一,利用子線程發消息刷新UI。
子線程負責處理UI需要的數據,然後發消息到主線程來刷新UI。代碼結構如下:
new Thread(new Runnable() {

@Override
public void run() {
Person person=new Person();
person.setName(mName.getText().toString().trim());
person.setPhone(mPhone.getText().toString().trim());
Log.i("person",person.toString());
DatabaseInfoFactory.getPersonDao(mContext).addPerson(person);
Looper.prepare();
Message msg=Message.obtain();
msg.what=0x123456;
handler.sendMessage(msg);
Looper.loop();

}
}).start();
主線程中:
private Handler mHandler=new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.what==0x123456||msg.what==0x123){
fillData();
setListener();
}

}
};
第二,利用非同步任務更新UI。代碼結構如下:
new AsyncTask<void,void,void>() {

@Override
protected void onPostExecute(Void result) {

if(mAdapter==null){
mAdapter=new LeaveInfoAdapter();
//設置數據適配器
mLVleaveInfos.setAdapter(mAdapter);
Log.i("測試", "非同步任務顯示後台獲得資料庫數據");
}
else {
mAdapter.notifyDataSetChanged();

}

super.onPostExecute(result);
}

@Override
protected Void doInBackground(Void... params) {
//獲得要顯示的數據
mleaveInfos=mLeaveInfosDao.findAll();
if (mleaveInfos==null) {
Toast.makeText(HomeActivity.this,"請假數據不存在或是已經清除!", 500).show();

}

Log.i("測試", "非同步任務後台獲得資料庫數據"+mleaveInfos.size());

return null;
}
}.execute();</void,void,void>
第三,利用配置文件+activity的生命周期方法刷新UI。

⑻ Android service 可以直接更新UI嗎

就算是在Activity的開啟的新線程中也是無法直接更新UI的,若這樣做會導致應用崩潰,Android限制要求在UI線程中即主線程中才能更新UI,這樣做的目的是為了防止多線程同時修改同一個控制項導致各種問題的產生,若要在其他新建的線程中更新UI需要藉助API中提供的handler。

原理大致為在主線程中實現處理特定消息的介面,然後在其他地方使用handler發送自己定義的消息,當主線程接收到消息後,你就可以根據消息的內容更新UI了。

當然也有特例,如SurfaceView就支持在新線程中修改UI。service屬於後台與Avtivity屬於不同的組件,運行在不同的線程下,它的設計不是為了處理界面的,所以不建議這么做。

下面是幾個可行的方法:

  1. 通過廣播,即在 Activity中注冊一個廣播,然後通過廣播進行service和Activity間的數據傳遞,同時以達到更新UI的目的。

  2. 通過繼承Binder類和一個回調方法實現對view的更新。當然如果不要回調方法也可以,那就直接在handleMessage()中進行數據更新也是可以。

⑼ Android 在子線程中更新UI的幾種方法示例

請您慢慢看:

直接在UI線程中開啟子線程來更新TextView顯示的內容,運行程序我們會發現,如下錯誤:android.view.ViewRoot$: Only the original thread that created a view hierarchy can touch its views.翻譯過來就是:只有創建這個控制項的線程才能去更新該控制項的內容。

所有的UI線程要去負責View的創建並且維護它,例如更新冒個TextView的顯示,都必須在主線程中去做,我們不能直接在UI線程中去創建子線程,要利用消息機制:handler,如下就是handler的簡單工作原理圖:

既然android給我們提供了Handler機制來解決這樣的問題,請看如下代碼:

public class HandlerTestActivity extends Activity { private TextView tv; private static final int UPDATE = 0; private Handler handler = new Handler() { @Overridepublic void handleMessage(Message msg) { // TODO 接收消息並且去更新UI線程上的控制項內容if (msg.what == UPDATE) { // Bundle b = msg.getData();// tv.setText(b.getString("num")); tv.setText(String.valueOf(msg.obj)); } super.handleMessage(msg); } }; /** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); tv = (TextView) findViewById(R.id.tv); new Thread() { @Overridepublic void run() { // TODO 子線程中通過handler發送消息給handler接收,由handler去更新TextView的值try { for (int i = 0; i < 100; i++) { Thread.sleep(500); Message msg = new Message(); msg.what = UPDATE; // Bundle b = new Bundle();// b.putString("num", "更新後的值:" + i);// msg.setData(b); msg.obj = "更新後的值:" + i; handler.sendMessage(msg); } } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }}

我們就通過Handler機制來處理了子線程去更新UI線程式控制制項問題,Andrid開發中要經常用到這種機制。

熱點內容
python練手項目 發布:2025-05-12 11:14:07 瀏覽:121
壓縮聽算音頻 發布:2025-05-12 10:58:12 瀏覽:800
資料庫系統報告 發布:2025-05-12 10:43:17 瀏覽:602
日產高配有哪些配置 發布:2025-05-12 10:32:16 瀏覽:475
大眾朗逸哪個配置值得入手 發布:2025-05-12 10:31:20 瀏覽:505
壓縮包的後綴 發布:2025-05-12 10:20:35 瀏覽:940
煙台招聘編程 發布:2025-05-12 10:04:21 瀏覽:53
sql查詢所有表名 發布:2025-05-12 10:01:28 瀏覽:665
用python編譯器的簡單代碼 發布:2025-05-12 09:48:40 瀏覽:358
香港多ip站群伺服器租用 發布:2025-05-12 09:33:16 瀏覽:896