Android开发系列——实战篇11:多线程与异步机制
本文介紹安卓的多線程與異步任務處理的機制
目錄
- 一、多線程
- 1.主線程與子線程
- 2.Handler用法詳解
- 使用Handler發(fā)送post請求
- 使用Handler處理Message消息
一、多線程
1.主線程與子線程
每個 Android 應用都有一個主線程,負責處理界面(包括測量和繪制視圖)、協(xié)調(diào)用戶互動以及接收生命周期事件。
主線程一般被用于操作UI界面,與用戶進行交互,所以也被稱為UI線程。
與此相對的,在一些耗時比較久的任務處理中,比如從網(wǎng)絡上下載資源、進行后臺服務等,這些是用戶看不到的地方。我們不能直接將這些任務放在主線程中進行處理,不然會耗費大量資源并且出現(xiàn)錯誤,降低用戶體驗。
所以一般遇到這些任務,需要在主線程之外重新開一個子線程進行任務處理,也就是所謂的非UI線程。
注:子線程(非UI線程)里的操作是不能直接對UI界面進行更新的。
通過一個從網(wǎng)絡上下載圖片的案例來理解主線程與子線程。
主要邏輯:在界面上創(chuàng)建一個Button按鈕,點擊后從網(wǎng)絡上下載一幅圖片。
主要步驟:
1.在布局文件中創(chuàng)建按鈕和圖片視圖,給按鈕添加事件。
2.在Java文件中編寫事件處理邏輯。
3.在AndroidManifest清單文件中添加網(wǎng)絡權(quán)限。
activity_main.xml文件:
<Buttonandroid:id="@+id/bt1"adnroid:onClick="download"android:layout_width="128dp"android:layout_height="wrap_content"android:layout_alignParentStart="true"android:layout_alignParentTop="true"android:layout_alignParentEnd="true"android:layout_marginStart="134dp"android:layout_marginTop="100dp"android:layout_marginEnd="134dp"android:text="Download" /><ImageViewandroid:id="@+id/image"android:layout_width="300dp"android:layout_height="200dp"android:layout_centerInParent="true"android:background="@color/colorAccent" />效果:
Java類文件
package com.example.handler;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.View; import android.widget.ImageView;import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection;public class MainActivity extends AppCompatActivity {//實例化ImageView對象ImageView mimageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {//初始化方法中將imageView對象綁定視圖mimageView = (ImageView)findViewById(R.id.image);}public void download(View view){//按鍵處理函數(shù)//創(chuàng)建字符串變量,將網(wǎng)絡圖片的地址傳入String urlstr = "https://www.baidu.com/s?wd=%E4%BB%8A%E6%97%A5%E6%96%B0%E9%B2%9C%E4%BA%8B&tn=SE_Pclogo_6ysd4c7a&sa=ire_dl_gh_logo&rsv_dl=igh_logo_pc";URL url = null;try {//捕獲異常//實例化URL對象,將地址傳入url = new URL(urlstr);//創(chuàng)建URLConnection對象,進行連接URLConnection con = url.openConnection();//創(chuàng)建輸入流對象接受輸入流InputStream in = con.getInputStream();//創(chuàng)建流對象解碼輸入流Bitmap bm = BitmapFactory.decodeStream(in);//將解碼后的流(圖片)傳入視圖mimageView.setImageBitmap(bm);} catch (Exception e) {e.printStackTrace();}}}AndroidManifest清單文件
<uses-permission android:name="android.permission.INTERNET"/>這樣基本邏輯就已經(jīng)完善了,但是實際編譯過程中卻無法實現(xiàn)功能,查看日志可以發(fā)現(xiàn)這一行:
在高版本的安卓中,網(wǎng)絡請求是不能放在主線程里的,一定要開啟一個子線程去處理網(wǎng)絡任務。
開啟子線程后的Java類文件
package com.example.handler;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.View; import android.widget.ImageView;import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection;public class MainActivity extends AppCompatActivity {//實例化ImageView對象ImageView mimageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {//初始化方法中將imageView對象綁定視圖mimageView = (ImageView)findViewById(R.id.image);}public void download(View view){//按鍵處理函數(shù)//創(chuàng)建一個內(nèi)部類開啟子線程Thread t = new Thread(){@Overridepublic void run(){String urlStr = "https://www.baidu.com/s?wd=%E4%BB%8A%E6%97%A5%E6%96%B0%E9%B2%9C%E4%BA%8B&tn=SE_Pclogo_6ysd4c7a&sa=ire_dl_gh_logo&rsv_dl=igh_logo_pc";URL url = null;try {//捕獲異常//實例化URL對象,將地址傳入url = new URL(urlStr);//創(chuàng)建URLConnection對象,進行連接URLConnection con = url.openConnection();//創(chuàng)建輸入流對象接受輸入流InputStream in = con.getInputStream();//創(chuàng)建流對象解碼輸入流Bitmap bm = BitmapFactory.decodeStream(in);//將解碼后的流(圖片)傳入視圖mimageView.setImageBitmap(bm);} catch (Exception e) {e.printStackTrace();}}};t.start();}}但是依舊會進行報錯,原因在于:
子線程是不能對UI界面直接進行更新的。、如果要對UI界面進行更新,一定是子線程給主線程發(fā)消息,由主線程對界面進行更新。
UI線程與非UI線程之間通過Handler進行通信。
完整的Java類代碼
package com.example.handler;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.ImageView;import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection;public class MainActivity extends AppCompatActivity {//實例化ImageView對象ImageView mimageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}//創(chuàng)建一個Handler對象Handler h = new Handler(){@Overridepublic void handleMessage(Message msg){//接受來自子線程中Message的消息并強制轉(zhuǎn)換為數(shù)據(jù)流類型Bitmap bm = (Bitmap)msg.obj;//更新視圖mimageView.setImageBitmap(bm);}};private void initView() {//初始化方法中將imageView對象綁定視圖mimageView = (ImageView)findViewById(R.id.image);}public void download(View view){//按鍵處理函數(shù)//創(chuàng)建一個內(nèi)部類開啟子線程Thread t = new Thread(){@Overridepublic void run(){//直接復制網(wǎng)絡圖片的地址傳入?yún)?shù)String urlStr = "http://img4.imgtn.bdimg.com/it/u=1906469856,4113625838&fm=26&gp=0.jpg";URL url = null;try {//捕獲異常//實例化URL對象,將地址傳入url = new URL(urlStr);//創(chuàng)建URLConnection對象,進行連接URLConnection con = url.openConnection();//創(chuàng)建輸入流對象接受輸入流InputStream in = con.getInputStream();//創(chuàng)建流對象解碼輸入流Bitmap bm = BitmapFactory.decodeStream(in);//將解碼后的流(圖片)傳入視圖//mimageView.setImageBitmap(bm);//創(chuàng)建一個Message對象用來發(fā)送消息Message m = new Message();m.obj = bm;//向主線程發(fā)送消息h.sendMessage(m);} catch (Exception e) {e.printStackTrace();}}};t.start();}}這樣效果就出來了:
2.Handler用法詳解
使用Handler發(fā)送post請求
通過第一節(jié)的例子可以看到在主線程與子線程之間使用Handler這個消息處理器進行消息的傳遞與處理。
第一節(jié)的例子中是使用Handler的Message方法進行發(fā)送消息,在子線程中進行網(wǎng)絡資源下載后傳遞消息給主線程進行UI更新。
Handler還有其他的請求方法,如post請求。
通過一個實例來理解post請求的一些方法。
主要功能:通過post請求實現(xiàn)一個圖片的輪播行為。
使用Handler處理Message消息
總結(jié)
以上是生活随笔為你收集整理的Android开发系列——实战篇11:多线程与异步机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dda算法控制电机_新能源汽车电机制动控
- 下一篇: Android6.0 无法锁屏