Handler與多線程

1、Handler介紹

在Android開發中,我們常會使用單獨的線程來完成某些操作,比如用一個線程來完成從網絡上下的圖片,然后顯示在一個ImageView上,在多線程操作時,Android中必須保證以下兩點:

(1)不要阻塞UI線程

(2)不要再UI線程之外訪問Android UI工具包

有了以上兩點的限制,我們在程序之間的消息如何進行傳遞呢?

用Handler,消息的處理者。

public class MainActivity extends Activity {private TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);}private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 100:tv.setText("下載完成");break;}}};public void downloadClick(View view) {//使用線程模擬下載操作new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}break;}handler.sendEmptyMessage(100);}}).start();}
}

?

2、Handler常用API

使用handler可以完成以下兩點工作:

(1)消息調度和在將來的某個時間點執行一個Runnable

(2)多個任務加入到一個隊列中執行

Handler相關方法:

                //發送一個空消息,即obj為空,標記為100handler.sendEmptyMessage(100);//獲取一個消息對象,返回一個Msg對象Message msg = handler.obtainMessage();msg.what = 100;msg.obj = "要存的信息";//任意類型handler.sendMessage(msg);//發送消息//在制定時間后發送消息handler.sendEmptyMessageAtTime(200, System.currentTimeMillis() + 3000);//延遲2s后發送消息handler.sendEmptyMessageDelayed(300, 2000);

?

3、Handler內部實現原理

Handler實現機制:

(1)Message對象,表示要傳遞的一個消息

(2)MessageQueue對象,存放消息對象的消息隊列,先進先出原則

(3)Looper對象負責管理當前線程的消息隊列(MessageQueue)

(4)Handler對象負責把消息push到消息隊列中,以及接收Looper從消息隊列中取出的消息

?

Android啟動程序時會在UI線程創建一個MessageQueue。

/*** Handler機制* 1、Message 消息對象,內部使用鏈表數據結構實現一個消息池,用于重復利用,避免大量創建消息對象,造成內存浪費* 2、Handler 消息處理者,通過該對象把消息存入消息隊列,并最后通過HandlerMessage方法處理消息* 3、MessageQueue 消息隊列,用于存儲Message對象的數據結構,先進先出* 4、Looper 消息隊列的處理者,用于循環檢查消息隊列,從消息隊列中一個一個的取出消息對象,傳入HandlerMessage方法*/

?

4、Handler內存泄露問題分析

內存泄漏:當activity退出后,handler依然還占用activity的引用,導致activity沒有真正退出,依然占用內存。解決方法如下:

/*** Handler的內存泄露問題* 1、定義一個內部類時,會默認擁有外部類對象的引用,所以建議使用內部類時,最好定義為一個靜態內部類* 2、引用的強弱,強引用->軟引用 ->弱引用*/public class HandlerMemoryActivity extends Activity {private MyHandler handler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_handler_memory);//使用Handler延遲執行一個Runnable(10分鐘)handler.postDelayed(new Runnable() {@Overridepublic void run() {System.out.println("!!!!!!run");}}, 1000 * 60 * 10);//關閉當前的Activity
        finish();}private static class MyHandler extends Handler {WeakReference<HandlerMemoryActivity> weakReference;public MyHandler(HandlerMemoryActivity activity) {weakReference = new WeakReference<HandlerMemoryActivity>(activity);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);HandlerMemoryActivity activity = weakReference.get();if (activity != null) {//做處理
            }}}
}

?

5、AsyncTask

除了使用Handler實現線程間的通信外,Android提供了一個工具類:AsyncTask,他使創建需要與用戶界面交互的長時間運行的任務變得簡單,相對來說AsyncTask更清涼已寫,適用與簡單的異步處理,不需要借助線程和Handler即可實現。

AsyncTask是抽象類,AsyncTask定義了三種泛型類型:Params,Progress和Result

Params啟動任務執行的輸入參數,比如,Http請求的URL;

Progress后臺任務執行的百分比

