編輯:關於android開發
Android Service中方法使用詳細介紹
在Android中,Activity主要負責前台頁面的展示,Service主要負責需要長期運行的任務。例如,一個從service播放音樂的音樂播放器,應被設置為前台運行,因為用戶會明確地注意它的運行.在狀態欄中的通知可能會顯示當前的歌曲並且允許用戶啟動一個activity來與音樂播放器交互。
Service的兩種實現形式
1.非綁定
通過調用應用程序組件(例如Activity)的startService()方法來啟動一個服務.一旦啟動,服務就會在後台一直運行,即使應用程序組件此時被關閉.通常,已經啟動的服務會處理一些單一功能,並且也不需要返回結果給調用者.例如,在網絡上下載或上傳文件.當服務的工作處理結束,才會自己關閉服務.
2.綁定(bind)
通過調用應用程序組件的bindService()方法來綁定一個服務.已綁定的服務會提供一個客戶端-服務端交互接口.該接口主要用來與應用程序交互,發送請求,獲取結果,甚至通過IPC來訪問進程.只要一個程序組件綁定服務就會運行綁定服務,多個應用程序組件可以同時時間綁定一個服務.當所有的應用程序組件都解除綁定,該綁定服務器就會被銷毀.
實現service的方法介紹
onStartCommand()
系統在其它組件比如activity通過調用startService()請求service啟動時調用這個方法.一旦這個方法執行,service就啟動並且在後台長期運行.如果你實現了它,你需要負責在service完成任務時停止它,通過調用stopSelf()或stopService().(如果你只想提供綁定,你不需實現此方法).
OnBind()
當組件調用bindService()想要綁定到service時(比如想要執行進程間通訊)系統調用此方法.在你的實現中,你必須提供一個返回一個IBinder來以使客戶端能夠使用它與service通訊,你必須總是實現這個方法,但是如果你不允許綁定,那麼你應返回null.
OnCreate()
系統在service第一次創建時執行此方法,來執行只運行一次的初始化工作(在調用它方法如onStartCommand()或onBind()之前).如果service已經運行,這個方法不會被調用.
OnDestroy()
系統在service不再被使用並要銷毀時調用此方法.你的service應在此方法中釋放資源,比如線程,已注冊的偵聽器,接收器等等.這是service收到的最後一個調用.
如果一個組件通過調用startService()啟動一個service(最終導致onStartCommand()被調用),之後service會保持運行,直到它通過stopSelf()停止自己或另外的組件調用stopService()停止它.
service實現代碼
1.非綁定
新建一個MyService繼承自Service,並重寫父類的onCreate()、onStartCommand()和onDestroy()方法
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
// IntentService會使用單獨的線程來執行該方法的代碼
// 該方法內執行耗時任務,比如下載文件,此處只是讓線程等待20秒
long endTime = System.currentTimeMillis() + 20 * 1000;
System.out.println("onStart");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("----耗時任務執行完成---");
}
}
我們在布局文件中加入了兩個按鈕,一個用於啟動Service,一個用於停止Service。
然後打開或新建MainActivity作為程序的主Activity,在裡面加入啟動Service和停止Service的邏輯,代碼如下所示:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MainActivity extends Activity implements OnClickListener {
private Button startService;
private Button stopService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService = (Button) findViewById(R.id.start_service);
stopService = (Button) findViewById(R.id.stop_service);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
break;
default:
break;
}
}
項目中的每一個Service都必須在AndroidManifest.xml中注冊才行,所以還需要編輯AndroidManifest.xml文件,代碼如下所示:
?
1
2
3
4
5
6
7
8
9
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
……
<service android:name="com.example.servicetest.MyService" >
</service>
</application>
周期分析
onCreate()方法只會在Service第一次被創建的時候調用,如果當前Service已經被創建過了,不管怎樣調用startService()方法,onCreate()方法都不會再執行。因此你可以再多點擊幾次Start Service按鈕試一次,每次都只會有onStartCommand()方法中的打印日志。
2.綁定的service
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
public class LocalBinder extends Binder {
LocalService getService() {
// 返回本service的實例到客戶端,於是客戶端可以調用本service的公開方法
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**客戶端所要調用的方法*/
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
下面是一個綁定到LocalService並且在按鈕按下時調用getRandomNumber()的actvity的例子:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// 綁定到類LocalService的實例
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 從service解除綁定
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** 當按鈕按下時調用(在layout文件中定義的button並用android:onClick 屬性指定響應到本方法) */
public void onButtonClick(View v) {
if (mBound) {
// 調用LocalService的一個方法
// 然而,如果這個調用中有掛起操作,那麼這個請求應發
// 生在另一個線程來避免拉低activity的性能.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** 定義service綁定的回調,傳給bindService() 的*/
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
//我們已經綁定到了LocalService,把IBinder進行強制類型轉換並且獲取LocalService實例.
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
service的周期函數
1、當采用Context.startService()方法啟動服務,與之有關的生命周期方法
onCreate()–> onStart()–> onDestroy()
onCreate()該方法在服務被創建時調用,該方法只會被調用一次,無論調用多少次startService()或bindService()方法,服務也只被創建一次。
onStart() 只有采用Context.startService()方法啟動服務時才會回調該方法。該方法在服務開始運行時被調用。多次調用startService()方法盡管不會多次創建服務,但onStart() 方法會被多次調用。
onDestroy()該方法在服務被終止時調用。
2、 當采用Context.bindService()方法啟動服務,與之有關的生命周期方法
onCreate()–> onBind() –> onUnbind() –> onDestroy()
onBind()只有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務綁定時被調用,當調用者與服務已經綁定,多次調用Context.bindService()方法並不會導致該方法被多次調用。
onUnbind()只有采用Context.bindService()方法啟動服務時才會回調該方法。該方法在調用者與服務解除綁定時被調用。
如果先采用startService()方法啟動服務,然後調用bindService()方法綁定到服務,再調用unbindService()方法解除綁定,最後調用bindService()方法再次綁定到服務,觸發的生命周期方法如下:
onCreate()–>onStart()–>onBind()–>onUnbind()[重載後的方法需返回true–>onRebind()
那麼如果我們既點擊了Start Service按鈕,又點擊了Bind Service按鈕會怎麼樣呢?
這個時候你會發現,不管你是單獨點擊Stop Service按鈕還是Unbind Service按鈕,Service都不會被銷毀,必要將兩個按鈕都點擊一下,Service才會被銷毀。也就是說,點擊Stop Service按鈕只會讓Service停止,點擊Unbind Service按鈕只會讓Service和Activity解除關聯,一個Service必須要在既沒有和任何Activity關聯又處理停止狀態的時候才會被銷毀。
Service和Thread的區別
主要就是因為Service的後台概念。Thread我們大家都知道,是用於開啟一個子線程,在這裡去執行一些耗時操作就不會阻塞主線程的運行。而Service我們最初理解的時候,總會覺得它是用來處理一些後台任務的,一些比較耗時的操作也可以放在這裡運行,這就會讓人產生混淆了。但是,如果我告訴你Service其實是運行在主線程裡的,所以是沒有任何關系的。
Service又有何用呢?
其實大家不要把後台和子線程聯系在一起就行了,這是兩個完全不同的概念。
Android的後台就是指,它的運行是完全不依賴UI的。即使Activity被銷毀,或者程序被關閉,只要進程還在,Service就可以繼續運行。
比如說一些應用程序,始終需要與服務器之間始終保持著心跳連接,就可以使用Service來實現。你可能又會問,前面不是剛剛驗證過Service是運行在主線程裡的麼?在這裡一直執行著心跳連接,難道就不會阻塞主線程的運行嗎?當然會,但是我們可以在Service中再創建一個子線程,然後在這裡去處理耗時邏輯就沒問題了。
使用service創建線程和activity直接創建線程的區別
Activity很難對Thread進行控制,當Activity被銷毀之後,就沒有任何其它的辦法可以再重新獲取到之前創建的子線程的實例。而且在一個Activity中創建的子線程,另一個Activity無法對其進行操作。但是Service就不同了,所有的Activity都可以與Service進行關聯,然後可以很方便地操作其中的方法,即使Activity被銷毀了,之後只要重新與Service建立關聯,就又能夠獲取到原有的Service中Binder的實例。因此,使用Service來處理後台任務,Activity就可以放心地finish,完全不需要擔心無法對後台任務進行控制的情況。
IntentService介紹
IntentService是Service的子類,比普通的Service增加了額外的功能。
先看Service本身存在兩個問題:
Service不會專門啟動一條單獨的進程,Service與它所在應用位於同一個進程中;
Service也不是專門一條新線程,因此不應該在Service中直接處理耗時的任務;
二、IntentService特征
會創建獨立的worker線程來處理所有的Intent請求;
會創建獨立的worker線程來處理onHandleIntent()方法實現的代碼,無需處理多線程問題;
所有請求處理完成後,IntentService會自動停止,無需調用stopSelf()方法停止Service;
為Service的onBind()提供默認實現,返回null;
為Service的onStartCommand提供默認實現,將請求Intent添加到隊列中;
實現
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
// IntentService會使用單獨的線程來執行該方法的代碼
// 該方法內執行耗時任務,比如下載文件,此處只是讓線程等待20秒
long endTime = System.currentTimeMillis() + 20 * 1000;
System.out.println("onStart");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("----耗時任務執行完成---");
}
}
activity代碼
?
1
2
3
4
5
public void startIntentService(View source) {
// 創建需要啟動的IntentService的Intent
Intent intent = new Intent(this, MyIntentService.class);
startService(intent);
電信網絡拓撲圖自動布局在電信網絡拓撲圖中,很經常需要用到自動布局的功能,在大數據的層級關系中,通過手工一個一個擺放位置是不太現實的,工作量是相當大的,那麼就有了自動布局這
Android中使用Notification實現普通通知欄(Notification示例一),rest示例java實現Notification是在你的應用常規界面之外展示
Android自定義實現循環滾輪控件WheelView 首先呈上效果圖 現在很多地方都用到了滾輪布局WheelView,比如在選擇生日的時候,風格類似系統提供的Date
Android Studio2.1.2 Java8環境下引用Java Library編譯出錯,studio2.1.2java8問題:在Android Studio2.1.