Android startService()需要很长时间才能返回UI线程

时间:2011-12-06 17:34:45

标签: android service time synchronized

我的用例在第一次启动时(大致)是以下内容:

  1. 活动启动服务
  2. 服务获取并保存数据库中的数据
  3. 服务以意图通知活动
  4. 活动显示数据
  5. 现在我想在服务繁忙时显示进度条。问题是:

    startService(new Intent(getApplicationContext(), UpdateDataService.class));

    需要很长时间才能“返回”UI线程。它似乎是一个同步函数(或not?)。如果清空服务类,则几乎立即处理startService命令。似乎UI线程等待Serice处理它的工作,这根本没有意义。我尝试启动(尽管看起来很愚蠢)在我的UI线程中显示进度条时启动服务异步任务。奇怪的是,这有时会起作用。 Othertimes我只是在我的服务正在工作时获得一个白色屏幕,之后是一毫秒ma进度条然后我的UI。

    现在我的问题是:如何在不阻止我的UI的情况下启动服务?

    public class MyClass extends TabActivity {
    private ProgressDialog pd;
    
    @Override
    public void onCreate(final Bundle savedInstanceState) {
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        Intent intent = null;
    
        //building some tabs here, setting some text views....
    
        // starting service if does not exist yet
        boolean serviceRunning = false;
    
        final ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        for (final RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if ("aegir.mobile.UpdateDataService".equals(service.service.getClassName())) {
                serviceRunning = true;
                Log.i(MY_APP_TAG, "Service found.");
            }
        }
        if (!serviceRunning) {
            pd = ProgressDialog.show(this, "Loading...", "Setting up data.", true, false);
            new StartServiceAsync().execute("");
        }
    
    }
    
    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(final Message msg) {
            pd.dismiss();
    
        }
    };
    
    public class StartServiceAsync extends AsyncTask<String, Void, String> {
    
        @Override
        protected String doInBackground(final String... params) {
            // starting service
            startService(new Intent(getApplicationContext(), UpdateDataService.class));
            return null;
        }
    
        @Override
        protected void onPostExecute(final String result) {
            handler.sendEmptyMessage(0);
            super.onPostExecute(result);
        }
    }
    

4 个答案:

答案 0 :(得分:9)

从指南主题Services

  

警告:默认情况下,服务在与声明它的应用程序相同的进程中运行,并在该应用程序的主线程中运行。因此,如果您的服务在用户与同一应用程序中的活动进行交互时执行密集或阻止操作,则该服务将降低活动性能。为避免影响应用程序性能,您应该在服务中启动一个新线程。

这不会因为您从AsyncTask调用startService而改变。

答案 1 :(得分:1)

我认为您应该在异步任务中将逻辑从服务移动到doInBackground方法。这就是异步任务的用途,执行艰苦的工作,为您提供与UI交互的简单方法。在异步任务中调用服务很奇怪,你有没有理由这样做?

答案 2 :(得分:1)

要么在AsyncTask本身工作,要使用IntentService而不是普通的Service,要么从Service开始执行您的工作。 Android中的Service本身并不使用其他线程(IntentService可以执行其工作)。

尽管Service开始你的AsyncTask,但现在看来你的UI线程中正在执行实际的工作。

答案 3 :(得分:0)

请使用此代码轻松地执行您提出的问题。

@Override
public void onCreate(final Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Intent intent = null;
    registerReceiver(dataUpdated, new IntentFilter("<FLAG>"));
    //building some tabs here, setting some text views....

    // starting service if does not exist yet
    boolean serviceRunning = false;

    final ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    for (final RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if ("aegir.mobile.UpdateDataService".equals(service.service.getClassName())) {
            serviceRunning = true;
            Log.i(MY_APP_TAG, "Service found.");
        }
    }
    if (!serviceRunning) {
        pd = ProgressDialog.show(this, "Loading...", "Setting up data.", true, false);
        startService(new Intent(getApplicationContext(), UpdateDataService.class));
    }

}


private BroadcastReceiver dataUpdated= new BroadcastReceiver() {
    @SuppressLint("ShowToast")
    @Override
    public void onReceive(Context context, Intent intent) {
        //<Your Process which you want when Service finishes a task >
              pd.dismiss();
    }
};

@Override
protected void onDestroy() {

    unregisterReceiver(dataUpdated);
}

当您的任务完成时在服务中调用此方法

sendBroadcast(new Intent("<FLAG>"));