Result后臺執行任務的最中返回結果,比如String

AsyncTask的執行步驟:

AsyncTask的執行分為四個步驟,每一步對應一個回調方法,我們需要的就是實現這些方法。

(1)首先定義一個類繼承AsyncTask

(2)實現AsyncTask中定義的下面一個或幾個方法

四個執行步驟分別為:

(1)onPreExecute():被UI Thread調用,該方法用來做已寫準備工作,如在界面上顯示一個進度條

(2)doInBackground(Params..):將在onPreExcute之后執行,運行在后臺的線程中。負責執行耗時操作。可以調用publishProgress方法來更新實時任務進度

(3)onProgressUpdate(Progress..):在publishProgress方法被調用后,UI Thread將調用該方法在界面上展示任務的進展情況

(4)onPostExcute(Result):在doInBackground執行完成后,onPostExcute(Result)方法將被UI Thread調用,后臺的計算結果將通過該方法傳遞到UI Thread。

AsyncTask準則:

(1)AsyncTask的實例必須在UI Thread中創建。

(2)excute方法必須在UI Thread中調用

(3)不要手動調用onPreExecute、onPostExecute、doInBackground和onProgressUpdate這借個方法

(4)改Task只能被執行一次,否則多次調用時會出現異常

(5)AsyncTask不能餓完全取代線程,在一些邏輯較為復雜或者后臺反復執行的邏輯可能就需要線程來實現了

public class MainActivity extends Activity {private TextView tv;private ProgressBar progressBar;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);progressBar = (ProgressBar) findViewById(R.id.progressBar);}public void downloadClick(View view) {new MyAsyncTask(MainActivity.this).execute("http://a.hiphotos.baidu.com/image/pic/item/d50735fae6cd7b8926b326c20c2442a7d8330e97.jpg");}/*** 通過AsyncTask實現一個異步任務*/private static class MyAsyncTask extends AsyncTask<String, Integer, Integer> {private MainActivity activity;public MyAsyncTask(MainActivity activity) {this.activity = activity;}//執行任務之前觸發的事件,可以在該方法中做一些初始化動作,例如顯示一個dialog//這個是在主線程中
        @Overrideprotected void onPreExecute() {super.onPreExecute();activity.progressBar.setProgress(0);}//在子線程中//執行后臺任務的方法
        @Overrideprotected Integer doInBackground(String... params) {String s = params[0];try {URL url = new URL(s);HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();//獲取文件的大小int size = urlConnection.getContentLength();//0是一個標記,表示需要更新的最大進度值,1表示更新當下下載的進度值publishProgress(0, size);byte[] bytes = new byte[100];int len = -1;FileInputStream in = (FileInputStream) urlConnection.getInputStream();FileOutputStream out = new FileOutputStream("/sdcard/" + System.currentTimeMillis() + ".jpg");while ((len = in.read(bytes)) != -1) {out.write(bytes, 0, len);//更新進度publishProgress(1, len);out.flush();}out.close();in.close();} catch (Exception e) {e.printStackTrace();}return 200;}//更新進度
        @Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);switch (values[0]) {case 0:activity.progressBar.setMax(values[1]);break;case 1:activity.progressBar.incrementProgressBy(values[1]);break;}}@Overrideprotected void onPostExecute(Integer integer) {super.onPostExecute(integer);if (integer == 200) {activity.tv.setText("下載完成");}}}
}

?

轉載于:https://www.cnblogs.com/chhom/p/4732041.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/273052.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/273052.shtml
英文地址,請注明出處:http://en.pswp.cn/news/273052.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

oracle read only 事務,oracle set transaction read only與dbms_transaction實現事務transaction控制...

SQL> show userUser is "SYS"SQL> set transaction read only;Transaction setSQL> insert into t_table values(3);1 row insertedSQL> commit;Commit complete---sys用戶 set transaction read only不生效SQL> select * from t_table;A------------…

