Android startService () takes a long time to get back to UI thread

my usecase (approximately) on first run:

  • activity starts the service
  • the service receives and stores data in the database
  • the service notifies of the activity with the intention.
  • activity displays data

Now I want to display a progress bar while the service is busy. The problem is this:

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

It takes a very long time to "return" to the user interface thread. This seems to be a synchronized function (or not ?). If the service class is empty, the startService command is processed almost instantly. It seems that the UI thread is expecting Serice to handle its work, which makes no sense. I tried to start (oddly enough, stupid) to start the async task service, showing a progress bar in my user interface thread. It is strange that this works sometimes. In other cases, I get a white screen while my service is running, and then for the millisecond ma progressbar, and then my user interface.

Now my question is: how to start the service without blocking my interface?

 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
source share
4 answers

I think you just need to move the logic from the service to the doInBackground method in the async task. Why do we need an asynchronous task, doing the hard work gives you a simple way to interact with the user interface. It is strange to call a service in an async task, is there any reason why you did this?

+1
source

From the Services Guide:

Warning. Services run in the same process as the application in which it is declared, and in the main thread of this application, by default. Thus, if your service performs intensive or blocking operations when a user interacts with activity from the same application, the service slows down. In order not to affect application performance, you must start a new thread inside the service.

This does not change just because you call startService from AsyncTask.

+9
source

Either do your work in AsyncTask itself, use the IntentService instead of the plain old Service or start a thread from Service to do your work. A Service in Android does not use a different thread in different ways ( IntentService does its job).

Despite starting Service with AsyncTask , it now seems that the actual work is being done in your user interface thread.

+1
source

Please use this code as an easy way to do what you asked.

 @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 the service, when your task completes, call this method

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

Source: https://habr.com/ru/post/1384965/


All Articles