博主原創轉載請註明作者MskyAndroid
出處http://blog.csdn.net/AndroidMsky/article/details/53407925
GITHUB鏈接:
https://github.com/AndroidMsky/UpdateApp
本文將簡述一個APP升級功能,通過前臺service實時下載一個APK然後跳入安裝界面.
首先回顧一下Service的知識點,service可翻譯爲服務,你可以暫時把它理解爲一個沒有界面的Activity,但是他的生命週期又和activity有所不同。但又大致相同,我認爲唯一需要特別注意的就是onbind方法,是綁定的意思。也就是說一個service自己在黑暗中運行,要如何給他指指路呢,那麼就通過onbind方法,綁定這個service。說起綁定這個詞肯定很多人又開始暈了,其實可以這樣理解,一個Activity去通過ServiceConnection綁定一個service,就是從Activity中拿取一個service中的對象,這個對象往往有一些可以控制service做什麼的方法(這並不是一定的,你可以寫一些沒什麼用的方法因爲這個類的方法都是自己定義的)。
好下面舉個栗子:
本文通過更新按鈕啓動一個service去通過HttpURLConnection去下載一個網絡的apk,並且可以通過獲取進度按鈕獲取實時進度。實時獲取進度,我們就用activity去綁定一個service來實現。
首先也就是我們剛纔說的,activity拿取service的一個對象,這個對象的類型必須是Binder的子類:
class MyBinder extends Binder {
public int getDownload() {
Log.d("TAG", "getDownload ");
return updateCount;
}
}
在service中聲明該對象
private MyBinder mBinder = new MyBinder();
在service這個唯一的抽象方法中返回這個mBinder對象
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
service的工作就做完了,接下來就是activity中寫一個實現serviceConnection接口的類:
class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName arg0, IBinder service) {
Log.d("info", "Service Connection Success");
myBinder = (UpdateService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
Log.d("info", "Service Connection Filed");
//連接失敗執行
}
}
可見兩個方法,一個連接成功一個連接失敗,連接成功方法中的IBinder service也就是傳遞給我們的那個連接二者的對象,操作這個對象的方法,去指揮service中的動作就可以了。
最後啓動service並且綁定:
UpdateService.into(this, getString(R.string.app_name), url);
Intent intent = new Intent(this, UpdateService.class);
bindService(intent,myServiceConnection , Context.BIND_AUTO_CREATE);
相信綁定這塊大家都已經清楚了,接下來就看一下service的生命週期,我們在幾個關鍵的生命週期打一下log。當我們點擊更新按鈕,創造並綁定service:
當我們每次點擊獲取進度按鈕,也就是通過綁定得到那個對象中的方法,都會調用service中的方法執行。
特別需要注意的是即使調用
stopSelf();
service並沒有完全結束,因爲它還被綁定,必須解綁stop兩者同時滿足service纔會停下來,我們就設定如果獲取進度打到100的時候就進行解綁。
public void getprogress(View v){
textView.setText("進度:"+myBinder.getDownload());
if (myBinder.getDownload()==100)
unbindService(myServiceConnection);
}
接下來說一下前臺service一個service如何穿上前臺service的外衣就是在通知欄去創造一個通知它就升級爲前臺service,這樣就有了更高的優先級不容易被系統殺死了,當然這個通知不是通過NotificationManager來顯示出來的,是通過startForeground(1, notification);方法來顯示出來,這樣service就編程前臺service了。
public void createNotification() {
builder = new Notification.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher).setOngoing(false)
.setContentText("正在下載")
.setContentTitle("XXXX下載");
builder.setAutoCancel(false);
builder.setOngoing(true);
builder.setTicker("XXXX正在下載");
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
builder.setProgress(100, 0, false);
Notification notification = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
builder.setPriority(Notification.PRIORITY_MAX);
notification = builder.build();
} else {
notification = builder.getNotification();
}
notification.icon = R.mipmap.ic_launcher;
startForeground(1, notification);
}
另外不要以爲service在後臺沒有界面它就有自己的線程了,錯錯錯,普通的service的代碼默認還是跑在主線程中的,所以我們開啓下載任務也是要重新開啓線程來下載的。
private class DownLoadThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
Message message = new Message();
try {
long downloadSize = downloadUpdateFile(down_url,
FileUtil.updateFile.toString());
if (downloadSize > 0) {
message.what = DOWN_OK;
handler.sendMessage(message);
}
} catch (Exception e) {
message.what = DOWN_ERROR;
handler.sendMessage(message);
}
}
}
相信通過本文的淺談,大家都可以靈活的去使用service了。
歡迎關注作者。歡迎評論討論。歡迎拍磚。 如果覺得這篇文章對你有幫助,歡迎打賞, 歡迎star,Fork我的github。 喜歡作者的也可以Follow。也算對作者的一種支持。
本文Github代碼鏈接
https://github.com/AndroidMsky/UpdateApp
歡迎加作者自營安卓開發交流羣:308372687
—————————————————————————————
作者推薦:
安卓自定義view滾動數據顯示
http://blog.csdn.net/androidmsky/article/details/53009886 RecyclerView
下拉刷新分頁加載性能優化和Gilde配合加載三部曲
http://blog.csdn.net/androidmsky/article/details/53115818
打造企業級網絡請求框架集合retrofit+gson+mvp
http://blog.csdn.net/androidmsky/article/details/52882722
安卓手機自動接起QQ視頻秒變攝像頭
http://blog.csdn.net/androidmsky/article/details/53066441 —————————————————————————————