Antipattern: freezing the UI with a Service and an IntentService
The worst thing that can happen to your app's responsiveness is an "Application Not Responding" (ANR) dialog.
In my previous posts I described how to freeze the UI with a Broadcast Receiver and with a Async Task.
In this post I'll freeze the UI with a Service and with an IntentService.
A Service is an application component that can perform long-running operations in the background.
We should read official doc very carefully.
The standard pattern for implementing a Service is to create and run a new Thread from
I have often seen code in
This is fine, but do not forget that this method is not executed in separate thread.
If you launch service from your Activity,
In our BAD example (intentionally bad) we will launch a Service.
Launch app, click refresh button and the freezing up of the UI is gone!
Here we can see where runs
...."Application Not Responding" (ANR) dialog...
We can see as OwnThread instance runs in separate Thread.
We can do the same with an IntentService.
It is a subclass of Service that uses a worker thread to handle all start requests, one at a time.
If we see source code we can find where it creates a thread.
You should pay attention to
Both methods run in Main Thread... therefore also in this case you should avoid long task in these methods.
Indeed, you should not override
It is very simple to obtain a ANR dialog with an IntentService.
This is our bad code.
We can see as
You can get code from GitHub:
In my previous posts I described how to freeze the UI with a Broadcast Receiver and with a Async Task.
In this post I'll freeze the UI with a Service and with an IntentService.
A Service is an application component that can perform long-running operations in the background.
We should read official doc very carefully.
- A Service is not a separate process. The Service object itself does not imply it is running in its own process
- A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors)
The standard pattern for implementing a Service is to create and run a new Thread from
onStartCommand()
to perform the processing in the background, and then stop the Service when it’s been completed.I have often seen code in
onStartCommand()
method that creates a separate Thread.This is fine, but do not forget that this method is not executed in separate thread.
If you launch service from your Activity,
onStartCommand()
will be execute in main GUI Thread.In our BAD example (intentionally bad) we will launch a Service.
public class ServiceFreezingActivity extends SherlockActivity { protected ServiceFreezy mService = null; private static final String TAG = "ServiceFreezingActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.service); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } /** * */ private void newEvent() { Toast.makeText(this, getString(R.string.text_newevent), 1000).show(); } /** * Launch Async Task */ private void launchService() { Toast.makeText(this, getString(R.string.text_service), 1000).show(); Intent serviceIntent = new Intent(this,ServiceFreezy.class); startService(serviceIntent); } @Override public boolean onCreateOptionsMenu(Menu menu) { getSupportMenuInflater().inflate(R.menu.freezing_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; case R.id.menu_refresh: launchService(); return true; case R.id.menu_newevent: newEvent(); return true; } return super.onOptionsItemSelected(item); } }In our example we will take "a long running task" in onStartCommand() method. This means that our Service blocks any UI handling.
public class ServiceFreezy extends Service { private static final String TAG = "ServiceFreezy"; public ServiceFreezy() { } @Override public int onStartCommand(Intent intent, int flags, int startId) { // This is an example of WHAT NOT TO DO !! // A Service is not a separate process. // This method runs in Main Thread.... avoid long task in this method try { Thread.sleep(7500); } catch (Exception e) {} Log.d(TAG, "onStartCommand END"); OwnThread thread = new OwnThread(); thread.start(); return START_STICKY; } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate"); } private class OwnThread extends Thread { @Override public void run() { Log.d(TAG, "Separate Thread"); try { Thread.sleep(10000); } catch (Exception e) {} Log.d(TAG, "Separate Thread END"); } } @Override public IBinder onBind(Intent intent) { return null; } }
Launch app, click refresh button and the freezing up of the UI is gone!
Here we can see where runs
onStartCommand()
method:...."Application Not Responding" (ANR) dialog...
We can see as OwnThread instance runs in separate Thread.
We can do the same with an IntentService.
It is a subclass of Service that uses a worker thread to handle all start requests, one at a time.
If we see source code we can find where it creates a thread.
You should pay attention to
OnCreate()
and onStartCommand()
methods.Both methods run in Main Thread... therefore also in this case you should avoid long task in these methods.
Indeed, you should not override
onStartCommand()
method for your IntentService.It is very simple to obtain a ANR dialog with an IntentService.
This is our bad code.
public class IntentServiceFreezy extends IntentService { private static final String TAG = "IntentServiceFreezy"; public IntentServiceFreezy() { super("IntentService"); } @Override public void onCreate() { super.onCreate(); // This is an example of WHAT NOT TO DO !! // This method runs in Main Thread.... avoid long task in this method try { Thread.sleep(2500); } catch (Exception e) { } Log.d(TAG, "onCreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // This is an example of WHAT NOT TO DO !! // You should not override this method for your IntentService. // This method runs in Main Thread.... avoid long task in this method try { Thread.sleep(7500); } catch (Exception e) {} Log.d(TAG, "onStartCommand END"); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(Intent intent) { Log.d(TAG, "Separate Thread"); try { Thread.sleep(1000); } catch (Exception e) {} Log.d(TAG, "Separate Thread END"); } }Here you can see where runs
OnCreate()
method.
We can see as
onHandleIntent()
instance runs in separate Thread.You can get code from GitHub:
But what WE MUST TO DO?
ReplyDeletewhere and how we have to run long tasks? For example, I need run five requests to the five different sites... how to implement it? without freezing UI...
It depends on your environment and what you want to achieve.
ReplyDeleteIt is important to use methods that do not run in the main thread.
For long task, I would use a IntentService using the method onHandleIntent().
If you have to update your activity, you can use a BroadcastReceiver that you can register in onResume() method, and unregister in onPause().
Alternatively you can use an AsyncTask using the method doInBackground() or use your own Thread.
Thank you for your response.
ReplyDeleteMy task is: when you press the button - to update the information about the object. To do this, program makes a request on a few different sites, parses response, the result is stored in the database, and, if the activity is still alive, modifies it.
Do I understand correct, that all requests should be executed in onHandleIntent from IntentService? With BroadcastReceiver everything clear.
This comment has been removed by the author.
ReplyDeleteThank you for this wonderful information looking forward for more. I really appreciate your efforts to write such amazing piece of content for us. Are you looking for android services at reasonable prices.
ReplyDeleteHey,
ReplyDeleteThank you, I appreciate that I am getting a lot of good and reliable information from your post. Thanks for sharing such a kind of wonderful post about Line Freezing.
This is the first time I was able to read an article on this topic without being bored. I can tell that you worked very hard on this article. Thank you. Either you are looking for tags with strings attached. we can give you quality material, which last for years. Call and talk to our Designer.
ReplyDeleteYou have an incredible way with words as displayed in your article. You're even acceptable with instructive substance like you have here. I like your perspectives and your composing method. Keep doing awesome! Either you are looking for tags with strings attached with or without strings. we can give you quality material, which last for years. Call and talk to our Designer.
ReplyDeleteaninZcu_hi_1980 Eric Spier Free Download
ReplyDeletemihostobit