Avoid ANR on SCREEN_ON using Handler Thread - android

Getting ANR executing a blocking/heavy call for Intent.ACTION_SCREEN_ON. Below is the code
private static BroadcastReceiver mScreenOnReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_ON)) {
// Blocking operation
}
}
}
To avoid ANR, I am planning to move the Blocking operation inside worker thread. Will the below code help in avoiding the ANR?
private static BroadcastReceiver mScreenOnReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_ON)) {
new Handler().post(new Runnable() {
#Override
public void run() {
//Blocking operation
}
});
}
}
}

No. BroadcastReceivers are short-lived. There is no guarantee that the OS process hosting your BroadcastReceiver will live long enough to execute this code. Not only that, but you would be running this code on the Main (UI) thread, which you cannot block (your Runnable will not run in a "worker thread", it will run in the Main (UI) thread).
Your BroadcastReceiver should start a Service, which can run a background (worker) thread which can perform your blocking operation. Or you may be able to use JobScheduler to schedule this operation (if it is suitable for your purpose).

Related

Intent Service blocking the UI

I need to make so backround job without blocking user UI, so I made a test IntentService to check how it's work, but this intent services block the UI.
Here my Code on start app ic start service:
Intent msgIntent = new Intent(this, AutoExchange.class);
startService(msgIntent);
AutoExchange.java
public class AutoExchange extends IntentService{
public AutoExchange() {
super("AutoExchange");
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The problem is that this service block the main Ui, somethig I did wrong?
instead of thread.sleep() you can you handler
here is an example
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// do stuff
}
},3000);
Try to make a new Runnable() around the try-catch-block.
Caution: A service runs in the main thread of its hosting process; the service does not create its own thread and does not run in a separate process unless you specify otherwise.
Source
Register your service in android manifest.

Android: Unable to perform a task repeatedly using android service

I have written a service in android.I want to repeatedly perform a task using service. That is the service shouldn't die and should perform the task repeatedly. However,the service performs the task just once and then gets killed.How to perform the task repeatedly in background.
My current code is->
public class SyncService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(SyncService.this, "servicestarting", Toast.LENGTH_SHORT).show();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(SyncService.this, "service done", Toast.LENGTH_SHORT).show();
}
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
Toast.makeText(SyncService.this, "repeatedly perform some task", Toast.LENGTH_SHORT).show();
//constantly perform task here
}
}
}
How to repeatedly perform some task using service?
Well you only send one message to the Handler. So that message will be processed once. You could have the Handler pass the same message back again, but with no delay that isn't a good idea- you'll deadlock the main thread. The best way to do something repeatedly would be to spin off a Thread and do it in the Thread, with the Thread's Runnable looping forever.

Android IntentService update loop

My intention is to have download service created when the app first runs and checks for update every 24 hours. I originally had everything running my main activity but it seems to much to run everything on one thread and one class. So this is my attempt to move it to another class and into service. It suppose to run and check for an update ever 24 hours and if there is no internet try again in 4 hours. I specifically want to involve any recursive problems, having two or three same services checking update, just one every 24 hours. But having problem with integrating my code into service, what am I doing wrong?
public class DownloadService extends IntentService {
// TODO 0 - Define your Download Service as Android component in
// AndroidManifest.xml
private int result = Activity.RESULT_CANCELED;
public DownloadService() {
super("DownloadService");
}
// Will be called asynchronously be Android
#Override
protected void onHandleIntent(Intent intent) {
private final Runnable mUpdateUi = new Runnable(){
public void run(){
check();
}
};
private void start(){
new Thread(
new Runnable(){
public void run(){
Log.d(TAG, "inside start");
Looper.prepare();
mHandler = new Handler();
check();
Looper.loop();
}
}
).run();
}
private void check(){
if (isNetworkAvailable()== true){
try {
new checkupdate().execute();
delayTime = 86400000;
Toast.makeText(DownloadService.this, "Daily update check!", Toast.LENGTH_SHORT).show();
}
catch (IOException e) {
e.printStackTrace();
delayTime = 21600000;
}
}else{
delayTime = 21600000;
Toast.makeText(DownloadService.this, "No internet for Daily update check, try again in little!", Toast.LENGTH_SHORT).show();
}
reCheck();
}
private void reCheck(){
mHandler.postDelayed(mUpdateUi, delayTime);
}
}
IntentService already handles setting up a worker thread and queue, and termination when the queue is empty. Which makes it a very good candidate for something like a download service to manage the actual work of downloading data, but not really a great candidate for a time scheduler.
I'd suggest using an AlarmManager to schedule your work instead. What you want is to trigger an Intent to start your DownloadService, by sending it intent with an Action indicating what to do.
Note also that if you want to cancel an IntentService with an Action, you will need to implement onStartCommand in addition to the usual onHandleIntent, so that you can respond to the action immediately -- you cannot do this from onHandleIntent, since the intent won't be sent to that until the current task in the queue is completed. Here's a quick example:
public class DownloadService extends IntentService {
private static final String TAG = "DownloadService";
////////////////////////////////////////////////////////////////////////
// Actions
public static final String ACTION_CANCEL = "package.name.DownloadService.action.CANCEL";
public static final String ACTION_DOWNLOAD = "package.name.DownloadService.action.DOWNLOAD";
////////////////////////////////////////////////////////////////////////
// Broadcasts
public static final String BROADCAST_DOWNLOADED = "package.name.DownloadService.broadcast.DOWNLOADED";
public static final String BROADCAST_ERROR = "package.name.DownloadService.broadcast.ERROR";
////////////////////////////////////////////////////////////////////////
// Extras
public static final String MESSAGE = "package.name.DownloadService.extra.MESSAGE";
// etc.
private boolean isCancelled;
// usual stuff omitted
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null) {
String action = intent.getAction();
Log.v(TAG, "onStartCommand() - action: "+action);
if(ACTION_CANCEL.equals(action)) {
isCancelled = true;
// insert code here to signal any objects to cancel
// their work, etc.
stopSelf();
}
}
return super.onStartCommand(intent, flags, startId);
}
#Override
protected void onHandleIntent(Intent intent) {
if(intent != null) {
final String action = intent.getAction();
Log.v(TAG, "onHandleIntent() - action: "+action);
if(ACTION_DOWNLOAD.equals(action)) {
handleDownloading(intent);
}
else if(ACTION_CANCEL.equals(action)) {
// nothing to do here, handled in onStartCommand
}
}
}
////////////////////////////////////////////////////////////////////
private void handleDownloading(Intent intent) {
// get stuff you need from the intent using intent.getStringExtra(), etc.
if(!isCancelled) {
// do downloading, call broadcastDownloaded() when done
}
else {
// stop work, send broadcast to report cancellation, etc.
}
}
// send a broadcast to a BroadcastReceiver (e.g. in your activity)
// to report that the download completed
private void broadcastDownloaded() {
Log.v(TAG, "broadcastDownloaded()");
Intent broadcastIntent = new Intent();
if (broadcastIntent != null) {
broadcastIntent.setAction(BROADCAST_DOWNLOADED);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
}
}
private void broadcastError(String message) {
Log.v(TAG, "broadcastError(), message: "+message);
Intent broadcastIntent = new Intent();
if (broadcastIntent != null) {
broadcastIntent.setAction(BROADCAST_ERROR);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
if(message != null) {
broadcastIntent.putExtra(MESSAGE, message);
}
sendBroadcast(broadcastIntent);
}
}
}
This is not how IntentService is meant to be used. As per the documentation, IntentService already creates its own worker threads. You should not be creating your own:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Apart from the fact that your code as shown here won't compile (your start method is inside the onHandleIntent method), your general approach seems to be to start your own worker thread. What would happen in this approach is that you would start the thread, onHandleIntent would complete and then the service would be stopped. In addition to not actually working, this approach is also a bad idea because (at best if you're lucky) the service would be running continually 24/7.
What you should do instead is actually do your main work in onHandleIntent which IntentService will queue on a worker thread for you. Then instead of using postDelayed use AlarmManager to set an alarm to send an Intent to start the service again in 24 hours or 4 hours.

