使用Intent将数据从Activity传递到Service

90

我如何在Android Service中获取从调用Activity传递的数据?

9个回答

234

如何从Activity发送数据到Service?要精确回答这个问题,您需要覆盖onStartCommand()方法以接收意图对象:

当您创建一个Service时,应该覆盖onStartCommand()方法。如果您仔细看下面的签名,这是接收传递给它的intent对象的地方:

  public int onStartCommand(Intent intent, int flags, int startId)

因此,从一个活动中,您将创建意图对象来启动服务,然后将您的数据放入意图对象中。例如,您想要从Activity传递UserIDService

 Intent serviceIntent = new Intent(YourService.class.getName())
 serviceIntent.putExtra("UserID", "123456");
 context.startService(serviceIntent);

当服务启动时,它的onStartCommand()方法将被调用,在这个方法中,您可以从意图对象中检索值(UserID),例如:

当服务启动时,它的onStartCommand()方法将被调用,在这个方法中,您可以从意图对象中检索值(UserID),例如:

public int onStartCommand (Intent intent, int flags, int startId) {
    String userID = intent.getStringExtra("UserID");
    return START_STICKY;
}

注意:上面的答案指定使用getIntent()方法获取Intent,但在服务的上下文中不正确。


56
应该接受这个答案。针对“服务(Service)”,被接受的答案是错误的。 - zeeshan
1
我有这个错误:未能启动服务 Intent:未找到 - fullOfQuestion
getintent现已弃用。 - DikShU
2
服务启动后,我如何向服务发送意图? - Lavnish Chaudhary
那么你只能在 onStartCommand 函数内部访问变量,这使得它变得相当无用,不是吗? - Yunfei Chen

44

第一个上下文(可为Activity/Service等)

对于服务,您需要重写onStartCommand,这样您就可以直接访问意图:intent

Override
public int onStartCommand(Intent intent, int flags, int startId) {

您有以下几个选项:

1) 使用 Intent 中的 Bundle

Intent mIntent = new Intent(this, Example.class);
Bundle extras = mIntent.getExtras();
extras.putString(key, value);  

2) 创建一个新的 Bundle

Intent mIntent = new Intent(this, Example.class);
Bundle mBundle = new Bundle();
mBundle.extras.putString(key, value);
mIntent.putExtras(mBundle);

3) 使用 Intent 的 putExtra() 快捷方法

Intent mIntent = new Intent(this, Example.class);
mIntent.putExtra(key, value);

新上下文(可以是Activity/Service等)

Intent myIntent = getIntent(); // this getter is just for example purpose, can differ
if (myIntent !=null && myIntent.getExtras()!=null)
     String value = myIntent.getExtras().getString(key);
}

注意: Bundles(捆绑包)具有所有原始类型、可传递的对象和可序列化对象的“get”和“put”方法。我只是出于演示目的使用了字符串。


30
但是我们不能在服务中使用 getIntent() 方法。当我们需要从活动向服务发送值时,该怎么做呢?请提供解决方法。 - Chanaka udaya
5
只需使用意图,无需使用getIntent()。 - Neelay Srivastava
2
这不应该被接受为答案,因为这并不是服务的正确解决方案。 - NoHarmDan

10

如果您绑定了服务,您将在onBind(Intent intent)中获得额外的内容。

活动:

 Intent intent = new Intent(this, LocationService.class);                                                                                     
 intent.putExtra("tour_name", mTourName);                    
 bindService(intent, mServiceConnection, BIND_AUTO_CREATE); 

服务:

@Override
public IBinder onBind(Intent intent) {
    mTourName = intent.getStringExtra("tour_name");
    return mBinder;
}

@ChefPharaoh 这是一个好问题。尝试记录意图的值。Arrays.toString(yourAry[]) 将会对你有所帮助。 - Martin Pfeffer
1
由于我想传递一个自定义类,我发现我只需要实现Parcelable接口就可以了,然后一切都很好。不过还是谢谢。 - Chef Pharaoh

