[AndroidThread&Handler]Thread3-案例2

來源:互聯網
上載者:User

標籤:des   android   c   class   blog   code   

 

 

使用Thread+Handler實現非UI線程更新UI介面

 

概述:每個Android應用程式都運行在一個dalvik虛擬機器進程中,進程開始的時候會啟動一個主線程(MainThread),主線程負責處理和ui相關的事件,因此主線程通常又叫UI線程。而由於Android採用UI單執行緒模式,所以只能在主線程中對UI元素進行操作。如果在非UI線程直接對UI進行了操作,則會報錯:

CalledFromWrongThreadException:only the original thread that created a view hierarchy can touch its views.

 

Android為我們提供了訊息迴圈的機制,我們可以利用這個機制來實現線程間的通訊。那麼,我們就可以在非UI線程發送訊息到UI線程,最終讓Ui線程來進行ui的操作。

 

對於運算量較大的操作和IO操作,我們需要新開線程來處理這些繁重的工作,以免阻塞ui線程。

例子:下面我們以擷取CSDN logo的例子,示範如何使用Thread+Handler的方式實現在非UI線程發送訊息通知UI線程更新介面。

 

UIupdateActivity.java

  
 public class UIupdateActivity extends Activity{ private static final int MSG_SUCCESS = 0;//擷取圖片成功的標識 private static final int MSG_FAILURE = 1;//擷取圖片失敗的標識 protected static final String TAG = "Raylee "; protected static final String TITLE = "UIupdate through workerThread"; private ImageView mImageView; private Button mButton; private Thread mThread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.example2); mImageView= (ImageView) findViewById(R.id.imageView);//顯示圖片的ImageView mButton = (Button) findViewById(R.id.button); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(mThread == null) { mThread = new Thread(runnable); mThread.start();//線程啟動 } else { Toast.makeText(getApplication(),getApplication(). getString(R.string.thread_started),Toast.LENGTH_LONG).show(); } } }); } @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { public void handleMessage (Message msg) {//此方法在ui線程運行 switch(msg.what) { case MSG_SUCCESS: mImageView.setImageBitmap((Bitmap) msg.obj);//imageview顯示從網路擷取到的logo Log.i(TAG, "Handler Success ---> " + msg.obj); Toast.makeText(getApplication(), getApplication() .getString(R.string.get_pic_success),Toast.LENGTH_LONG).show(); break; case MSG_FAILURE: Log.i(TAG, "Handler Failure!"); Toast.makeText(getApplication(), getApplication(). getString(R.string.get_pic_failure),Toast.LENGTH_LONG).show(); break; } } }; Runnable runnable = new Runnable() { @Override public void run() {//run()在新的線程中運行 HttpClient hc = new DefaultHttpClient(); HttpGet hg = new HttpGet("http://csdnimg.cn/www/images/csdnindex_logo.gif");//擷取csdn的logo Log.i(TAG + TITLE, "hg Not null ---> " + hg); Bitmap bm = null; try { HttpResponse hr = hc.execute(hg); bm = BitmapFactory.decodeStream(hr.getEntity().getContent()); Log.i(TAG + TITLE, "bm Not null ---> " + bm); } catch (Exception e) { mHandler.obtainMessage(MSG_FAILURE).sendToTarget();//擷取圖片失敗 Log.i(TAG + TITLE, "Failure!"); return; } Log.i(TAG + TITLE, "Success ---> " + bm); mHandler.obtainMessage(MSG_SUCCESS,bm).sendToTarget();//擷取圖片成功,向ui線程發送MSG_SUCCESS標識和bitmap對象 } }; }

 

 

example2.xml

  
 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button" android:text="@string/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="30dp" /> <ImageView android:id="@+id/imageView" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="100dp" android:layout_width="wrap_content" android:contentDescription="@android:string/untitled" /> </LinearLayout>

 

 

AndroidManifest.xml

 
 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="home.lee.example2UIupdate" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="10" /> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".UIupdateActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 

 

運行結果

 

為了不阻塞ui線程,我們使用mThread從網路擷取了CSDN的LOGO

,並用bitmapObject Storage Service了這個Logo的像素資訊。

此時,如果在這個線程的run()方法中調用

 

 
 mImageView.setImageBitmap(bm)

 

會出現:CalledFromWrongThreadException:only the original thread that created a view hierarchy can touch its views。原因是run()方法是在新開的線程中執行的,我們上面提到不能直接在非ui線程中操作ui元素。

 

非UI線程發送訊息到UI線程分為兩個步驟

一、發送訊息到UI線程的訊息佇列

通過使用Handler的

 
 Message obtainMessage(int what,Object object) 

 

構造一個Message對象,這個Object Storage Service了是否成功擷取圖片的標識what和bitmap對象,然後通過message.sendToTarget()方法把這條message放到訊息佇列中去。

二、處理髮送到UI線程的訊息

在ui線程中,我們覆蓋了handler的

 
 public void handleMessage (Message msg)

 

這個方法是處理分發給ui線程的訊息,判斷msg.what的值可以知道mThread是否成功擷取圖片,如果圖片成功擷取,那麼可以通過msg.obj擷取到這個對象。最後,我們通過

 mImageView.setImageBitmap((Bitmap) msg.obj); 

 

設定ImageView的bitmap對象,完成UI的更新。補充:

事實上,我們還可以調用View的post方法來更新ui

 
 mImageView.post(new Runnable() {//另外一種更簡潔的發送訊息給ui線程的方法。 @Override public void run() {//run()方法會在ui線程執行 mImageView.setImageBitmap(bm); } }); 

 

 

這種方法會把Runnable對象發送到訊息佇列,ui線程接收到訊息後會執行這個runnable對象。從例子中我們可以看到handler既有發送訊息和處理訊息的作用,會誤以為handler實現了訊息迴圈和訊息分發,其實Android為了讓我們的代碼看起來更加簡潔,與UI線程的互動只需要使用在UI線程建立的handler對象就可以了。

http://blog.csdn.net/mylzc/article/details/6736988

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.