1.在子線程中更新UI
Android中更新UI元素箩祥,必須在主線程中進行蠢正,否則就會出現(xiàn)異常曙咽。
changeBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(connection);
new Thread(new Runnable() {
@Override
public void run() {
tv1.setText("改變了");
}
});
}
});
運行以上程序,你會發(fā)現(xiàn)程序果然崩潰了涤浇,由此證實Android確實不允許在子線程中進行UI操作鳖藕。
使用異步消息處理機制進行UI操作問題。
public class MainActivity extends AppCompatActivity {
private Button changeBt;
private TextView tv1;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 1) {
tv1.setText("改變了");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
changeBt = (Button) findViewById(R.id.ChangeButton);
tv1 = (TextView) findViewById(R.id.Tv1);
changeBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(connection);
runOnUiThread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
});
}
});
}
}
或者使用runOnUiThread()方法只锭,它其實就是一個異步消息處理機制的接口封裝著恩,背后的實現(xiàn)原理上面的代碼一模一樣。
changeBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(connection);
runOnUiThread(new Runnable() {
@Override
public void run() {
tv1.setText("改變了");
}
});
}
});
Android還提供了另外一些好用的工具,比如AsyncTask喉誊,它背后的實現(xiàn)原理也是基于異步消息處理機制的邀摆,只是Android幫我們做了封裝。
public class DownloadTask extends AsyncTask<Void,Integer,Boolean>{
private int i=0;
private Context con = null;
ProgressDialog pd1;
DownloadTask(Context con){
this.con= con;
}
@Override
protected Boolean doInBackground(Void... params) {
try{
while(true){
int downloadPercent = doDownload();
publishProgress(downloadPercent);
if(downloadPercent>=100000){
break;
}
}
}catch (Exception e){
return false;
}
return true;
}
@Override
protected void onPreExecute() {
pd1 = ProgressDialog.show(con, "提示", "正在下載");
}
@Override
protected void onProgressUpdate(Integer... values) {
pd1.setMessage("Downloaded"+values[0]+"%");
}
@Override
protected void onPostExecute(Boolean aBoolean) {
pd1.dismiss();
Toast.makeText(con,"下載成功",Toast.LENGTH_SHORT).show();
}
private int doDownload() {
for (int j =0;j<10;j++){
i++;
}
return i;
}
}
AsyncTask是一個抽象類伍茄,使用的時候必須繼承它栋盹,并且我們要為AsyncTask類指定3個泛型參數(shù),第一個是執(zhí)行AsyncTask傳入的參數(shù)敷矫,可以在后臺任務中使用例获。第二個參數(shù)是如果需要在界面上顯示當前的進度,以第二個參數(shù)的類型作為進度單位曹仗。第三個參數(shù)是使用這里指定的泛型作為返回值類型榨汤。
- onPreExecute()方法是在后臺任務開始執(zhí)行之前調用≌希可以用于進行一些界面初始化操作件余。
- onInBackground()方法中的所有代碼都是在子線程中執(zhí)行的。任務完成后通過return返回執(zhí)行結構遭居。但不可以進行UI操作啼器,要進行UI操作可以調用publishProgress()方法。
- onProgressUpdate()方法俱萍,調用了publishProgress()方法后會調用該方法端壳,在onProgressUpdate()方法里可以進行UI操作。
- onPostExecute()方法是在后臺任務執(zhí)行完枪蘑,利用返回數(shù)據(jù)判斷進行一些UI操作的损谦。
- 如果要啟動這個任務,需要以下代碼:
new DownloadTask.execute(Context 類型);
2.Service的基本用法
什么時候需要Service呢岳颇?比如播放多媒體的時候用戶啟動了其他Activity這個時候程序要在后臺繼續(xù)播放照捡,比如檢測SD卡上文件的變化,再或者在后臺記錄你地理信息位置的改變等等话侧,總之服務嘛栗精,總是藏在后頭的。
或者可以把 Service 想象成一種消息服務瞻鹏,而你可以在任何有 Context 的地方調用 Context.startService悲立、Context.stopService、Context.bindService新博,Context.unbindService薪夕,來控制它,你也可以在 Service 里注冊 BroadcastReceiver赫悄,在其他地方通過發(fā)送 broadcast 來控制它原献,當然這些都是 Thread 做不到的馏慨。
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.i("MyService","oncreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("MyService","onstartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("MyService","ondestroy");
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
class DownloadBinder extends Binder {
public void startDownload(){
Log.i("Downloadbinder", "startDownload: ");
}
public void getprogress(){
Log.i("Downloadbinder", "getprogress: ");
}
}
}
- onCreate()方法,顧名思義姑隅,在服務創(chuàng)建的時候調用熏纯。
- onStartCommand()方法在每次服務啟動的時候調用。
- onDestroy()方法在服務銷毀的時候調用粤策。
- 啟動服務的方法
Intent startIntent = new Intent(MainActivity.this, MyService.class);
startService(startIntent);
- 暫停服務的方法
Intent stopIntent = new Intent(MainActivity.this,MyService.class);
stopService(stopIntent);
-綁定服務和解綁服務
public class MainActivity extends AppCompatActivity {
private Button changeBt;
private TextView tv1;
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getprogress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
changeBt = (Button) findViewById(R.id.ChangeButton);
tv1 = (TextView) findViewById(R.id.Tv1);
Intent startIntent = new Intent(MainActivity.this, MyService.class);
bindService(startIntent, connection, BIND_AUTO_CREATE);//綁定服務
changeBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(connection);//解綁服務
}
});
}
}
綁定了服務后,可以調用DownloadBinder類里所有public方法误窖。任何一個服務在整個應用程序范圍類都是通用的叮盘,即Myservice不僅可以和MainActivity綁定,還可以和其他后動綁定膛壹。獲取到相同的的Binder實例蛙紫。
使用IntentService筝尾,好處是onHandleIntent已經(jīng)是在子線程中運行了。服務在運行結束后會自動停止愈魏。