編輯:關於Android編程
Service是一個可以在後台執行長時間運行操作而不使用用戶界面的應用組件.Service可由其他應用組件啟動,而且即使用戶切換到其他應用,Service仍將在後台繼續運行.Service主要用於在後台處理一些耗時的邏輯,或者去執行某些需要長期運行的任務.必要的時候我們甚至可以在程序退出的情況下,讓Service在後台繼續保持運行狀態.
Service和Activity很相似,但是區別在於:Service一直在後台運行,沒有用戶界面,所以不會到前台,如果Service被啟動起來,就和Activity一樣,具有自己的聲明周期.另外,需要注意的是,Service和Thread不是一個意思,不要被Service的後台概念所迷惑.實際上Service並不會自動開啟線程,所有的代碼都是默認運行在主線程中的.因此,我們需要在Service的內部手動創建子線程,並在這裡執行具體的任務,否則可能造成ANR的問題.
Bound(綁定的) 當應用組件通過調用 bindService() 綁定到Service時,Service即處於“綁定”狀態.一個綁定的Service提供客戶端/服務器接口允許組件和Service交互,甚至跨進程操作使用進行間通信(IPC).僅當與另一個應用組件綁定時,綁定服務才會運行.多個組件可以同時綁定到該服務,但全部取消綁定後,該服務即會被銷毀.一個形象的比喻bindService,//這種方式,就是說:“起來,快去干活,有事電話聯系”。
package com.servicedemo; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; /** * Created by YK on 2016/8/26. */ public class MyService extends Service { //當其他組件調用bindService()方法請求綁定Service時,該方法被回調。(默認為null) @Override public IBinder onBind(Intent intent) { Log.e("kaka", "onBind"); return null; } //當Service第一次創建時,回調該方法(只一次)。 @Override public void onCreate() { super.onCreate(); Log.e("kaka", "onCreate"); } //當其他組件調用startService()方法請求啟動Service時,該方法被回調(每次)。 @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e("kaka", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } //當Service被銷毀時回調,在該方法中應清除一些占用的資源。 @Override public void onDestroy() { super.onDestroy(); Log.e("kaka", "onDestroy"); } }Service是Android四大基本組件之一,那麼就必須在AndroidManifest.xml中注冊
在MainActivity中加入啟動Service和停止Service的方法
package com.servicedemo; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button mStartService, mStopService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); mStartService.setOnClickListener(this); mStopService.setOnClickListener(this); } private void initView() { mStartService = (Button) findViewById(R.id.start); mStopService = (Button) findViewById(R.id.stop); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.start: Intent startIntent = new Intent(this, MyService.class); startService(startIntent); break; case R.id.stop: Intent stopIntent = new Intent(this, MyService.class); stopService(stopIntent); break; default: break; } } }
結論:Service只有在第一次啟動的時候才會調用onCreate()方法,此後再次點擊Start Service按鈕只會執行onStartCommand()方法,並不會再啟動一個服務。
如何讓Activity與Service產生“羁絆"呢?這裡就需要使用之前MyService中沒有使用的方法onBind()了,這個方法就是用於與Activity建立關聯的。先修改MyService的代碼,新增了一個MyBinder類繼承自Binder類,MyBinder中添加了一個doSomething()方法用於執行你要執行的後台任務。
package com.servicedemo; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; /** * Created by YK on 2016/8/26. */ public class MyService extends Service { //當其他組件調用bindService()方法請求綁定Service時,該方法被回調。(默認為null) @Override public IBinder onBind(Intent intent) { Log.e("kaka", "onBind"); return new MyBinder(); } //當Service第一次創建時,回調該方法(只一次)。 @Override public void onCreate() { super.onCreate(); Log.e("kaka", "onCreate"); } //當其他組件調用startService()方法請求啟動Service時,該方法被回調(每次)。 @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e("kaka", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public boolean onUnbind(Intent intent) { Log.e("kaka", "onUnbind"); return super.onUnbind(intent); } //當Service被銷毀時回調,在該方法中應清除一些占用的資源。 @Override public void onDestroy() { super.onDestroy(); Log.e("kaka", "onDestroy"); } class MyBinder extends Binder { public void doSomething(){ Log.e("kaka","doSomething"); } } }
package com.servicedemo; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button mStartService, mStopService; private MyService.MyBinder myBinder; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e("kaka", "onServiceConnected"); myBinder = (MyService.MyBinder) service; myBinder.doSomething(); } @Override public void onServiceDisconnected(ComponentName name) { Log.e("kaka", "onServiceDisconnected"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); mStartService.setOnClickListener(this); mStopService.setOnClickListener(this); } private void initView() { mStartService = (Button) findViewById(R.id.start); mStopService = (Button) findViewById(R.id.stop); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.start: //這裡傳入BIND_AUTO_CREATE,表示在Activity和Service關聯後自動創建Service, //這會使得MyService中的onCreate()方法得到執行,但onStartCommand()方法不會執行。 Intent startIntent = new Intent(this, MyService.class); bindService(startIntent, conn, BIND_AUTO_CREATE); break; case R.id.stop: //如果沒有綁定服務就執行unbindService是會報錯, java.lang.IllegalArgumentException: Service not registered: unbindService(conn); break; default: break; } } }
@Override protected void onDestroy(){ super.onDestroy(); unbindService(conn); }點擊綁定服務後再點擊解綁: 我們可以知道,多次點擊綁定服務按鈕,並不會重復執行ServiceConnection中的onServiceConnected()方法。
1). 被啟動的服務的生命周期:如果一個Service被某個Activity 調用 Context.startService 方法啟動,那麼不管是否有Activity使用bindService綁定或unbindService解除綁定到該Service,該Service都在後台運行。如果一個Service被startService 方法多次啟動,那麼onCreate方法只會調用一次,onStartCommand將會被調用多次(對應調用startService的次數),並且系統只會創建Service的一個實例(因此你應該知道只需要一次stopService調用)。該Service將會一直在後台運行,而不管對應程序的Activity是否在運行,直到被調用stopService,或自身的stopSelf方法。當然如果系統資源不足,android系統也可能結束服務。
2). 被綁定的服務的生命周期:如果一個Service被某個Activity 調用 Context.bindService 方法綁定啟動,不管調用 bindService 調用幾次,onCreate和onBind方法都只會調用一次,同時onStartCommand方法始終不會被調用。當連接建立之後,Service將會一直運行,除非調用Context.unbindService 斷開連接或者之前調用bindService 的 Context 不存在了(如Activity被finish的時候),系統將會自動停止Service,對應onDestroy將被調用。
3). 被啟動又被綁定的服務的生命周期:如果一個Service又被啟動又被綁定,則該Service將會一直在後台運行。並且不管如何調用,onCreate始終只會調用一次,對應startService調用多少次,Service的onStartCommand便會調用多少次。調用unbindService將不會停止Service,而必須調用 stopService 或 Service的 stopSelf 來停止服務。
4). 當服務被停止時清除服務:當一個Service被終止(1、調用stopService;2、調用stopSelf;3、不再有綁定的連接(沒有被啟動))時,onDestroy方法將會被調用,在這裡你應當做一些清除工作,如停止在Service中創建並運行的線程。
注意:1、使用startService的時候,一般在onStartCommand()中寫主要的邏輯代碼,但是Service運行在主線程中,所以Service本身不能做耗時操作。如果做耗時操作或訪問網絡可以使用異步任務、子線程、Loader等來處理。
特別注意:
1、你應當知道在調用 bindService 綁定到Service的時候,你就應當保證在某處調用 unbindService 解除綁定(盡管 Activity 被 finish 的時候綁定會自動解除,並且Service會自動停止);
2、你應當注意 使用 startService 啟動服務之後,一定要使用 stopService停止服務,不管你是否使用bindService;
3、同時使用 startService 與 bindService 要注意到,Service 的終止,需要unbindService與stopService同時調用,才能終止 Service,不管 startService 與 bindService 的調用順序,如果先調用 unbindService 此時服務不會自動終止,再調用 stopService 之後服務才會停止,如果先調用 stopService 此時服務也不會終止,而再調用 unbindService 或者 之前調用 bindService 的 Context 不存在了(如Activity 被 finish 的時候)之後服務才會自動停止;
4、當在旋轉手機屏幕的時候,當手機屏幕在“橫”“豎”變換時,此時如果你的 Activity 如果會自動旋轉的話,旋轉其實是 Activity 的重新創建,因此旋轉之前的使用 bindService 建立的連接便會斷開(Context 不存在了),對應服務的生命周期與上述相同。
5、在 sdk 2.0 及其以後的版本中,對應的 onStart 已經被否決變為了 onStartCommand,不過之前的 onStart仍然有效。這意味著,如果你開發的應用程序用的 sdk 為 2.0 及其以後的版本,那麼你應當使用 onStartCommand 而不是 onStart。
都是後台運行,那麼Service和Thread的選擇就會迷惑不少人,什麼時候用Service?什麼時候用Thread?
區別:
Service是運行在主線程裡的,而Thread是開辟新的線程。(即如果在Service裡編寫了非常耗時的代碼,程序必定會出現ANR的) Service後台是指它的運行完全不依賴UI,即使Activity被銷毀,或者程序被關閉,只要進程還在,Service就可以運行。(耗時的操作可以在Service中創建一個子線程去處理即可) 既然都要創建子線程,為什麼不在Activity中創建而是到Service中?
這是因為Activity很難對Thread進行控制,當Activity被銷毀後,就無法獲取到Thread的實例了,而且在1Activity中創建的線程,在2Activity中是無法對其進行操作的。但Service不受這些約束,只要進程還在,Activity即使被銷毀了,也能對子線程進行控制。
Service基本都是後台運行的,既然後台運行有時候希望它能一直運行,比如時鐘,或者需要實時運行的服務。但是Service的系統優先級還是比較低的,當系統出現了內存不足的情況,還是有可能回收掉正在後台運行的Service,Service如果要防止盡可能不被系統殺掉,需要設置為在前台運行。就像QQ一樣,會在系統狀態欄一直顯示一個圖標信息。
由於設置前台運行service的方法在2.0之前和2.0之後有所變化。所以需要根據不同的版本進行區分;或者完全使用反射機制來處理,這樣只要有相應的方法就可以使用,否則使用其他版本的方法。修改MyService中的代碼為:
待續。。。
官方文檔告訴我們,Android系統會盡量保持擁有service的進程運行,只要在該service已經被啟動(start)或者客戶端連接(bindService)到它。當內存不足時,需要保持,擁有service的進程具有較高的優先級。
如果service正在調用onCreate,onStartCommand或者onDestory方法,那麼用於當前service的進程則變為前台進程以避免被killed。如果當前service已經被啟動(start),擁有它的進程則比那些用戶可見的進程優先級低一些,但是比那些不可見的進程更重要,這就意味著service一般不會被killed.如果客戶端已經連接到service (bindService),那麼擁有Service的進程則擁有最高的優先級,可以認為service是可見的。如果service可以使用startForeground(int, Notification)方法來將service設置為前台狀態,那麼系統就認為是對用戶可見的,並不會在內存不足時killed。如果有其他的應用組件作為Service,Activity等運行在相同的進程中,那麼將會增加該進程的重要性。
參考資料:
官方文檔:https://developer.android.com/reference/android/app/Service.html
一、概述大家編寫項目的時候,肯定會或多或少的使用Log,尤其是發現bug的時候,會連續在多個類中打印Log信息,當問題解決了,然後又像狗一樣一行一行的去刪除剛才隨便添加的
Cocos2d-x 3.0 - Eclipse上構建一個Android項目2014年4月30日 4月末 本篇繼續介紹Cocos2d-x 3.0的一些基礎內容,前面一篇博客
自己研究的安卓app簽核系統,目前公司內部用著好像也相對穩定,就用這篇文章記錄一下工具環境:Eclipse4.2 ADT23.0 JDK1.8.0 服務端vs2010簡單
main.xml代碼如下: .java代碼如下: package org.lxh.demo; import androi