在android應用程式裡,有一種沒有UI的類(android.app.Service)——Service。簡單來說,Service是一個 background process(背景程式),通過背景程式,可以實現一些不需要UI的功能,比如播放背景音樂。
下面是一個實現播放背景音樂的常式:
在上個工程的基礎上,在Activity中添加音樂播放功能。
在工程中添加一個新類yypService(File->New->Class):
[java] </pre><pre name="code" class="java">import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class yypService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
</pre><pre name="code" class="java">import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class yypService extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
yypService 類繼承 android.app.Service,幾個有關Service 的重要概念如下:
1. Service 對象以 separated process 的方式執行,這表示 Service 與 UI(Activity)並不在同一個 process 裡執行,而是各自在不同的 process 執行。
2. Android應用程式是在 Activity 啟動與停止 Service。
3. 重載(override)onStart() 方法(method)在 Service 被啟動,執行我們想要的背景功能。
4. 重載 onDestroy() 方法在 Service 被停止時,停止執行中的背景功能。
下面是Service的具體實現:
[java] package com.android;
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
public class yypService extends Service {
private MediaPlayer mp;
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
// 開始播放音樂
mp.start();
// 音樂播放完畢的事件處理
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
// 迴圈播放
try {
mp.start();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
// 播放音樂時發生錯誤的事件處理
mp.setOnErrorListener(new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
// 釋放資源
try {
mp.release();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
});
super.onStart(intent, startId);
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
// 初始化音樂資源
try {
// 建立MediaPlayer對象
mp = new MediaPlayer();
// 將音樂儲存在res/raw/xingshu.mp3,R.java中自動產生{public static final int xingshu=0x7f040000;}
mp = MediaPlayer.create(yypService.this, R.raw.xingshu);
// 在MediaPlayer取得播放資源與stop()之後要準備PlayBack的狀態前一定要使用MediaPlayer.prepeare()
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
// 服務停止時停止播放音樂並釋放資源
mp.stop();
mp.release();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
package com.android;
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
public class yypService extends Service {
private MediaPlayer mp;
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
// 開始播放音樂
mp.start();
// 音樂播放完畢的事件處理
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
// 迴圈播放
try {
mp.start();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
// 播放音樂時發生錯誤的事件處理
mp.setOnErrorListener(new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
// 釋放資源
try {
mp.release();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
});
super.onStart(intent, startId);
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
// 初始化音樂資源
try {
// 建立MediaPlayer對象
mp = new MediaPlayer();
// 將音樂儲存在res/raw/xingshu.mp3,R.java中自動產生{public static final int xingshu=0x7f040000;}
mp = MediaPlayer.create(yypService.this, R.raw.xingshu);
// 在MediaPlayer取得播放資源與stop()之後要準備PlayBack的狀態前一定要使用MediaPlayer.prepeare()
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
// 服務停止時停止播放音樂並釋放資源
mp.stop();
mp.release();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
至此,一個完整的服務產生,接下來是在Activity中啟動服務。
修改 AndroidManifest.xml
在 Package Explorer 視窗裡找到目前 Android 項目的資訊描述檔,名稱為 AndroidManifest.xml。這是一個用來描述 Android 應用程式「整體資訊」的檔案,每個 Android 應用程式項目都會有一個。在這裡修改 Androidmanifest.xml 的目的是為了「 Android 應用程式加入一個 Service 類別」,這樣才有辦法驅動 Service。
[html] <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".WebTestActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".yypService"
android:exported="true"
android:process=":remote">
</service>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".WebTestActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".yypService"
android:exported="true"
android:process=":remote">
</service>
</application>
</manifest>
配置好之後,接下來就是在Activity中添加啟動服務代碼 Service - startService()。
在OnCreate()中添加如下代碼:
[java] Intent intent = new Intent(WebTestActivity.this,yypService.class);
startService(intent);
Intent intent = new Intent(WebTestActivity.this,yypService.class);
startService(intent);
Activity 類裡有一個 method 叫做 startService:
startService(Intent service)
調用 startService() 即可啟動一個 Service ,只是,startService() 的參數是一個「Intent」型,並不是所要啟動的類名。「Intent」是一個很像「Event」的類,暫時還沒對Intent做深入研究,就先把它當作一個"Event"看吧?
現在,其實已經可以在Activity中播放背景音樂了,但有一個小問題,就是Activity已經被掛起或是被銷毀時,背景音樂還是在繼續播放的,這也說明Service與Activity是兩個不同的進程,我們收下尾,讓Activity在OnStop時把背景音樂也停止播放,重載Activity的OnStop:
[java] @Override
protected void onStop() {
// TODO Auto-generated method stub
Intent intent = new Intent(WebTestActivity.this,yypService.class);
stopService(intent);
super.onStop();
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
Intent intent = new Intent(WebTestActivity.this,yypService.class);
stopService(intent);
super.onStop();
}
備忘:eclipse的使用小技巧,快速補全重載代碼(快速鍵Alt+Shift+s -> Override/implement Mothods)。
至此,一個完整的播放背景音樂功能已經全部完成。
摘自 Young的專欄