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

android線程更新ui

發布時間: 2022-07-08 22:33:06

① 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更新Ui的幾種方法和見解

  1. 利用Looper更新UI界面

  2. 2.AsyncTask利用線程任務非同步更新UI界面

  3. 3.利用Runnable更新UI界面

③ 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 在子線程中更新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開發中要經常用到這種機制。

⑤ 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一條單獨線程,更新ui

方法有兩種:
通過繼承Thread類,重寫Run方法來實現
通過繼承介面Runnable實現多線程
主要接受子線程發送的數據, 並用此數據配合主線程更新UI.

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

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

在大白話一點的介紹它的運行過程:
啟動應用時Android開啟一個主線程
(也就是UI線程) , 如果此時需要一個耗時的操作,例如:
聯網讀取數據,或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,界面會出現假死現象(這也就是你在主線程中直接訪問網路時會提示你異常的原因,如我們上篇文章所述Android主線程不能訪問網路異常解決辦法)。

⑦ 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怎麼樣在子線程實例化的handler去更新UI

之前用過android-async-http,雖然沒認真看過源碼,但也有簡單的瀏覽過,心裡一直有個疑問,因為android-async-http也是採用hanlder機制來執行回調的,也就是說handler是它實例化的,可我們知道handler的一個重要作用是將一個任務切換到handler所在的線程去執行的,我的疑問就是:如果我們在子線程調用android-async-http的網路請求,這時候如果handler是在子線程被實例化的呢(當然我沒認真研究過源碼,也不知道它是怎麼實現),還能更新UI嗎?
我們都正常以為handler在哪個線程實例化的,我們通過handler就可以把任務切換到該任務去執行,我們看如下代碼:

private void initd() {

new Thread(new Runnable() {

@Override

public
void run() {

Looper.prepare();

Handler handler = new
Handler() {

@Override

public void handleMessage(Message msg) {

Toast.makeText(MainActivity.this, "測試子線程彈出toast",
Toast.LENGTH_LONG).show();

((TextView)findViewById(R.id.main_tv_text)).setText("測試子線程");

}

};

Looper.loop();

handler.sendEmptyMessage(0);

}

}).start();

}

經過我的測試上面這段方法是無法更新UI的,因為handler是在子線程實例化的,並非在UI線程,也證實了我們的想法。

如果我的疑問存在(我沒嘗試過在子線程使用android-async-http,不知道什麼情況,這里只是做個假設),那麼它使怎麼實現的呢。

最近看了android開發藝術探索,特意去研究了一下android的消息機制,才弄明白了Handler的工作原理,其實起關鍵作用的是Looper並不是handler,我們先來看下Looper的構造方法:

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

Looper會把所在的當前的線程保存起來,而handler的工作需要Looper,於是我嘗試了一下如下代碼:

private void init() {

new Thread(new Runnable() {

@Override

public
void run() {

Handler handler = new
Handler(Looper.getMainLooper()) {

@Override

public void handleMessage(Message msg) {

Toast.makeText(MainActivity.this, "測試子線程彈出toast",
Toast.LENGTH_LONG).show();

((TextView)findViewById(R.id.main_tv_text)).setText("測試子線程");

}

};

handler.sendEmptyMessage(0);

}

}).start();

}

handler實例化的時候,我傳入的是UI線程的Looper,確實是可以更新UI。

總結:

1、handler執行任務不是在它實例化所在的線程決定的,而是關鍵在於Looper。

2、我們可以在子線程實例化handler並且可以用它來更新UI了。

熱點內容
雙面警長第一季ftp 發布:2025-05-16 11:41:20 瀏覽:664
php取數組第一個 發布:2025-05-16 11:30:58 瀏覽:423
解調演算法 發布:2025-05-16 11:21:09 瀏覽:136
python密碼暴力破解 發布:2025-05-16 11:13:28 瀏覽:592
倒角刀編程 發布:2025-05-16 11:12:55 瀏覽:350
資料庫的酸性 發布:2025-05-16 11:03:17 瀏覽:124
phpmysql長連接 發布:2025-05-16 10:51:50 瀏覽:734
android橫屏全屏 發布:2025-05-16 10:47:43 瀏覽:475
伺服器直鏈下載搭建 發布:2025-05-16 10:47:38 瀏覽:176
編譯不成功怎麼辦 發布:2025-05-16 10:35:54 瀏覽:613