Липкий Сервис Менеджмент - PullRequest
       10

Липкий Сервис Менеджмент

0 голосов
/ 16 сентября 2011

У меня есть Sticky Service (возвращает START_STICKY из onStartCommand), который выполняет некоторый код в AsyncTask, но у меня возникают некоторые проблемы с тем, как и когда запускать, связывать, останавливать, отменять привязку. Мне нужен только сервис, пока родительская активность активна, я не хочу, чтобы он зависал в фоновом режиме, когда приложение закрыто, но мне нужен сервис, чтобы пережить изменение ориентации. В настоящее время мне не нужно, чтобы служба была активной в течение всего периода активности, поэтому я вызываю stopSelf () после выполнения основной работы в моем AsyncTask в Service, а затем запускаю Service снова, когда это необходимо. Иногда мне нужно прервать работу службы, отменить AsyncTask и начать заново с другими данными. Проблема в том, что независимо от того, что я делаю, я не могу понять это во всех возможных сценариях. Может кто-нибудь посмотреть и сказать, что я делаю не так?

Мой Service:

public class ChordCalculatorService extends Service {

    private final IBinder mBinder = new LocalBinder();
    private AsyncTask<SearchData, SearchStatusData, List<Item>> currentTask;

    @Override
    public void onCreate() {}

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }

    /**
     * Class for clients to access. Because we know this service always runs in
     * the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        public ChordCalculatorService getService() {
            return ChordCalculatorService.this;
        }
    }

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

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

    public SearchData getSearchData() {
        return searchData;
    }        

    public void startWork() {
        if (currentTask != null && currentTask.getStatus() == Status.RUNNING) {
            currentTask.cancel(true);
        }
        if(searchData != null) {
            Worker task = new Worker();
            currentTask = task.execute(new SearchData[] { searchData });
        } else {
            Message msg = handler.obtainMessage(ERROR, "No search data set");
            handler.sendMessage(msg);
        }
    }


    class Worker extends AsyncTask<SearchData, SearchStatusData, List<Item>> {
        // ... code ...

        @Override
        protected void onPostExecute(List<Item> result) {
            Message msg = handler.obtainMessage(COMPLETE, new StatusData(Status.STATUS_FINISHED, result));
            handler.sendMessage(msg);
            stopSelf();
        }
    }
}

В настоящее время у меня запускается Service при создании моего пользовательского View:

public class MyCustomView extends BasicFretBoardView  {

    private ServiceConnection conn;
    private MyService myService;
    private boolean isServiceStarted;
    private boolean isServiceBound;

    public MyCustomView(Context context, AttributeSet attr) {
        super(context, attr);
        startService();
    }

    public void startService() {
        Intent serviceIntent = new Intent(getContext(), MyService.class);
        conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                myService = ((LocalBinder) service).getService();
                myService.registerHandler(serviceHandler);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                myService = null;
            }
        };

        // Explicitly start the service. Don't use BIND_AUTO_CREATE, since it
        // causes an implicit service stop when the last binder is removed.

        getContext().startService(serviceIntent);
        getContext().bindService(serviceIntent, conn, 0);
        isServiceStarted = true;
        isServiceBound = true;
    }

    public void stopService() {
        if (isServiceStarted) {
            Intent serviceIntent = new Intent(getContext(), MyService.class);
            getContext().stopService(serviceIntent);
            isServiceStarted = false;
        }
        unBindService();
    }


    public void unBindService() {
        if(isServiceBound) {
            getContext().unbindService(conn);
            isServiceBound = false;
        }
    }

    // gets called based on some user interaction
    private void startServiceWork() {
        if(!isServiceStarted) {
            startService();
        } else {
            myService.cancelCalcalation();
        }
        myService.setData(data);
        myService.startWork();
    } 
}

и остановка службы обрабатывается в Activity:

public class CustomChordActivity extends Activity {

    // ... code ...

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

    @Override
    protected void onPause() {
        if(isFinishing()) {
            chordsView.stopService();
        }
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        chordsView.unBindService();
        super.onDestroy();
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    }
}

1 Ответ

0 голосов
/ 16 сентября 2011

Кажется, что вы хотите, чтобы ваша задача выполнялась по требованию, возможно, IntentService был бы более подходящим вариантом.Когда вам нужно выполнить работу (startServiceWork ()), вы просто запускаете службу, и это запускает AsyncTask.Служба будет завершена после завершения задачи.

Теперь, что касается изменений ориентации, вам нужно будет реализовать широковещательный приемник с фильтром намерений "android.intent.action.CONFIGURATION_CHANGED".(Я предполагаю, что вы хотите, чтобы служба работала, когда меняется ориентация). Поместите Broadcast Receiver в ваш поток действий / основного пользовательского интерфейса.Это фактически сделает процесс размещения вашего Broadcast Receiver основным процессом приложения, что сделает более безопасным запуск службы из Broadcast Receiver.

...