как передать данные из активности в запущенную службу

Я хочу периодически отправлять данные на сервер, я использую для этого фон Service, но я хочу отправлять, когда данные обновляются, и обновленные данные я получаю в Activity, а Service работает в фоновом режиме.. так как могу ли я передать данные для запуска Service из Activity. Используя Intent, я могу отправить данные только один раз при запуске Service.

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

person Tushar Kotecha    schedule 02.05.2017    source источник
comment
Мое мнение - использовать шину событий или широковещательный приемник.   -  person Piyush    schedule 02.05.2017
comment
Привет. Вы можете использовать широковещательный приемник для отправки данных в работающую службу или stackoverflow.com/questions/15346647/   -  person Vasudev Vyas    schedule 02.05.2017
comment
Вы можете отправлять данные в работающую службу столько раз, сколько хотите, с помощью startService(). Это не запускает Service, если он уже запущен, но вызовет onStartCommand() с данными в Intent.   -  person David Wasser    schedule 02.05.2017
comment
Возможный дубликат Android: передача переменных в уже запущенную службу   -  person SafalFrom2050    schedule 30.05.2018


Ответы (4)


Прочтите эту статью 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();
    }
}

А в свой Activity или Fragment можно отправлять данные таким образом:

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://stackoverflow.com/a/17929775

person Alexander Goncharenko    schedule 02.05.2017
comment
Это требует привязки к Service и несколько сложнее и тяжелее, чем просто повторный вызов startService() для отправки дополнительных данных. В противном случае это совершенно нормальное решение. - person David Wasser; 02.05.2017
comment
@ ДэвидВассер, да. Но в случае с Сервисом для управления вызовами API он должен создать рабочий поток в сервисе. Отправка намерений для обработки в отдельном потоке через startService не совсем понятна мне и другим программистам, которые могли бы поддерживать приложение в будущем. В случае с IntentService после первого handleIntent сервис должен быть остановлен. Итак, я думаю, что если сервис должен выполнять длительные задачи и может принимать данные во время работы, он должен использовать привязку и передавать данные через мессенджер или какие-то пользовательские методы службы, но это тоже требует привязки. - person Alexander Goncharenko; 02.05.2017
comment
Очевидно, что IntentService не является правильным решением. Здесь вам нужен обычный Service, который вы можете запускать и останавливать самостоятельно. Нет абсолютно никаких причин, по которым вы не можете или не должны использовать startService() для передачи Intent работающему Service. Service в любом случае должен запустить фоновый поток для выполнения обработки, поэтому вы можете управлять Service, отправив ему новый Intent в любое время. - person David Wasser; 02.05.2017
comment
@Александр Гончаренко, я хочу запустить сервис в режиме START_STICKY. с этим решением я думаю, что метод onStartCommand не вызывается. как я могу использовать режим STICKY с вашим решением? - person hkh114; 02.12.2019

Лучшим вариантом было бы сохранить данные на жестком диске (например, SharedPreferences, базу данных,...).

Активность обновлена ​​=> сохраняется в хранилище => вызывает службу

Сервис должен прочитать данные из выбранного хранилища перед отправкой данных.

person dipdipdip    schedule 02.05.2017

Вместо этого используйте многопоточность, это становится намного проще, и вы получите ту же функциональность.

 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;
person Sumit Shetty    schedule 02.05.2017

1.Отправка данных в сервис Upto Lolipop edition

Intent serviceIntent= new Intent(DriverActivity.this,demoService.class);
serviceIntent.putExtra("token", token);
startService(serviceIntent);
  1. Получение данных в классе обслуживания:

     @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";
    }
    
person Rajasekhar    schedule 02.05.2017
comment
В своем вопросе я задал вопрос, что хочу отправить данные в работающую службу, используя намерение, которое я не могу отправить только один раз. - person Tushar Kotecha; 02.05.2017
comment
@TusharKotecha неправда. Вы можете отправить данные работающему Service, вызвав startService() с Intent. В Service, onStartCommand() будет вызываться ваша работающая служба. - person David Wasser; 02.05.2017
comment
Это, безусловно, самый простой способ, хотя существует множество других. - person David Wasser; 02.05.2017
comment
@Rajasekhar, если я использую startService() каждый раз, когда хочу отправить данные, чтобы создать новый поток или новую службу? или это сделает нагрузку на устройство? в основном вы хотите сказать, что startService() и передача данных через намерение будут передавать данные работающей службе? - person Tushar Kotecha; 03.05.2017