如何将数据从活动传递到正在运行的服务

Posted

技术标签:

【中文标题】如何将数据从活动传递到正在运行的服务【英文标题】:how to pass data from activity to running service 【发布时间】:2017-09-29 21:47:29 【问题描述】:

我想定期向服务器发送数据,为此我正在使用后台 Service,但我想在数据更新时发送,以及我在 Activity 和 @987654325 中获得的更新数据@ 正在后台运行.. 那么我如何将数据从 Activity 传递给正在运行的 Service。使用Intent,我在启动Service时只能发送一次数据。

Intent serviceIntent= new Intent(DriverActivity.this,demoService.class);
serviceIntent.putExtra("token", token);
startService(serviceIntent);

【问题讨论】:

我的意见是使用事件总线或广播接收器 您好,您可以使用广播接收器将数据发送到正在运行的服务或***.com/questions/15346647/… 您可以使用startService() 向正在运行的服务多次发送数据。如果 Service 已经启动,这不会启动它,但会使用 Intent 中的数据调用 onStartCommand() android: Passing variables to an already running service的可能重复 【参考方案1】:

阅读这篇文章https://developer.android.com/guide/components/bound-services.html

例如你可以使用Messanger

public class MessengerService extends Service 
    /** Command to the service to display a message */
    static final int MSG_SAY_HELLO = 1;

    /**
     * Handler of incoming messages from clients.
     */
    class IncomingHandler extends Handler 
        @Override
        public void handleMessage(Message msg) 
            switch (msg.what) 
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            
        
    

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) 
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    

而在您的ActivityFragment 中,您可以通过这种方式发送数据:

public class ActivityMessenger extends Activity 
    /** Messenger for communicating with the service. */
    Messenger mService = null;

    /** Flag indicating whether we have called bind on the service. */
    boolean mBound;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() 
        public void onServiceConnected(ComponentName className, IBinder service) 
            // This is called when the connection with the service has been
            // established, giving us the object we can use to
            // interact with the service.  We are communicating with the
            // service using a Messenger, so here we get a client-side
            // representation of that from the raw IBinder object.
            mService = new Messenger(service);
            mBound = true;
        

        public void onServiceDisconnected(ComponentName className) 
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mBound = false;
        
    ;

    public void sayHello(View v) 
        if (!mBound) return;
        // Create and send a message to the service, using a supported 'what' value
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try 
            mService.send(msg);
         catch (RemoteException e) 
            e.printStackTrace();
        
    

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    

    @Override
    protected void onStart() 
        super.onStart();
        // Bind to the service
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    

    @Override
    protected void onStop() 
        super.onStop();
        // Unbind from the service
        if (mBound) 
            unbindService(mConnection);
            mBound = false;
        
    

如果您不知道如何使用 Message 传递数据,请查看此答案 https://***.com/a/17929775

【讨论】:

这需要绑定到Service,并且比再次调用startService() 发送更多数据要复杂一些。否则这是一个完美的解决方案。 @DavidWasser,是的。但如果是服务,为了管理 api 调用,他应该在服务中创建工作线程。发送意图,通过 startService 在单独的线程中处理,对于我和其他将来可能支持应用程序的程序员来说并不明确。如果 IntentService 在第一个 handleIntent 服务之后应该停止。所以,我认为,如果服务应该执行长时间运行的任务并且可以在运行时接受数据,他应该使用绑定并通过信使或一些自定义服务方法传递数据,但这也是需要绑定的。 显然IntentService 不是正确的解决方案。在这里,您需要一个可以自己启动和停止的常规Service。绝对没有理由不能或不应该使用startService()Intent 传递给正在运行的ServiceService 无论如何都应该启动一个后台线程来进行处理,因此您可以随时通过发送新的Intent 来控制Service @Alexander Goncharenko ,我想以 START_STICKY 模式启动服务。使用此解决方案,我认为未调用 onStartCommand 方法。如何在您的解决方案中使用 STICKY 模式?【参考方案2】:

最好的选择是将数据保存在硬盘上(例如 SharedPreferences、数据库等)。

Activity 已更新 => 保存到存储 => 调用 Service

服务必须在发送数据之前从所选存储中读取数据。

【讨论】:

【参考方案3】:

改用多线程会变得更容易,并且您将获得相同的功能。

 mHandler = new Handler();

    // Set a click listener for button
    btn.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            mCounter = 0;
            /*
                Runnable
                    Represents a command that can be executed. Often used to run code in a
                    different Thread.

                Thread
                    A Thread is a concurrent unit of execution. It has its own call stack for
                    methods being invoked, their arguments and local variables. Each application
                    has at least one thread running when it is started, the main thread, in the
                    main ThreadGroup. The runtime keeps its own threads in the system thread group.

                    There are two ways to execute code in a new thread. You can either subclass
                    Thread and overriding its run() method, or construct a new Thread and pass a
                    Runnable to the constructor. In either case, the start() method must be
                    called to actually execute the new Thread.

            */
            mRunnable = new Runnable() 
                /*
                    public abstract void run ()
                        Starts executing the active part of the class' code. This method is
                        called when a thread is started that has been created with a class which
                        implements Runnable.
                */
                @Override
                public void run() 
                    // Do some task on delay
                    doTask();
                
            ;

            /*
                public final boolean postDelayed (Runnable r, long delayMillis)
                    Causes the Runnable r to be added to the message queue, to be run after the
                    specified amount of time elapses. The runnable will be run on the thread to
                    which this handler is attached. The time-base is uptimeMillis(). Time spent
                    in deep sleep will add an additional delay to execution.
            */
            mHandler.postDelayed(mRunnable, (mInterval));
        
    ); //use minterval to be the period in ms eg:     private int mInterval = 4000;

【讨论】:

【参考方案4】:

1.向服务Upto Lolipop版本发送数据

Intent serviceIntent= new Intent(DriverActivity.this,demoService.class);
serviceIntent.putExtra("token", token);
startService(serviceIntent);

    在服务类中检索数据:

     @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    
    Toast.makeText(this, "Starting..", Toast.LENGTH_SHORT).show();
    Log.d(APP_TAG,intent.getStringExtra("token"));
    return "your flag";
    
    

【讨论】:

我在我的问题中问过我想通过使用意图将数据发送到正在运行的服务,但我不能只发送一次。 @TusharKotecha 不正确。您可以通过使用Intent 调用startService() 将数据发送到正在运行的Service。在Service 中,onStartCommand() 会在你正在运行的服务上被调用。 这当然是最简单的方法,虽然还有很多其他方法。 @Rajasekhar 如果我每次想发送数据时都使用 startService(),那么它会创建一个新线程或新服务吗?或者它会给设备带来负担?基本上你想说 startService() 和通过意图传递数据会将数据传递给正在运行的服务? @Rajasekhar 回答上述问题

以上是关于如何将数据从活动传递到正在运行的服务的主要内容,如果未能解决你的问题,请参考以下文章

如何将上下文从活动传递到服务

以非常高的速度将连续数据从服务发送到活动

如何将数据从一项活动传递到多项活动?

如何使用数据库将大量数据从一个活动传递到android中的另一个活动

如何将数据从一个活动传递到android中的另一个活动片段? [复制]

将活动之间的数据从列表视图传递到另一个活动