2011-12-06 81 views
4

我的用例爲(大約)以下的第一次啓動:的Android startService()需要很長的時間才能返回到UI線程

  1. 活動啓動的服務
  2. 服務獲取並在數據庫中
  3. 保存數據
  4. 服務通知活動,意圖
  5. 活動顯示數據

現在我想同時顯示第一個進度條e服務正忙碌。問題是:

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

需要很長的時間來「回來」到UI線程。它似乎是一個同步功能(或not?)。如果一個空的服務類的startService命令幾乎是即時處理的。似乎UI線程等待Serice處理它的工作,這根本沒有意義。我試圖開始(像看起來一樣愚蠢)在我的UI線程中顯示進度條的同時啓動該服務的異步任務。奇怪的是,這個工程有時候。 Othertimes我只是在我的服務正在工作時獲得一個白色屏幕,之後是一個毫秒的進度條,然後是我的用戶界面。

現在我的問題:如何在不阻止我的用戶界面的情況下啓動服務?

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

回答

1

我想你應該把邏輯從服務移動到異步任務中的doInBackground方法。這就是異步任務,執行艱苦的工作,爲您提供一種簡單的與UI進行交互的方式。在異步任務中調用服務很奇怪,你有沒有理由這樣做?

+0

嗯,真的。我認爲啓動線程會導致另一個線程並行執行。這似乎是錯誤的。我會嘗試將我的服務的「工作」放在異步任務中。謝謝 – Redfox

9

從引導話題Services

小心:服務運行在相同的工藝,聲明它的應用程序,並在該應用程序的主線程,默認情況下。因此,如果您的服務在用戶與來自同一應用程序的活動進行交互時執行密集或阻止操作,則該服務會降低活動性能。爲了避免影響應用程序性能,您應該在服務中啓動一個新線程。

這不會因爲您從AsyncTask調用startService而改變。

1

要麼你在AsyncTask本身的工作,使用IntentService,而不是一個普通的老Service或從Service啓動一個線程做你的工作。 Android中的Service本身並不使用不同的線程(IntentService確實可以完成它的工作)。

儘管開始從AsyncTask,現在看來實際工作正在您的UI線程中執行。

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>")); 
相關問題