在后台工作时更新用户界面

6

我有一个更新数据库操作,其中有一个活动会不断更新百分比,并在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)并传递当前百分比值,因此它会在UI中publishProgress(value)
我正在调试,然后按下Home/Back按钮,它就停止运行工作线程。
我尝试的另一个解决方案是启动一个服务在后台运行,无论用户是否按下Home/Back按钮,所以我想,服务会调用控制器执行工作的方法,并且它将调用callPublishProgress(value) 无论如何都会在UI上更新百分比值。
然而,事实上发生的情况是,代码到达doInBackground() 并启动服务,但它立即转到onPostExecute() ,它根本没有等待服务完成(当然!)。 因此它会出现NullPointerException。 我考虑在doInBackground()内部使用循环,并在Service中设置标志,因此当Service未完成时,它将离开此循环(我正在使用IntentService),但它仍然无效。
我也想过使用定时器。 但我不知道该怎么做。
我正在阅读有关线程等的文档文章。 它建议像我一样使用AsyncTask。 它还讨论了runOnUiThread(Runnable)无论如何,我需要在后台执行操作(可能使用IntentService),因此无论用户是否按Home键,它都将继续运行,但它必须在UI上更新百分比,当用户离开屏幕并回到它时,它会显示当前百分比值在屏幕上更新。 对于我的情况,最佳解决方案是什么?
谢谢。

请在SDK示例中查看API演示,其中有一个服务的示例,可以计数并通知前台活动,该活动可以显示计数。 - Chris Stratton
这个示例的名称是什么? - rogcg
我记不清了,所有的内容都在sdk的samples/目录下的API演示应用程序中 - 构建整个应用并运行它,浏览菜单并浏览代码。还有很多其他有用的东西值得知道。 - Chris Stratton
3个回答

5
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));

运行得非常好,但我不需要使用Handler。我只是启动了IntentService,并从IntentService中调用了sendBroadcast(Intent)。非常感谢! - rogcg

1
这对我很有用。我在一个线程上启动了一个后台服务,它只是获取值并更新单例中的对象。
在视图控制器中,我启动了一个定时器,通过从单例中的对象获取数据来不断更新视图。
我有一点问题理解你整个问题文本,所以我不确定你是否尝试过这个。但这就是有效的方法。此外,服务是使用START_STICKY启动的。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接