7

另一种可能性是使用intent.getAction:

在服务中:

public class SampleService inherits Service{
    static final String ACTION_START = "com.yourcompany.yourapp.SampleService.ACTION_START";
    static final String ACTION_DO_SOMETHING_1 = "com.yourcompany.yourapp.SampleService.DO_SOMETHING_1";
    static final String ACTION_DO_SOMETHING_2 = "com.yourcompany.yourapp.SampleService.DO_SOMETHING_2";
    static final String ACTION_STOP_SERVICE = "com.yourcompany.yourapp.SampleService.STOP_SERVICE";

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action = intent.getAction();
        //System.out.println("ACTION: "+action);
        switch (action){
            case ACTION_START:
                startingService(intent.getIntExtra("valueStart",0));
                break;
            case ACTION_DO_SOMETHING_1:
                int value1,value2;
                value1=intent.getIntExtra("value1",0);
                value2=intent.getIntExtra("value2",0);
                doSomething1(value1,value2);
                break;
            case ACTION_DO_SOMETHING_2:
                value1=intent.getIntExtra("value1",0);
                value2=intent.getIntExtra("value2",0);
                doSomething2(value1,value2);
                break;
            case ACTION_STOP_SERVICE:
                stopService();
                break;
        }
        return START_STICKY;
    }

    public void startingService(int value){
        //calling when start
    }

    public void doSomething1(int value1, int value2){
        //...
    }

    public void doSomething2(int value1, int value2){
        //...
    }

    public void stopService(){
        //...destroy/release objects
        stopself();
    }
}

在Activity中:

public void startService(int value){
    Intent myIntent = new Intent(SampleService.ACTION_START);
    myIntent.putExtra("valueStart",value);
    startService(myIntent);
}

public void serviceDoSomething1(int value1, int value2){
    Intent myIntent = new Intent(SampleService.ACTION_DO_SOMETHING_1);
    myIntent.putExtra("value1",value1);
    myIntent.putExtra("value2",value2);
    startService(myIntent);
}

public void serviceDoSomething2(int value1, int value2){
    Intent myIntent = new Intent(SampleService.ACTION_DO_SOMETHING_2);
    myIntent.putExtra("value1",value1);
    myIntent.putExtra("value2",value2);
    startService(myIntent);
}

public void endService(){
    Intent myIntent = new Intent(SampleService.STOP_SERVICE);
    startService(myIntent);
}

最后,在清单文件中:

<service android:name=".SampleService">
    <intent-filter>
        <action android:name="com.yourcompany.yourapp.SampleService.ACTION_START"/>
        <action android:name="com.yourcompany.yourapp.SampleService.DO_SOMETHING_1"/>
        <action android:name="com.yourcompany.yourapp.SampleService.DO_SOMETHING_2"/>
        <action android:name="com.yourcompany.yourapp.SampleService.STOP_SERVICE"/>
    </intent-filter>
</service>

1
您正在多次启动服务...这是否意味着每次都会创建相同服务的多个实例? - oshurmamadov
4
服务具有单例模式。https://dev59.com/qHE85IYBdhLWcg3w_Itr - Carlos Gómez
"switch (action)" 操作可以为空。 - Marian Paździoch
不在我的代码中:该服务始终使用方法调用。无论如何,这是一个简单的代码,用于解释如何执行操作。在实际程序中,您总是需要检查这些内容,以及参数是否具有适当的值。 - Carlos Gómez

3

活动:

int number = 5;
Intent i = new Intent(this, MyService.class);
i.putExtra("MyNumber", number);
startService(i);

服务:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null && intent.getExtras() != null){
        int number = intent.getIntExtra("MyNumber", 0);
    }
}

2

从Activity传递数据到IntentService

以下是我如何将数据从Activity传递到IntentService

