Android:从Activity向Service传递参数

28

我是用以下方式绑定服务的:

活动类:

ListenLocationService mService;
@Override
public void onCreate(Bundle savedInstanceState) {
        ...
        Intent intent = new Intent(this, ListenLocationService.class);
        intent.putExtra("From", "Main");
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        ...
}

private ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName className,
                IBinder service) {
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();         
        }

        public void onServiceDisconnected(ComponentName arg0) {
        }
    };

这是我ServiceonBind方法:

@Override
public IBinder onBind(Intent intent) {
    Bundle extras = intent.getExtras(); 
    if(extras == null)
        Log.d("Service","null");
    else
    {
        Log.d("Service","not null");
        String from = (String) extras.get("From");
        if(from.equalsIgnoreCase("Main"))
            StartListenLocation();
    }
    return mBinder;
}

我在 LogCat 中看到 "null",尽管我已经在 bindService 之前使用了 intent.putExtra。总的来说,服务是正常工作的。然而,我只需要从应用程序的主活动中调用 StartListenLocation();(我决定通过发送一个标志来实现这一点)。

我该如何向服务发送数据?或者也许有另一种方法可以检查启动 onBind 的活动是什么?

3个回答

49

您可以通过以下简单方式传递参数:

Intent serviceIntent = new Intent(this,ListenLocationService.class); 
   serviceIntent.putExtra("From", "Main");
   startService(serviceIntent);

在您的服务类的onStart方法中获取参数

@Override
public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
    Bundle extras = intent.getExtras(); 
    if (extras == null) {
        Log.d("Service","null");
    else {
        Log.d("Service","not null");
        String from = (String) extras.get("From");
        if(from.equalsIgnoreCase("Main"))
        StartListenLocation();
    }
}

享受吧 :)


2
这是按要求传递参数到onBind方法的方式。@yorkw提供了一种很好的通用解决方案,可以从服务中调用Activity。 - Brent Faust
onStart已被弃用,请使用onStartCommand代替。 - Konstantin Konopko

15

1 创建一个接口,声明从Activity中要调用的所有方法的签名:

public interface ILocationService {
  public void StartListenLocation(Location location);
}

2 让你的binder实现ILocaionService接口,并定义实际的方法体:

public class MyBinder extends Binder implements ILocationService {
  ... ...

  public void StartListenLocation(Location location) {
    // implement your method properly
  }

  ... ...
}

在绑定服务的活动中,通过接口引用你的binder:

... ...

ILocationService mService; // communication is handled via Binder not the actual service class.

private ServiceConnection mConnection = new ServiceConnection() {

  public void onServiceConnected(ComponentName className, IBinder service) {
    mService = (ILocationService) service;     
  }

  ... ...
};

... ...

// At some point if you need call service method with parameter:
Location location = new Location();
mService.StartListenLocation(location);

所有通信(即对您的服务的方法调用)应该通过绑定类在ServiceConnection.onServiceConnected()中进行处理和执行,而不是实际的服务类(binder.getService()是不必要的)。这就是绑定服务通信在API中的设计。

请注意,bindService()是一个异步调用。在您调用bindService()之后,在系统介入ServiceConnection.onServiceConnected()回调之前会有一段时间间隔。所以在ServiceConnection.onServiceConnected()方法中,mService初始化后立即执行服务方法的位置最佳。

希望这可以帮助到您。


谢谢你的回答。后来我遇到了另一个问题,也许你知道如何解决:http://stackoverflow.com/questions/9956601/android-set-and-get-services-variable-in-different-activities - Ilya Blokh
@yorkw,“这就是API中绑定服务通信设计的工作方式” - 我并不怀疑你的正确性,但你有没有一些官方的Android文档链接,我可以在上面阅读更多相关信息呢? - DuneCat
2
@DuneCat,我同意这个说法并不完全准确,实际上它引用了Google建议实现绑定服务的一种推荐方式,更多详情请参见这里 - yorkw

-1
根据这个会话 http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html 向服务发送数据的一种方法是使用包含pid(进程ID)、data(数据)、status(状态)等列的数据库,其中状态可以是READ、READY、BINDING等等。当服务加载时,它会读取由调用活动填充的表格,并在完成后删除。另一种指示的方法是AIDL,根据您的应用程序选择适合的方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接