【问题标题】:Android startService() takes a long time to return to UI threadAndroid startService() 需要很长时间才能返回UI线程
【发布时间】:2012-01-14 07:23:12
【问题描述】:

我的用例在第一次启动时(大致)如下:

  1. activity 启动服务
  2. 服务获取数据并将其保存在数据库中
  3. 服务根据意图通知活动
  4. 活动显示数据

现在我想在服务繁忙时显示进度条。问题是:

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

需要很长时间才能“返回”到 UI 线程。它似乎是一个同步函数(或not?)。如果服务类为空,则几乎立即处理 startService 命令。似乎 UI 线程等待 Serice 处理其工作,这根本没有意义。我试图开始(尽管看起来很愚蠢)以异步任务启动服务,同时在我的 UI 线程中显示进度条。很奇怪,这有时会起作用。有时我只是在我的服务工作时得到一个白屏,然后是一个毫秒的进度条,然后是我的 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);
    }
}

【问题讨论】:

    标签: android service time synchronized


    【解决方案1】:

    请使用此代码以简单的方式完成您提出的问题。

    @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);
    }
    

    In Service 当你的任务完成时调用这个方法

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

    【讨论】:

      【解决方案2】:

      要么在AsyncTask 本身中工作,要么使用IntentService 而不是普通的旧Service,或者从Service 开始一个线程来完成你的工作。 Android 中的 Service 本身并不使用不同的线程(IntentService 确实可以完成它的工作)。

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 嗯,没错。我认为启动一个线程会导致另一个线程并行执行。这似乎是错误的。我将尝试将我的服务的“工作”放在异步任务中。谢谢
        【解决方案4】:

        来自引导主题Services

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-07-21
          • 1970-01-01
          • 1970-01-01
          • 2018-09-10
          • 2020-09-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多