❶ 如何在android一條單獨線程,更新ui
方法有兩種:
通過繼承Thread類,重寫Run方法來實現
通過繼承介面Runnable實現多線程
主要接受子線程發送的數據, 並用此數據配合主線程更新UI.
Handler的主要作用:主要用於非同步消息的處理
Handler的運行過程:
當(子線程)發出一個消息之後,首先進入一個(主線程的)消息隊列,發送消息的函數即刻返回,而在主線程中的Handler逐個的在消息隊列中將消息取出,然後對消息進行處理。這樣就實現了跨線程的UI更新(實際上還是在主線程中完成的)。
這種機制通常用來處理相對耗時比較長的操作,如訪問網路比較耗時的操作,讀取文大文件,比較耗時的操作處理等。
在大白話一點的介紹它的運行過程:
啟動應用時Android開啟一個主線程
(也就是UI線程) , 如果此時需要一個耗時的操作,例如:
聯網讀取數據,或者讀取本地較大的一個文件的時候,你不能把這些操作放在主線程中,如果你放在主線程中的話,界面會出現假死現象(這也就是你在主線程中直接訪問網路時會提示你異常的原因,如我們上篇文章所述Android主線程不能訪問網路異常解決辦法)。
❷ android studio子線程更新UI 問題
睡使用Thread.currentthread().sleep(1000);
發送不同的Message,每次都是一個,放到for循環內Message message = new Message();
❸ 在Android子線程中初始化handler後,為什麼該子線程也能更新UI(大神請進)
子線程的hanlder裡面是不能更新Android UI的。
簡單說下:
如果你在子線程裡面創建hander是用的是以下代碼:
new Handler(Looper.getMainLooper())
那還是用的主線程的Looper
❹ 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線程與主線程真是一個神奇的東西,求高手~~
先給你提示一下。android中更新UI只能用UI線程,即主線程。 這樣說吧 ui線程== 主線程。
1 想要在子線程中數據發生改變更新主線程的ui,可以通過消息機制,message和handler結合的方式,比較好用。
2 還可以 用特定的控制項的方法,比如ListView的adapter中的notifydatachang().好像是這個方法
3 在view中還可以在數據變化後用invalidata()或者postInvalidata()這兩個方法。
基本上就這幾種常見的,希望可以幫你,大家都來討論。
❻ android中在子線程中更新UI的幾種方法
照搬一個我自己的回答
..com/question/1822980438413918108
public class passWebViewInNewThread{ static android.os.Handler h=null; static WebView w=null; public static void getWebView(WebView w0){//有點想不起來webview的類名是啥了,強答 w=w0; h=new android.os.Handler();//請用UI線程來運行這段代碼 } public static void doWithWebView(){ new Thread() {//開新線程 @Override public void run() { try {//裡面寫新線程執行內容 /* XXX 耗時內容…… */ h.post(new Runnable(){//用handler轉交UI處理操作 @Override public void run(){ //在這寫操作webview的代碼 //請不要在這里放耗時代碼,否則會卡住UI線程 } }); }catch(Exception e){ } } }.start(); }}//PS:因為我已經不記得如果對象聲明在方法內部如何用final,所以索性寫成這樣。沒環境寫JAVA,所以可能有幾個小錯誤
❼ 如果在Android 子線程中更新ui
針對於b情況,你嘗試下在類中新建一個thread,然後在button的setOnClickListener中調用,應改沒有問題。如果在button的setOnClickListener,應該算是內部類了。
❽ 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了。
❾ android 線程中怎麼更新ui進度條
如果你用的是標準的ProgressBar類,那麼調用setProgress(int progress)方法進行更新即可。
不過如果載入處理不是在UI線程,那就需要用Handler去更新了
舉例如下:
int progress = calculateProgress();
ProgressBar progressBar = mActivity.getProgressBar();
// 獲取主線程Handler。需要編寫getHandler()方法
Handler handler = mActivity.getHandler();
handler.post(new Runnable() {
void run() {
progressBar.setProgress(progress);
}
})
❿ 在多線程中,子線程更新主線程ui有哪些方法及注意點
Android
UI多線程Androidthread工作
在一個Android 程序開始運行的時候,會單獨啟動一個Process。默認的情況下,所有這個程序中的Activity或者Service(Service和 Activity只是Android提供的Components中的兩種,除此之外還有Content Provider和Broadcast Receiver)都會跑在這個Process。
一個Android 程序默認情況下也只有一個Process,但一個Process下卻可以有許多個Thread。在這么多Thread當中,有一個Thread,我們稱之為UI Thread。UI Thread在Android程序運行的時候就被創建,是一個Process當中的主線程Main Thread,主要是負責控制UI界面的顯示、更新和控制項交互。在Android程序創建之初,一個Process呈現的是單線程模型,所有的任務都在一個線程中運行。因此,我們認為,UI Thread所執行的每一個函數,所花費的時間都應該是越短越好。而其他比較費時的工作(訪問網路,下載數據,查詢資料庫等),都應該交由子線程去執行,以免阻塞主線程。
那麼,UI Thread如何和其他Thread一起工作呢?常用方法是:
誕生一個主線程的Handler物件,當做Listener去讓子線程能將訊息Push到主線程的Message Quene里,以便觸發主線程的handlerMessage()函數,讓主線程知道子線程的狀態,並在主線程更新UI。
例如,在子線程的狀態發生變化時,我們需要更新UI。如果在子線程中直接更新UI,通常會拋出下面的異常:11-07 13:33:04.393: ERROR/JavaBinder(1029):android.view.ViewRoot$:Only the original thread that created a view hierarchy can touch its views.
意思是,無法在子線程中更新UI。為此,我們需要通過Handler物件,通知主線程Ui Thread來更新界面。
如下,首先創建一個Handler,來監聽Message的事件:
private final int UPDATE_UI = 1;private Handler mHandler = new MainHandler();private class MainHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case UPDATE_UI: {Log.i("TTSDeamon", "UPDATE_UI");showTextView.setText(editText.getText().toString());ShowAnimation();break;}default:break;}}}
或者
private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case UPDATE_UI: {Log.i("TTSDeamon", "UPDATE_UI");showTextView.setText(editText.getText().toString());ShowAnimation();break;}default:break;}}}
當子線程的狀態發生變化,則在子線程中發出Message,通知更新UI。
mHandler.sendEmptyMessageDelayed(UPDATE_UI, 0);
在我們的程序中,很多Callback方法有時候並不是運行在主線程當中的,所以如果在Callback方法中更新UI失敗,也可以採用上面的方法。