how to stop Handler working in android?

My APP has to start some time consuming job when receiving ACTION_SCREEN_OFF, and interrupt the job when receiving ACTION_SCREEN_ON if job is still going on.
public class TimeConsumingWorkIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
TimeConsumingWork();
}
}
public class ScreenStatusReceiver extends BroadcastReceiver {
Intent intent = new Intent(mContext, TimeConsumingWorkIntentService.class);
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
mContext.startService(intent );
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
mContext.stopService(intent );
}
}
}
By print log of time, I find time consuming work is still going on stop the TimeConsumingWorkIntentService (when receiving ACTION_SCREEN_ON).
why ?
Use
// Cancel the runnable
myHandler.removeCallbacks(yourRunnable);
Ok , then you can do something like this
Runnable r = new Runnable{
public void run(){
if(booleanCancelMember != false){
// within this you make the call to handler and work
// Since you block the call the handler wont get repeated
}
}
}
You can't do this like that. When you start your IntentService, it will call onHandleIntent() on a separate worker thread. That mehod then calls TimeConsumingWork(). Stopping the service will not interrupt the execution of the worker thread. It just tells the worker thread that when it has finished processing the current Intent, it should stop.
What you will need to do is to have your TimeConsumingWork() method periodically look to see if it should stop. You can do this by setting a static boolean variable and have TimeConsumingWork() periodically check this variable and quit if it is set.
You don't need to call stopService() on an IntentService as it will stop itself when it has nothing to do.

how can i stop my RECEIVE_BOOT_COMPLETED service

seeing many questions about this but im unable to fix this.
I have this code
public class myBroadcastReceiver extends BroadcastReceiver {
private final String TAG = "myBroadcastReceiver";
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Consts.ANDROID_INTENT_ACTION_BOOT_COMPLEATE)){
Intent newinIntent = new Intent(context, ServiceBootCompleated.class);
context.startService(newinIntent);
}
}
}
It starts a Service and i can debug it using this line
android.os.Debug.waitForDebugger();
I see that return START_NOT_STICKY; is executed but still
the service is visible as a "running" service in the
Setttings>programs>Running Services
the onDestroy() is never called unless i stop it manually.
What do i have to do to stop it,
remove it from "Setttings>programs>Running Services " window?
Once you have completed the work you wanted to do in the background call stopSelf()
Be sure that any real work you do in the Service is done as a background thread and not in onCreate or onStartCommand.
See http://developer.android.com/reference/android/app/Service.html#ServiceLifecycle for more details on the Service Lifecycle.
Example:
public int onStartCommand(final Intent intent, final int flags, final int startId)
{
Thread thread = new Thread(new Runnable()
{
#Override
public void run()
{
//do work
stopSelf();
}
},"MyWorkerThread");
thread.start();
return Service.START_NOT_STICKY;
}
on completion of task, you have to do context.stopService() for stopping this type of unbound service.
Regards,
SSuman185

Categories

Resources