oracle report builder 6i下載,oracle report builder 6i - 數據模型中的SQL查詢代碼

我是Vijetha&#xff0c;我正在研究報告6i&#xff0c;我很陌生 . 我有以下查詢 .在front_end中&#xff0c;在Reports Parameter中&#xff0c;當用戶單擊“運行”按鈕時&#xff0c;它將詢問START_DATE和END_DATE輸入 .如果用戶提供START_DATE和END_DATE或者不提供輸入&#…

HTML/CSS/JavaScript學習總結(轉)

HTML 網站開發的主要原則是&#xff1a; – 用標簽元素HTML描述網頁的內容結構&#xff1b; – 用CSS描述網頁的排版布局&#xff1b; – 用JavaScript描述網頁的事件處理&#xff0c;即鼠標或鍵盤在網頁元素上的動作后的程序 HTML&#xff08;Hyper Text Mark-up Language 超文…

oracle引用vs,VS2013中使用oracle,有關引用哪個.dll

Oracle、Microsoft 和第三方供應商都提供了針對 Oracle 產品進行了優化的數據供應程序。 Oracle 和 Microsoft 免費提供其 Oracle 數據供應程序。訪問 Oracle 的操作有些類似于對 Sql Server 的操作。對Oracle 的訪問有以下幾種數據提供程序。 Microsoft.NET Oracle 提供程序 O…

貪心方法

1.背包問題 按效益值/重量 進行排序輸入 2.帶限期的作用排序 按效益值進行排序輸入 3 最小生成樹&#xff1a; 貪心方法&#xff1a;每次計入成本最小的邊 原樹T&#xff0c; 欲構造的最小生成樹T Prim&#xff1a; 從T中選與T中結點相連的成本最小的邊。 且&#xff1a;邊之前…

oracle語法官方文檔,Oracle官方文檔必備語法知識

很多Oracle DBA雖然接觸Oracle時間很長&#xff0c;但是一旦想不起語法或找不出相應參數時&#xff0c;習慣百度或谷歌。雖然已經下載了官方文檔&#xff0c;但是Oracle官方文檔必備語法知識[日期&#xff1a;2015-04-21]來源&#xff1a;Linux社區作者&#xff1a;kuqlan[字體…

新中大oracle實列名,新中大財務軟件操作流程(完整版)

新中大財務軟件最基本的三個模塊&#xff1a;核算單位、財務處理系統、報表處理系統。簡單地說&#xff0c;核算單位模塊是用于建賬&#xff0c;財務處理系統用于登賬&#xff0c;報表處理系統用于出報表的。一、總賬處理系統1、建賬套雙擊財務軟件圖標 → 在登錄界面選擇用戶編…

編寫DLL所學所思(1)——導出函數

燭秋 http://www.cnblogs.com/cswuyg/archive/2011/09/30/dll.html 動態鏈接庫的使用有兩種方式&#xff0c;一種是顯式調用。一種是隱式調用。 &#xff08;1&#xff09; 顯式調用&#xff1a;使用LoadLibrary載入動態鏈接庫、使用GetProcAddress獲取某函數地址。 &am…

linux切換任務命令,Linux top詳解之交互命令、命令行選項

top交互命令我們之前說過top是一個交互命令。上一節我們已經遇到了一些命令。這里我們會探索更多的命令。2.1 ‘h’: 幫助首先&#xff0c;我們可以用’h’或者’?’顯示交互命令的幫助菜單。2.2 “或者”: 刷新顯示top命令默認在一個特定間隔(3秒)后刷新顯示。要手動刷新&am…

linux 內核地址隨機化,GNU/Linux內核的地址隨機化

地址空間布局隨機化(ASLR)是一項增加安全性的技術&#xff0c;***者發現漏洞之后開始編寫exploit時如果要考慮繞過ASLR這會增加編寫exploit的難度&#xff0c;最早是2001年Grsecurity社區(強悍的社區&#xff0c;直到今天還在為各種各樣的加固為自由軟件安全社區作出持續而杰出…

