2022年3月11日 星期五

android studio:AsyncTesk

AsyncTask是一種不屬於主線的執行緒,目的在於提供簡單易用的方式來達成Handler+Thread的功能,因為它已經有寫好了的方法,因此在使用上會比自己重新寫Handler和Thread較為方便,比較適合進行短時間的執行緒工作。使用方法如下

(一)建立一個內部或外部類別Thread繼承至AsyncTask這個thread,AsyncTask要定義的參數為<Params,Progress,Result>,第一個參數Params 為啟動任務時要傳入的資料類型,第二個參數為Progress為背景活動的進度類型,而第三個參數為Result類型為執行返回的結果。如果沒有要傳入,可用Void,如AsyncTask<Void, Void, Void>。

如下:

class mythread extends AsyncTask<String , Integer , Bitmap>{ }
(二)修改AsyncTask預設的方法中的內容,方法依序有onPreExecute doInBackground
onProgressUpdate onPostExecute等等的內容,如果沒有用到可以不修改。

(1)onPreExecute為執行AsyncTask背景活動前要做的事。

(2)doInBackground中的程式為你希望在背景默默執行的工作。其中的參數String... params為一陣列清單,params[0]可取出第一個參數值,其餘依此類推。此處的內容只在背景執行,因此不要在此處直接更新主執行序的介面。

(3)onProgressUpdate 在背景程式時,要手動呼叫的活動。如果要背景執行時,持續的更新主執行緒的數據,像是 執行進度條,又或是時間倒數等資訊,就可以將程式放在此處。其中的參數Integer... values也是陣列清單,values[0]可取出第一個參數值,其餘依此類推。

(4)onPostExecute 此處為進行完,你要執行的背景活動後,要執行的程式活動。


 
import androidx.appcompat.app.AppCompatActivity;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;

import java.net.URL;

public class MainActivity extends AppCompatActivity {

private ImageView imageView; //宣告imageview準備放圖片的地方
private ProgressBar pgBar; //宣告進度表
private Button button; //宣告button,點選後開啟



@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView=findViewById(R.id.imageView); //從xml取得imageview
pgBar=findViewById(R.id.pgbar); //從xml中取得progressbar
button=findViewById(R.id.button); //從xml中取得button

button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mythread task = new mythread(MainActivity.this,pgBar,imageView); //宣告task為自己新建一個thread,其中的參數第一個為MainActivity,第二個為進度軸,第三個為imageview,把這三個參數傳入thread,以便控劉
task.execute("https://images.pexels.com/photos/11319741/pexels-photo-11319741.jpeg?cs=srgb&dl=pexels-mathilde-langevin-11319741.jpg&fm=jpg"); //讓thread啟動,參數為網路的圖片網址,targetSdkVersion27版本以上不能用http連接,要用https
}
});

}
//結束後,釋放資料
@Override
protected void onDestroy() {
super.onDestroy();

imageView.setImageBitmap(null);

}
}

//自己建立的thread執行緒,命名為mythread
class mythread extends AsyncTask<String , Integer , Bitmap>{
private ImageView imageView; // 宣告imageview,以對應主執行緒丟過來的imageview
private Context context;
private ProgressBar progressBar; // 宣告progressBar,以對應主執行緒丟過來的progressBar
private Object Integer;

//mythread的建構式,參數有context, progressBar, imageView
public mythread(Context context,ProgressBar progressBar,ImageView imageView) {
this.context = context; //將傳入的數值於類別的數值相互綁定
this.progressBar=progressBar;
this.imageView=imageView;
}


//在此設定執行執行緒前要做的設定
@Override
protected void onPreExecute() {
super.onPreExecute();
progressBar.setVisibility(View.VISIBLE); //進度表顯現
imageView.setVisibility(View.GONE); //於主畫面中隱藏imageview

//初始化進度條並設定樣式及顯示的資訊。

}

//執行序要跑的工作在此運作,params為執行任務
@Override
protected Bitmap doInBackground(String... params) {
int progress = 0;
publishProgress(0);
String urlStr = params[0];
try {
URL url = new URL(urlStr);
publishProgress(50);
//progressBar.setProgress(50);
Log.v("acao", "1");
return BitmapFactory.decodeStream(url.openConnection().getInputStream()); //將取得的bitmap檔return回去,於結果裡運用

} catch (Exception e) {
e.printStackTrace();
progressBar.setProgress(50);
Log.v("acao", "2");
//最後達到100%
return null;
}
}

@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
//在doInBackground中,若呼叫publishProgress的時候會在這裡告知使用者進度,配合progressBar.setProgress,可以控制進度條

}

@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);



imageView.setVisibility(View.VISIBLE); //當完成的時候,顯示imageview
progressBar.setVisibility(View.GONE); //當完成的時候,隱藏進度條

imageView.setImageBitmap(bitmap); //將讀取的bitmap放在imageview

//執行完的設定
}




(三)呼叫的方法是在主執行序執行,如果只是一次使用,可以使用:

new thread().execute;

如果說要多次使用,可用下列的方法。

mythread task = new mythread(要丟入的參數);

task.execute("https://images.pexels.com/photos/11319741/pexels-photo-11319741.jpeg?cs=srgb&dl=pexels-mathilde-langevin-11319741.jpg&fm=jpg");


補充:thread中是否給值,要看你於mythread裡的建構式,public mythread(Context context,ProgressBar progressBar,ImageView imageView),有沒有給予值,如上面例子就要給予三個值;而execute裡是否要有值,要看之前在AsyncTask<Void, Void, Void>中的設定,如果是Void就不用給值,而如果是有加入型態,就依你加入的型態給與適當的值。



參考網址:

http://aiur3908.blogspot.com/2015/06/android-asynctask.html

https://oldgrayduck.blogspot.com/2013/01/androidasynctask-thread.html

https://www.aiwalls.com/android軟體開發教學/15/2156.html

https://dotblogs.com.tw/hanktom/2016/01/26/191154

沒有留言:

張貼留言