Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent bound Service from being destroyed while Activity's runtime changes (ex: orientation)

I have a bound Service. An activity is binding it. It unbinds the Service on Activity's onStop() method.

The problem is, if runtime changes (for example, orientation change) happen to the Activity, then the Activity is recreated. So, onStop() method is called from the Activity, and the Activity unbinds the Service in that method, which results in destruction of the Service (and restarting of it).

I want to preserve the Service from being destroyed in the runtime changes while keeping Service stopping when the Activity is invisible. You could say that try startService() but it makes the Service not to stop when Activity is invisible. If I add stopService Activity's onStop(), then the result is the same as bindService() and unbindService().

PostDelaying unbindService() in Acitivity's onStop() can solve this problem partly, but the delaying time will be arbitrary, and this prevents the Activity from getting GC for some time. I want a more clear solution.

I don't want solutions like android:configChanges="orientation" since there are other runtime changes as well, and it is a discouraged way of processing runtime changes.

In short, I want the Service to act like a Fragment that called setRetainInstance(true). However, Fragments don't have something like bindService(). What should I do?

like image 929
Naetmul Avatar asked May 22 '13 23:05

Naetmul


People also ask

How do you stop a bound service?

Binding to a started service If you do allow your service to be started and bound, then when the service has been started, the system does not destroy the service when all clients unbind. Instead, you must explicitly stop the service by calling stopSelf() or stopService() .

Which of the following method is called when all components bound to the service have been unbound?

A service is termed as bounded when an application component binds itself with a service by calling bindService() method. To stop the execution of this service, all the components must unbind themselves from the service by using unbindService() method.

What is bound and unbound service in Android?

Bounded services are bounded to an activity which binds it and will work only till bounded activity is alive. while a unbounded service will work till the completion even after activity is destroyed.

What are the components you can bind to a service?

Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service can handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.


2 Answers

However, Fragments don't have something like bindService().

But they can use bindService() from the Application context:

public class BshFragment extends Fragment implements OnClickListener,
    ServiceConnection {
  private IScript service=null;
  private Button btn=null;

  public View onCreateView(LayoutInflater inflater,
                           ViewGroup container,
                           Bundle savedInstanceState) {
    View result=inflater.inflate(R.layout.main, container, false);

    btn=(Button)result.findViewById(R.id.eval);
    btn.setOnClickListener(this);
    btn.setEnabled(false);

    setRetainInstance(true);

    return(result);
  }

  @Override
  public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    getActivity().getApplicationContext()
                 .bindService(new Intent(getActivity(),
                                         BshService.class), this,
                              Context.BIND_AUTO_CREATE);
  }

  @Override
  public void onDestroy() {
    getActivity().getApplicationContext().unbindService(this);
    disconnect();

    super.onDestroy();
  }

  @Override
  public void onClick(View view) {
    EditText script=(EditText)getView().findViewById(R.id.script);
    String src=script.getText().toString();

    service.executeScript(src);
  }

  @Override
  public void onServiceConnected(ComponentName className, IBinder binder) {
    service=(IScript)binder;
    btn.setEnabled(true);
  }

  @Override
  public void onServiceDisconnected(ComponentName className) {
    disconnect();
  }

  private void disconnect() {
    service=null;
    btn.setEnabled(false);
  }
}

(as seen in this sample project, covered in this book)

By using the Application context, we are able to use the same Context for binding and unbinding. By retaining the fragment, we can avoid unbinding and rebinding on a configuration change.

Personally, I just try to avoid the binding pattern. I am a fan of loosely-coupled interfaces, and so I prefer using services via the command pattern and startService().

like image 50
CommonsWare Avatar answered Oct 28 '22 17:10

CommonsWare


Call startService in onCreate and then onStop

@Override
protected void onStop()
{
    super.onStop();
    if (!isChangingConfigurations ())
    {
          // call stopService
    }
}
like image 24
Hoan Nguyen Avatar answered Oct 28 '22 18:10

Hoan Nguyen