Обновление пользовательского интерфейса во время работы в фоновом режиме

у меня есть операция обновления базы данных, которая имеет действие, которое продолжает обновлять процент и работает внутри AsyncTask.

внутри doInBackground () я вызываю контроллер, который обновляет базу данных и продолжает обновлять процент активности, однако, если я нажму кнопку "Домой" или кнопку "назад", операция будет отменена. Что ты предлагаешь мне сделать?

я пытался запустить службу внутри doInBackground (), чтобы она работала в фоновом режиме, но она похоже, не работает.

мой код выглядит так:

public class UpdateDatabaseAsyncTask extends AsyncTask<Void, Integer, Integer>
{   
    @Override
    public void onPreExecute()
    {
        mCustomProgressBar.startAnimation();
    }

    @Override
    public Integer doInBackground(Void... params)
    {
        return mController.updateDatabase();
    }

    @Override
    public void onPostExecute(Integer result)
    {
        mCustomProgressBar.stopAnimation();
        // finish the activity
    }

    @Override
    public void onProgressUpdate(Integer... value)
    {
        updatePercentageValue(value[0]);
    }

    public void callPublishProgress(Integer value)
    {
        publishProgress(value);
    }
}

и внутри контроллера я вызываю метод callPublishProgress(value) передача текущего процентного значения, поэтому он будет publishProgress(value) в пользовательском интерфейсе.

я отлаживал, и я нажал кнопку home / back, и он просто перестал запускать рабочий поток.


другое решение, которое я пробовал, запускал службу для запуска в фоновом режиме независимо от того, нажимает ли пользователь кнопку home / back или нет, поэтому я думал, и Служба сделает вызов методу контроллера, который выполняет работу, и он вызовет callPublishProgress(value) чтобы обновить процентное значение в пользовательском интерфейсе в любом случае.

однако, что происходит, код reach doInBackground() и запустите службу, но она переходит в onPostExecute() сразу же, он просто не дождался окончания службы(конечно!). Так что это дает NullPointerException. Я думал сделать петлю внутри doInBackground() С флагом, установленным в Службе, поэтому он уйдет этот цикл, пока служба не была завершена (я использовал IntentService), но он все равно не работал.

я тоже подумал об использовании таймера. Но я не знаю.

Я читал статьи, в документации о потоках и т. д. И он предлагает использовать AsyncTask, как я и пытался сделать. Он также говорит о runOnUiThread(Runnable).

в любом случае мне нужно сделать операцию в фоновом режиме(возможно, используя IntentService), поэтому независимо от того, является ли пользователь нажмите кнопку "Домой", он будет продолжать работать, но он должен обновить процент в пользовательском интерфейсе, и когда пользователь покинет экран и вернется к нему, он покажет текущее процентное значение, обновленное на экране.

что является лучшим решением для моего случая?

спасибо.

3 ответов


public class MyServce extends Service{
public static final String BROADCAST_ACTION = "com.myapp";
Intent intent;
private final Handler handler = new Handler();

@Override
public void onCreate()
{
    super.onCreate();
    intent = new Intent(BROADCAST_ACTION);
}

 @Override
    public void onStart(Intent intent, int startId) {
        handler.removeCallbacks(sendUpdatesToUI);
        handler.postDelayed(sendUpdatesToUI, 1000); // 1 second

    }
   private Runnable sendUpdatesToUI = new Runnable() {
        public void run() {
            DoYourWorking();        
            handler.postDelayed(this, 1000); // 1 seconds
        }

        private void DoYourWorking() {
        ........
                    ........
                     intent.putExtra("key", progress);
             sendBroadcast(intent);

        }
    };   

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}
@Override
public void onDestroy() {   
    super.onDestroy();
    handler.removeCallbacks(sendUpdatesToUI);       

}

Теперь в вашей деятельности регистрация вещания на службу

private BroadcastReceiver brodcast = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
                 //intent.getWhatever
        // update your progress
        //progressbar.setProgress 
    }

зарегистрировать широковещательный

 registerReceiver(brodcast, new IntentFilter(MyService.BROADCAST_ACTION));

это сработало для меня. Я запустил фоновую службу в потоке, который просто извлекает значения и обновляет объект в одиночном элементе.

в контроллере представления я запускаю таймер, который продолжает обновлять представление, извлекая данные из объекта в singleton.

У меня была небольшая проблема с пониманием всего текста вашего вопроса, поэтому я не уверен, что вы пробовали это. Но это сработало. Кроме того, служба была запущена с START_STICKY


использовать IntentService (который является сервисом в собственном потоке) и проводник для передачи данных обратно в действие.