Activity啟動Service – 以GPS定位為例
Activity啟動Service – 以GPS定位為例
資料來源:http://mrandroidking.blogspot.tw/2011/02/activityservice-gps.html
Service以背景服務方式提供程序的運作執行. 在其運作執行期間, 並不能直接處理使用者介面的內容, 完全以背景服務方式執行. 如果必提供資料給前景的Activity, 則必須以一個android.os.Handler物件負責處理. 或是呼叫 sendBroadcast()方法送出一個Broadcast, 而由Activity預先產生的BroadcastReceiver負責接受, 進而處理使用者介面.
啟動Service的方式通常是呼叫Context.startService()方法.
一個Activity中有兩個按鈕, 分別處理啟動GPS的啟動與停止, 而有一個文字介面呈現啟動的GPS所傳回相關的資訊. 當啟動按鈕按下之後, 將會由Activity呼叫startService()啟動一個Service的生命周期:
1. onCreate()
2. onStartCommand()
3. onDestroy()
通常會在onCreate()中進行相關的初始化的程序, 而onStartCommand()負責主要的服務程序, 當Activity呼叫了stopService(), 就會使該Service進入到onDestroy()的程序.
此時Service負責蒐集目前GPS相關資訊, 並且將資料以sendBroadcast()方法發送給Activity, Activity會預先一個BroadcastReceiver務件負責接收, 並且將資料呈現在文字介面.
首先, 先簡單處理顯示的版面配置:
main.xml
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<Button
android:id=”@+id/service”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Service”
/>
<Button
android:id=”@+id/stop”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Stop”
/>
<TextView
android:id=”@+id/info”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
/>
</LinearLayout>
接著在Activity中加上一個自訂的BroadcastReceiver:
private class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
double Lat = intent.getDoubleExtra(“Lat”, 0.0);
double Long = intent.getDoubleExtra(“Long”, 0.0);
float Accuracy = intent.getFloatExtra(“Accuracy”, 0.0f);
float Bearing = intent.getFloatExtra(“Bearing”, 0.0f);
float Speed = intent.getFloatExtra(“Speed”, 0.0f);
long Time = intent.getLongExtra(“Time”, 0);
info.setText(“Lat: ” + Lat + “\n” +
“Long” + Long + “\n” +
“Accuracy” + Accuracy + “\n” +
“Bearing” + Bearing + “\n” +
“Speed” + Speed + “\n” +
“Time” + Time + “\n”
);
}
}
上段程式重點如下:
- 繼承 extends BroadcastReceiver, 並Override onReceive()方法
- 假設將會收到一個Intent物件, 其內含地理位置資訊資料.
- 取出資料後, 呈現在 info 的TextView物件中.
回到Activity中:
MyReceiver receiver = new MyReceiver();
IntentFilter filter = new IntentFilter(“MyFilter”);
registerReceiver(receiver, filter);
上段程式重點如下:
- 建構出前段程式中自訂的 MyReceive 物件
- 建構特定的 IntentFilter 物件, 只處理 “MyFilter” 的 Intent.
- 註冊 Receiver, 之後只要收到 Broadcast 後, 觸發 onReceive() 方法
將按鈕及其他部份處理上去:
package tw.brad.android.test.ServiceTest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class ServiceTest extends Activity {
private Button service,stop;
private TextView info;
private MyReceiver receiver;
private IntentFilter filter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
service = (Button)findViewById(R.id.service);
stop = (Button)findViewById(R.id.stop);
info = (TextView)findViewById(R.id.info);
info.setText(“Stop Service”);
receiver = new MyReceiver();
filter = new IntentFilter(“MyFilter”);
registerReceiver(receiver, filter);
service.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra(“mode”, true);
intent.setClass(ServiceTest.this, MyService.class);
startService(intent);
}
});
stop.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra(“mode”, false);
intent.setClass(ServiceTest.this, MyService.class);
startService(intent);
info.setText(“Stop Service”);
}
});
}
private class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
double Lat = intent.getDoubleExtra(“Lat”, 0.0);
double Long = intent.getDoubleExtra(“Long”, 0.0);
float Accuracy = intent.getFloatExtra(“Accuracy”, 0.0f);
float Bearing = intent.getFloatExtra(“Bearing”, 0.0f);
float Speed = intent.getFloatExtra(“Speed”, 0.0f);
long Time = intent.getLongExtra(“Time”, 0);
info.setText(“Lat: ” + Lat + “\n” +
“Long” + Long + “\n” +
“Accuracy” + Accuracy + “\n” +
“Bearing” + Bearing + “\n” +
“Speed” + Speed + “\n” +
“Time” + Time + “\n”
);
}
}
}
接下來將重點放在 Service:
package tw.brad.android.test.ServiceTest;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
public class MyService extends Service {
private LocationManager lm;
private MyLocationListener mll;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
lm = (LocationManager)getSystemService(LOCATION_SERVICE);
mll = new MyLocationListener();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
boolean mode = intent.getBooleanExtra(“mode”, true);
if (mode){
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 0, mll);
}else {
lm.removeUpdates(mll);
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
lm.removeUpdates(mll);
}
private class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
Intent intent = new Intent(“MyFilter”);
intent.putExtra(“Lat”, location.getLatitude());
intent.putExtra(“Long”, location.getLongitude());
intent.putExtra(“Accuracy”, location.getAccuracy());
intent.putExtra(“Bearing”, location.getBearing());
intent.putExtra(“Speed”, location.getSpeed());
intent.putExtra(“Time”, location.getTime());
sendBroadcast(intent);
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
}
不要忘記 AndroidManifest.xml 中處理權限及Service:
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”tw.brad.android.test.ServiceTest”
android:versionCode=”1″
android:versionName=”1.0″>
<application android:icon=”@drawable/icon” android:label=”@string/app_name”>
<activity android:name=”.ServiceTest”
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=”MyService”></service>
</application>
<uses-sdk android:minSdkVersion=”7″ />
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”></uses-permission>
</manifest>