Yii2的一些問題

Yii2中刪除能不能串著用 Yii2中find、findAll有什么區別 Yii2中User::findOne($id)和User::find->where([id>1])->one; 會員登錄信息 是以什么樣的形式存放在Yii::$app->user->identity 里面的&#xff1f; session的形式 http://www.cnblogs.com/kuyuecs/archi…

linux系統硬盤設置密碼,LUKS:Linux下磁盤加密

Linux下磁盤加密LUKS(Linux Unified Key Setup)為Linux硬盤加密提供了一種標準&#xff0c;它不僅能通用于不同的Linux發行版本&#xff0c;還支持多用戶/口令。因為它的加密密鑰獨立于口令&#xff0c;所以如果口令失密&#xff0c;我們可以迅速改變口令而無需重新加密真個硬盤…

Hibernate查詢

9.1 Hibernate數據查詢 數據查詢與檢索是Hibernate的一個亮點。Hibernate的數據查詢方式主要有3種&#xff0c;它們是&#xff1a; l Hibernate Query Language&#xff08;HQL&#xff09; l Criteria Query l Native SQL 下面對這3種查詢方式分別進…

linux x86 io端口映射,linux中的 IO端口映射和IO內存映射

下面是今天看到兩篇關于linux中的 IO端口映射和IO內存映射的文章,時間關系,沒來得及深入理解,有空好好看看CPU地址空間CPU地址空間(一)地址的概念1)物理地址&#xff1a;CPU地址總線傳來的地址&#xff0c;由硬件電路控制其具體含義。物理地址中很大一部分是留給內存條中的內存…

單例模式 創建對象

兩種選擇 1 使用pthread_once&#xff0c; once是類的成員變量 只執行一次Create create的作用是創建一個對象 2 使用 static lock 如下所示&#xff0c;注意lock必須是static的&#xff0c;否則是局部變量&#xff0c;每個線程都有自己的lock&#xff0c;無法保證只執行一次。…

Linux c編譯庫路徑,【一點一點學Linux C】交叉編譯時候如何配置連接庫的搜索路徑...

交叉編譯的時候不能使用本地(i686機器&#xff0c;即PC機器&#xff0c;研發機器)機器上的庫&#xff0c;但是在做編譯鏈接的時候默認的是使用本地庫&#xff0c;即/usr/lib,/lib兩個目錄。因此&#xff0c;在交叉編譯的時候&#xff0c;要采取一些方法使得在編譯鏈接的時候找到…

[NBUT 1458 Teemo]區間第k大問題,劃分樹

裸的區間第k大問題&#xff0c;劃分樹搞起。 #pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #inc…

Linux的軟件包封裝格式有,linux軟件安裝包詳解---全

詳細介紹了常見的四種Linux應用軟件安裝包及其安裝方法。一、解析Linux應用軟件安裝包&#xff0c;通常Linux應用軟件的安裝包有四種&#xff1a;1) tar包&#xff0c;如software-1.2.3-1.tar.gz。他是使用UNIX系統的打包工具tar打包的。2) rpm包&#xff0c;如software-1.2.3-…

人生的第一個博客(●'?'●)??--開博典禮

嘛&#xff0c;說實話&#xff0c;現在才開始&#xff0c;實在是有點晚了&#xff0c;一不小心大學都過去1年了_(:3 」∠)_ 我在專業方面的起步也是相當晚的&#xff0c;身為計算機專業&#xff0c;編程卻從大學才開始正式接觸&#xff0c;進入大學時其他方面的能力也都約等于0…

linux查看運行鐘的tomcat,linux查看tomcat啟動運行日志

Linux0&period;11內核--進程調度分析之2&period;調度[版權所有,轉載請注明出處.出處:http://www.cnblogs.com/joey-hua/p/5596830.html ] 上一篇說到進程調度歸根結底是調用timer_interrupt函數, ...iReport 下載地址iReport 下載地址: https://osdn.jp/projects/sfnet…