Служба Android: надлежащая практика взаимодействия со службой

#android #android-activity #service

#Android #android-активность #Обслуживание

Вопрос:

В моем приложении для Android я использую ‘LocationService’ в классе ‘Service’. Несколько руководств рекомендуют эту практику, чтобы иметь постоянную проверку местоположения во всех действиях. Однако, несмотря на наличие хорошей документации, у меня все еще есть вопрос, касающийся связи между activity и моим сервисом.

Это мой класс LocationService:

 public class LocationService extends Service {

    public static  LocationManager locationManager;
    public static  LocationListener listener;
    private static Location currentLocation = null;

    @Override
    public void onCreate() {
        super.onCreate();
    }

     @Override
     public void onStart(Intent intent, int startId) {

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        listener = new LocationListener() {

           @Override
           public void onLocationChanged(Location location) {
               currentLocation = location;
               System.out.println("Current Location: "   currentLocation);
           }

           @Override
           public void onStatusChanged(String s, int i, Bundle bundle) {
           }

           @Override
           public void onProviderEnabled(String s) {
           }

           @Override
           public void onProviderDisabled(String s) {
           }
       };
   }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        locationManager.removeUpdates(listener);
    }

    public static Location getCurrentLocation() {
        return currentLocation;
    }
  

Это часть моего глобального класса:

 ...
@Override
public void onCreate() {
    super.onCreate();

    if(!LocationService.isRunning()) {
        Intent intent = new Intent(this, LocationService.class);
        startService(intent);
    }
}
...
  

И это мой класс Activity:

 public class ScreenActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.screen);
    }

    if (usesPosition) {
        Location tLoc = LocationService.getCurrentLocation();
        TextView t = (TextView) findViewById(R.id.tv);
        t.setText(tLoc.toString());
    }
}
  

Я чувствую, что это не элегантный способ, возможно, даже неправильный. Я получаю хорошее местоположение, но мне кажется, что я не получаю доступа к службе, но
скорее относитесь к нему как к статическому классу. Я еще не знаком с концепцией привязки сервисов к activities, поэтому мне интересно, действительно ли мне нужно
чтобы сделать это.

РЕДАКТИРОВАТЬ 1

Спасибо за первые ответы! Это уже немного помогло мне. Теперь это часть моего класса Activity:

 private ServiceConnection locationServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceDisconnected(ComponentName name) {
        locationServiceBound = false;
        System.out.println("Service disconnected");
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        com.ma.sainz.geoobserver.Tools.Services.LocationService.MyBinder myBinder = (com.ma.sainz.geoobserver.Tools.Services.LocationService.MyBinder) service;
        locationService = myBinder.getService();
        locationServiceBound = true;
        System.out.println("Service bound");
    }
};
  

где myBinder — класс, определенный в LocationService .
И это мой новый OnStart () — метод моей деятельности:

 @Override
protected void onStart() {
    super.onStart();

    Intent locationServiceIntent = new Intent(this, com.ma.sainz.geoobserver.Tools.Services.LocationService.class);
    bindService(locationServiceIntent, locationServiceConnection, Context.BIND_AUTO_CREATE);
    locationService.requestBackgroundLocation();
    System.out.println("onStart");
}
  

startService(locationServiceIntent) выполнено в предыдущем действии.

Однако LocationService некоторое время равен нулю. Таким образом, подключение к службе занимает некоторое время. Как я узнаю, когда служба подключена?

И если предположить, что я хотел бы реализовать LocalBroadcast , будет ли это дополнением к реализации сервиса? У вас есть подсказка о том, как с этого начать? Потому что, если я отправлю LocationUpdates, как только они появятся, я бы не стал беспокоиться о том, чтобы ждать подключения службы.

Комментарии:

1. Я бы не хотел отвечать здесь о связанных службах, потому что вопрос по SO должен касаться одной темы. В общем, вы не должны использовать службу, пока не был вызван onServiceConnected() обратный вызов. В вашем случае вы могли бы locationService.requestBackgroundLocation(); ввести onServiceConnected() и посмотреть, что произойдет.

2. Ну ладно. Я не видел такой зависимости с функцией onServiceConnected (). Да, тогда это звучит неплохо. Тогда я позабочусь о трансляциях в другой раз. На данный момент все работает так, как я хочу. Спасибо!

Ответ №1:

То, что у вас есть, на самом деле не очень хороший дизайн. Подумайте вот о чем: обычно вы хотели бы не просто получить местоположение, но и постоянно обновлять его. Это означает, что ваша активность должна быть уведомлена о появлении таких обновлений.

Здесь у вас есть несколько вариантов:

  1. Привяжите службу и выполните обычные вызовы методов для нее (получите местоположение, зарегистрируйте / отмените регистрацию слушателей)
  2. Используется LocalBroadcastManager для трансляции обновлений местоположения из службы в Activities
  3. Используйте какую-нибудь шину событий (мою любимую — EventBus от GreenRobot), чтобы транслировать обновления местоположения из сервиса в мероприятия

Я лично использую последний подход: служба отправляет «липкие» события в Event Bus при обновлении местоположения, и действия запрашивают эти события в onResume() , а также подписываются на обновления. Таким образом, вашему Service не нужно будет постоянно работать — запустите его, когда вам нужно местоположение, получите местоположение с желаемой точностью и остановите службу, чтобы не расходовать заряд батареи.

Комментарии:

1. Спасибо, это было начало. Я привязал службу, но теперь моя служба равна нулю, пока она не подключена. Я отредактировал свой вопрос и был бы благодарен за еще несколько советов 🙂

Ответ №2:

Да, не делайте этого — это не только неэлегантно, но и приведет к утечке памяти. Служба Android может быть привязана к любому другому компоненту, см.:https://developer.android.com/guide/components/bound-services.html . Ваша активность или другая служба будут привязаны к вашей службе определения местоположения и использовать интерфейс, предоставляемый этой службой. Обратите внимание, служба будет запущена, когда останется хотя бы одно соединение. Запустите и привяжитесь к службе, а затем она будет выполняться до тех пор, пока вы ее не остановите, и вы сможете использовать явный интерфейс из этой службы с помощью Binder. Еще одна хорошая технология — использование EventBus (greenRobot) для передачи фиксированных событий между Activity и сервисом. Событие будет ждать, пока другой компонент не будет инициализирован и получит это событие. Вы можете подписаться на это событие и отказаться от подписки с помощью методов onPause и onResume.