Lesson 98. Service. Local Binding

Lesson 98. Service. Local Binding


In this lesson:

– data exchange in Binding

We are now able to connect to the service. In this lesson, let’s try to communicate with him.

In service, the onBind method returns an object that inherits the IBinder interface. The easiest way to do this is to use the Binder object and extend it with the methods we need. That is, we create our class MyBinder with the ancestor Binder and draw in it our methods.

With Binding, in the onServiceConnected method we get a Binder object. We can bring it to the MyBinder type (from service) and call its methods, and the implementation will work in the service where we described this class.

As you understand, this will only work if the service and application are running in the same process. That is why this kind of Binding is called local.

Let’s draw an example. We will have a service that will output something to the log at a certain interval. We will connect to it, and we will increase or decrease the interval and get a new interval value back.

Let’s create a project:

Project name: P0981_ServiceBindingLocal
Build Target: Android 2.3.3
Application name: ServiceBindingLocal
Package name: en.startandroid.develop.p0981servicebindinglocal
Create Activity: MainActivity

Add to strings.xml rows:

Start
Up
Down

screen main.xml:



	
	
	
	
	

Buttons to start the service, increase the interval and reduce the interval.

we create a service MyService.java:

package ru.startandroid.develop.p0981servicebindinglocal;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

  final String LOG_TAG = "myLogs";

  MyBinder binder = new MyBinder();

  Timer timer;
  TimerTask tTask;
  long interval = 1000;

  public void onCreate() {
    super.onCreate();
    Log.d(LOG_TAG, "MyService onCreate");
    timer = new Timer();
    schedule();
  }

  void schedule() {
    if (tTask != null) tTask.cancel();
    if (interval > 0) {
      tTask = new TimerTask() {
        public void run() {
          Log.d(LOG_TAG, "run");
        }
      };
      timer.schedule(tTask, 1000, interval);
    }
  }

  long upInterval(long gap) {
    interval = interval + gap;
    schedule();
    return interval;
  }

  long downInterval(long gap) {
    interval = interval - gap;
    if (interval < 0) interval = 0;
    schedule();
    return interval;
  }

  public IBinder onBind(Intent arg0) {
    Log.d(LOG_TAG, "MyService onBind");
    return binder;
  }

  class MyBinder extends Binder {
    MyService getService() {
      return MyService.this;
    }
  }
}

This is where we use the timer. It allows you to repeat any action after a specified period of time. I will briefly describe the principle of action. TimerTask is a task that Timer will perform periodically. In the run method, this task's action code. And then for the Timer object we call the schedule method, in which we pass the task to TimerTask, the time after which the execution will start, the delay period. To cancel a job, you must call the cancel method for TimerTask. The canceled task can no longer be scheduled, and if you need to switch it on again, you must create a new TimerTask instance and feed it with a timer.

So in the method onCreate we create a timer and run the schedule method in which the task starts.

method schedule checks that the task is already created and cancels it. Next he plans a new one, with a delay of 1000 ms start and period = interval. That is to say, this method restarts the task using the current recurrence interval (interval), and if the task is not already created, then creates it. The task itself simply outputs the run text. If interval = 0, then we do nothing.

method upInterval receives an input, increases the interval to that value, and restarts the job. Accordingly, the task will then be repeated less frequently.

method downInterval receives an input, reduces the interval to that value (but not less than 0), and restarts the job. Accordingly, the task will then be repeated more often.

onBind returns binder. This is a MyBinder class object.

MyBinder extends standard Binder, we add one getService method to it. This method returns our MyService.

That is, in the Activity connection, in the onServiceConnected method we get an object that goes to the onBind method output. Next, turn it into a MyBinder type, call getService and voila - we in Activity will have a link to the MyService object service.

Kodyma MainActivity.java:

package ru.startandroid.develop.p0981servicebindinglocal;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {

  final String LOG_TAG = "myLogs";

  boolean bound = false;
  ServiceConnection sConn;
  Intent intent;
  MyService myService;
  TextView tvInterval;
  long interval;
  

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    tvInterval = (TextView) findViewById(R.id.tvInterval);
    intent = new Intent(this, MyService.class);
    sConn = new ServiceConnection() {

      public void onServiceConnected(ComponentName name, IBinder binder) {
        Log.d(LOG_TAG, "MainActivity onServiceConnected");
        myService = ((MyService.MyBinder) binder).getService(); 
        bound = true;
      }

      public void onServiceDisconnected(ComponentName name) {
        Log.d(LOG_TAG, "MainActivity onServiceDisconnected");
        bound = false;
      }
    }; 
  }
  
  @Override
  protected void onStart() {
    super.onStart();
    bindService(intent, sConn, 0);
  }
  
  @Override
  protected void onStop() {
    super.onStop();
    if (!bound) return;
    unbindService(sConn);
    bound = false;
  }

  public void onClickStart(View v) {
    startService(intent);
  }
  
  public void onClickUp(View v) {
    if (!bound) return;
    interval = myService.upInterval(500);
    tvInterval.setText("interval = " + interval);
  }
  
  public void onClickDown(View v) {
    if (!bound) return;
    interval = myService.downInterval(500);
    tvInterval.setText("interval = " + interval);
  }
}

IN onCreate we create Intent to access the service and ServiceConnection. In the onServiceConnected method, we take binder, convert it to MyService.MyBinder, call the getService method, and get our MyService. We can now perform service methods. We are interested in methods of increasing and decreasing the interval.

In methods onStart and onStop we accordingly connect to the service and disconnect.

IN onClickStart run the service.

IN onClickUp and onClickDown we check that there is a connection to the service and call the appropriate service methods to increase or decrease the interval. As deltas change intervals we pass 500. In response, these methods give us a new value of the interval, and we display it in TextView.

We will save everything and run it.

press Start - start the service. In the logs:

MyService onCreate
MyService onBind
MainActivity onServiceConnected

A service is being created and we are connecting to it. Binding was previously called on onStart and when the service started, we automatically connected. In the last lesson, we have sorted out the situation when Binding goes to work that has not been started yet.

run
run
run
...
run

Then, at intervals of one second, the text run appears in the log.

Let's try to increase the interval. press Cf..

The current interval value appears on the screen. And by the time of log entries we see that it is at this interval that the task (output of the text run to the log) works.

Next you can click Cf. and Down and watch how the task interval changes. So Activity and I got connected to the service and managed it.

At the beginning of the lesson, I noted that all this would work if the application and service are in the same process. If they are in different processes, then a slightly more complicated variant for data exchange is used. But this is a much less used case, so now I'm not talking about it. But later on this is bound to be an article.

In the next lesson:

- helmet message from the service




Discuss in the forum [78 replies]

Leave a Comment