我有一个广播用户当前位置的简单服务。我想使用绑定机制来控制服务生命周期,但服务只是没有启动。
我做错了什么?
public class GPSActivity extends ListActivity {
...
protected void onResume() {
super.onResume();
Log.i("Service", "Service bound");
Intent intent = new Intent(this, LocationService.class);
bindService(intent, service_connection , Context.BIND_AUTO_CREATE);
}
protected void onPause() {
if (dataUpdateReceiver!=null)
unregisterReceiver(dataUpdateReceiver);
unbindService(service_connection);
super.onPause();
}
class LocationServiceConnection implements ServiceConnection{
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("Service", "Service Connected");
}
public void onServiceDisconnected(ComponentName name) {
}
}
}
LocalBinder.java
public class LocalBinder<S> extends Binder {
private String TAG = "LocalBinder";
private WeakReference<S> mService;
public LocalBinder(S service){
mService = new WeakReference<S>(service);
}
public S getService() {
return mService.get();
}
}
LocationService.java
public class LocationService extends Service {
public void onCreate() {
initLocationListener();
Log.i("Location Service","onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Location Service", "Received start id " + startId + ": " + intent);
return START_NOT_STICKY;
}
private final IBinder mBinder = new LocalBinder<LocationService>(this);
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
AndroidManifest.xml
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
...
<service android:name=".LocationService">
</service>
</application>
编辑:感谢 NickT 的回答。
清单条目没有意图过滤器或正确的名称
<service
android:enabled="true"
android:name="com.android.gps.services.LocationService">
<intent-filter>
<action android:name="com.android.gps.services.LocationService" />
</intent-filter>
</service>
我用于绑定的意图就像你在开始一项活动时需要使用的意图。正确的是:
Intent intent = new Intent("com.android.gps.services.LocationService");
onStartCommand 只会在服务明确启动时执行,看起来你只是想绑定到它,这很好。不过,我没有看到您已正确设置服务连接。我正在发布我的存根程序,它显示了如何绑定到服务并通过活页夹调用服务中的方法。您可能想运行它并查看各种日志消息的顺序。您显然需要添加您的 BroadcastReceiver 和 onLocationChaged 代码以使其对您有用。
活动
package com.servtest.test;
import com.servtest.test.LocationService.LocalBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class ServiceTestActivity extends Activity {
boolean mServiceConnected = false;
boolean mBound = false;
private LocationService mLocnServ;
ServiceConnection mServconn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("SVTEST", "Activity service connected");
LocalBinder binder = (LocalBinder) service;
mLocnServ = binder.getService();
// Can't call this methodInTheService UNTIL IT'S BOUND!
mLocnServ.methodInTheService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("SVTEST", "Activity service disconnected");
mBound = false;
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public void onStart() {
super.onStart();
Log.d("SVTEST", "Activity onStart");
mServiceConnected = bindService(new Intent(
"com.servtest.test.LOCATIONSERVICE"), mServconn,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onResume() {
super.onResume();
Log.d("SVTEST", "Activity onResume");
}
@Override
public void onPause() {
Log.d("SVTEST", "Activity onPause");
super.onPause();
}
@Override
public void onStop() {
Log.d("SVTEST", "Activity onStop");
if (mBound) {
unbindService(mServconn);
mBound = false;
}
super.onStop();
}
}
服务
package com.servtest.test;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class LocationService extends Service implements LocationListener {
private final IBinder mBinder = new LocalBinder();
@Override
public void onLocationChanged(Location arg0) {}
@Override
public void onProviderDisabled(String arg0) {}
@Override
public void onProviderEnabled(String arg0) {}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
@Override
public IBinder onBind(Intent intent) {
Log.d("SVTEST", "Loc service ONBIND");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("SVTEST", "Loc service ONUNBIND");
return super.onUnbind(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Won't run unless it's EXPLICITLY STARTED
Log.d("SVTEST", "Loc service ONSTARTCOMMAND");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("SVTEST", "Loc service ONDESTROY");
}
public class LocalBinder extends Binder {
LocationService getService() {
// Return this instance of LocalService so clients can call public methods
return LocationService.this;
}
}
public void methodInTheService() {
// A method you can call in the service
Log.d("SVTEST", "Loc service EXECUTING THE METHOD");
}
}
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.servtest.test"
android:versionCode="1"
android:versionName="1.0" >
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".ServiceTestActivity"
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:enabled="true"
android:name="LocationService">
<intent-filter>
<action android:name="com.servtest.test.LOCATIONSERVICE" />
</intent-filter>
</service>
</application>
</manifest>
希望这有帮助
我有我的
Activity
工具ServiceConnection
并像这样绑定:
bindService( new Intent( this, Service.class ), this, Context.BIND_AUTO_CREATE );
然后在我的
onServiceConnected()
中处理
onServiceDisconnected()
和
Activity
的回调
当你打电话给
bindService
你可能会得到这个错误:
ActivityManager java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.android.server.am.ActivityRecord$Token
检查 logcat 的输出。
这是Android的一个bug。
要解决它,请使用
getApplicationContext().bindService(...)
我遇到的一个问题是我在服务清单中设置了
android:enabled="false"
。这意味着您的应用也无法绑定。相反:
<service
android:name=".ServiceName"
android:enabled="true"
android:exported="..." />
根据文档:
服务是否可以被系统实例化——如果可以则为“true”,如果不能则为“false”。默认值为“真”。
我错误地认为我的应用程序正在执行实例化,而不是系统。