13

I want to send data to the server periodically, I'm using background Service for that, but I want to send when the data got updated, and updated data I'm getting in Activity and the Service is running in background.. so how can i pass data to running Service from Activity. Using Intent I can send data only one time while starting the Service.

Intent serviceIntent= new Intent(DriverActivity.this,demoService.class);
serviceIntent.putExtra("token", token);
startService(serviceIntent);
Tushar Kotecha
  • 764
  • 2
  • 7
  • 27
  • My opinion is to use Event Bus or broadcast receiver – Piyush May 02 '17 at 11:32
  • Hi You can use broadcast receiver to send data to running service or http://stackoverflow.com/questions/15346647/android-passing-variables-to-an-already-running-service – Vasudev Vyas May 02 '17 at 11:33
  • 5
    You can send data as many times as you want to a running service with `startService()`. This doesn't start the `Service` if it is already started, but will call `onStartCommand()` with the data in the `Intent`. – David Wasser May 02 '17 at 12:55
  • 1
    Possible duplicate of [Android: Passing variables to an already running service](https://stackoverflow.com/questions/15346647/android-passing-variables-to-an-already-running-service) – SafalFrom2050 May 30 '18 at 16:22

4 Answers4

9

Read this article https://developer.android.com/guide/components/bound-services.html

For example you can use 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();
    }
}

And in your Activity or Fragment you can send data in this way:

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;
        }
    }
}

If you don't know how to pass data with Message look at this answer https://stackoverflow.com/a/17929775

Community
  • 1
  • 1
  • This requires binding to the `Service` and is somewhat more complicated and heavier than just calling `startService()` again to send more data. Otherwise this is a perfectly OK solution. – David Wasser May 02 '17 at 12:56
  • 1
    @DavidWasser, yes. But in case with Service, to manage api calls he should create worker thread in service. Sending intents, to be processed in the separate thread through startService, is not clearly for me and other programmers that could support an application in the future. In case with IntentService after first handleIntent service should be stopped. So, I think, if service should perform long running tasks and could accept data while it is running he should use binding and pass data through messenger or some custom service methods, but this is require binding too. – Alexander Goncharenko May 02 '17 at 14:14
  • Obviously `IntentService` is not the correct solution. Here you need a regular `Service` that you can start and stop by yourself. There is absolutely no reason why you cannot or should not use `startService()` to pass an `Intent` to a running `Service`. The `Service` should start a background thread to do processing anyway, so you can control the `Service` by sending it a new `Intent` at any time. – David Wasser May 02 '17 at 15:19
0

The best option would be to persist the data on the hard drive (e.g. SharedPreferences, database, ...).

Activity got updated => persist to storage => invoke Service

The Service has to read the data from the chosen storage before sending the data.

dipdipdip
  • 2,326
  • 1
  • 21
  • 31
0

Use multithreading instead it becomes much easier and you will get the same functionality.

 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;
Sumit Shetty
  • 112
  • 1
  • 9
0

1.Sending data to service Upto Lolipop edition

Intent serviceIntent= new Intent(DriverActivity.this,demoService.class);
serviceIntent.putExtra("token", token);
startService(serviceIntent);
  1. Retrieving data in Service class :

     @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";
    }
    
Rajasekhar
  • 2,345
  • 1
  • 13
  • 20
  • 2
    i have asked in my question that i want to send data to running service, by using intent i cant send only one time. – Tushar Kotecha May 02 '17 at 11:38
  • 1
    @TusharKotecha not true. You can send data to a running `Service` by calling `startService()` with an `Intent`. In the `Service`, `onStartCommand()` will be called on your running service. – David Wasser May 02 '17 at 12:52
  • @Rajasekhar if i use startService() every time when i want to send data, so it would create a new thread or a new service? or it will make a load on device? basically you want to say that startService() and passing data through intent will pass data to running service? – Tushar Kotecha May 03 '17 at 05:11