我的应用程序中有这种情况。

MusicActivity ------url(String)------> DownloadSongService

1)发送数据(Activity代码)

  Intent intent  = new Intent(MusicActivity.class, DownloadSongService.class);
  String songUrl = "something"; 
  intent.putExtra(YOUR_KEY_SONG_NAME, songUrl);
  startService(intent);

2) 在服务中获取数据(IntentService代码)
您可以在onHandleIntent()方法中访问意图(intent)。

public class DownloadSongService extends IntentService {

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

        String songUrl = intent.getStringExtra("YOUR_KEY_SONG_NAME");

        //  Download File logic
    
    }

}

1

这是一种更好、更安全的方式。像魔法一样工作!

   private void startFloatingWidgetService() {
        startService(new Intent(MainActivity.this,FloatingWidgetService.class)
                .setAction(FloatingWidgetService.ACTION_PLAY));
    }

代替:
 private void startFloatingWidgetService() {
        startService(new Intent(FloatingWidgetService.ACTION_PLAY));
    }

因为当你尝试第二个方法时,会出现以下错误:

java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.floatingwidgetchathead_demo.SampleService.ACTION_START }

那么你的服务应该像这样:

static final String ACTION_START = "com.floatingwidgetchathead_demo.SampleService.ACTION_START";
    static final String ACTION_PLAY = "com.floatingwidgetchathead_demo.SampleService.ACTION_PLAY";
    static final String ACTION_PAUSE = "com.floatingwidgetchathead_demo.SampleService.ACTION_PAUSE";
    static final String ACTION_DESTROY = "com.yourcompany.yourapp.SampleService.ACTION_DESTROY";

 @SuppressLint("LogConditional")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    String action = intent.getAction();
    //System.out.println("ACTION: "+action);
    switch (action){
        case ACTION_START:
            Log.d(TAG, "onStartCommand: "+action);
            break;
        case ACTION_PLAY:
            Log.d(TAG, "onStartCommand: "+action);
           addRemoveView();
           addFloatingWidgetView();
            break;
        case ACTION_PAUSE:
            Log.d(TAG, "onStartCommand: "+action);
            break;
        case ACTION_DESTROY:
            Log.d(TAG, "onStartCommand: "+action);
            break;
    }
    return START_STICKY;

}

0

服务:启动服务可能会产生副作用,最好的方法是使用 Messenger 并传递数据。

private CallBackHandler mServiceHandler= new CallBackHandler(this);
private Messenger mServiceMessenger=null;
//flag with which the activity sends the data to service
private static final int DO_SOMETHING=1;

private static class CallBackHandler extends android.os.Handler {

private final WeakReference<Service> mService;

public CallBackHandler(Service service) {
    mService= new WeakReference<Service>(service);
}

public void handleMessage(Message msg) {
    //Log.d("CallBackHandler","Msg::"+msg);
    if(DO_SOMETHING==msg.arg1)
    mSoftKeyService.get().dosomthing()
}
}

操作:从Intent中获取Messenger,填充数据并将消息传递回服务。

private Messenger mServiceMessenger;
@Override
protected void onCreate(Bundle savedInstanceState) {
mServiceMessenger = (Messenger)extras.getParcelable("myHandler");
}


private void sendDatatoService(String data){
Intent serviceIntent= new 
Intent(BaseActivity.this,Service.class);
Message msg = Message.obtain();
msg.obj =data;
msg.arg1=Service.DO_SOMETHING;
mServiceMessenger.send(msg);
}

0
如果您正在使用Kotlin,可以尝试以下代码:
在发送活动中,
  val intent = Intent(context, RecorderService::class.java);
  intent.putExtra("filename", filename);
  context.startService(intent)

在编程服务中,

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
    super.onStartCommand(intent, flags, startId)

    if (intent != null && intent.extras != null)
       val filename = intent.getStringExtra("filename")

}

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