How to arrange long (time consuming) actions on Android? - android

For instance, we are in SomeActivity and the activity has a button that invokes moving files from one dir to another (let's call it job).
On BlackBerry I would:
push a non-cancellable popup (Dialog screen) saying "Please wait..."
start a thread that fulfills the job
on thread completion close the popup
This approach 99.99% can guarantee that we stay on the same screen after the task is over, user just sees the popup and waits for job completion. Device rotation or whatever does not break the desired workflow.
On Android things change. I know there's the AsyncTask that is probably provided to solve my case. There's even a good example of how it should be used. But since there's no guarantee of how long an Activity instance will live the AsyncTask should be cancelled on onSaveInstanceState (and restarted on onRestoreInstanceState). This means using AsyncTask there's no guarantee we are able to fully fulfill the job once started. In some cases as sending an http post request for creating a user I would not want to get in "user already exists for this login" trouble on reruning the AsyncTask. This is possible since the AsyncTask can be interrupted while the request is already sent (and the server actually is doing its job - creating a new user), but the AsyncTask is canceled before we got the response.
Is there any solution on Android to get the BB-like behaviour stated above?

But since there's no guarantee of how
long an Activity instance will live
the AsyncTask should be cancelled on
onSaveInstanceState (and restarted on
onRestoreInstanceState).
Or have it be managed by a Service.

If your Activity wants to stay on the screen, you can simply start a Thread like this:
final File fromFile = ...;
final File toFile = ...;
new Thread() {
#Override
public void run() {
// do something with fromFile, toFile
}
}.start();
That way the GUI-Thread is ready to do other thinks like displaying a
android.app.ProgressDialog
Also, consider making the Dialog uncancellable with
ProgressDialog.setCancelable(false);
That way the user can only leave via the HOME-Key, which you get notified of when
Activity.onPause()
is called. Futhermore you might want to look into Wakelocks, to stop the Screen from turning black and your application pushed in the background where it might be killed. You'd do this in the Thread:
PowerManager pm = (PowerManager) ivContext.getSystemService(Context.POWER_SERVICE);
Wakelock wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyApp");
wakeLock.acquire();
// ... copy stuff ...
wakeLock.release();
Of course you'd have to release the wakeLock, too, when the user leaves via the HOME-Key.
Finally if you want to call GUI-Elements from your background-thread, this will only work if the Thread is part of the GUI-Event-Loop, like the normal Thread is you are running in, when getting called with on...-Methods. To achieve this your background-thread will have to callback to the GUI-Thread via a Handler. Like this:
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.v(TAG, "Got Message "+msg.what); // prints: Got Message 77
// ... do GUI actions ...
}
};
// ... in Thread ...
int lvInfo = 77;
mHandler.sendEmptyMessage(lvInfo);
You can even put objects in the message like so:
Message txtMsg = Message.obtain();
textMsg.obj = "Hello World";
mHandler.sendMessage(lvTextMsg);

In May 2010 Google issued a new IO session called Developing Android REST client applications which explains how to achieve exactly what I asked for.
It turned out the question is rather complicated, so there is no easy and quick solution. The solution requires deep knowledge of Android platform/API. This is the price caused by the flexibility of the app process/Activity lifecycles.
I feel some oddity on why this info was not presented from the very first version of Android. Looks like Google knew how to write 100% bugless apps and for some marketing reason did not share the approach. Just imagine how many buggy apps was written by May 2010.
Anyway I'm glad now I have smth we call best practice approach.

Related

Service-Activity Communication data processing while sleep

Project statement:
i have a simple counter app which has 6 things i am counting. on my wearable, i have a radiobutton group which selects which of those things i want to count. it then displays the current count for the item on the watch and then i can either add or subtract 1 from it from the watch. The watch is only an interface and interaction device. it does no processing. All processing of information and storing of information is done on the mobile. so the watch merely sends messages and displays information.
How it works:
the wear sends messages to the mobile via Wearable.MessageApi.sendMessage() and the phone responds with Wearable.DataApi.putDataItem(). The watch is sending multiple forms of informaiton like add/subtract/countRequest in addition to which item it is references. the mobile only responds with the item count requested and the watch only need change the display if it is a different value than what is showing.
This is a general messenger understanding question. I have
public class MyListenerService extends WearableListenerService{
#Override
public void onMessageReceived(MessageEvent me){
showToast();
}
}
The listener works. Now i want to do something useful with the listener because it is actually sending data i need. But i am having trouble communicating between Service and Activity because of my limited experience. I have read up on messaging and broadcast receivers. and am looking for ideas on how to implement to get my result or a better understanding.
From what i am gathering from trying to code, a service cannot directly interact with my interface, so i need to communicate with my activity in some way. 2 ways i have read is messaging(handlers) and broadcastreceivers.
each of these methods will do the function, however have their drawbacks which is where i am looking for better understanding or help.
for the Handler: even though i can create a static handler class and run code within the handler class, because it is static i cannot call non static objects which means if i try and do this it fails.
Service:
public class MyListenerService extends WearableListenerService{
#Override
public void onMessageReceived(MessageEvent me){
Activity.mHandler.sendEmptyMessage(MyConstants.COMMAND);
}
}
Activity:
public static Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
doThis(msg.what);
}
};
private void doThis(int command){
processCommand();
updateUserInterface();
}
Is there a way i can implement the above Handler, because when i process message if i just simply do a toast, it works, so i can receive the message. I just cant call a non-static object from a static. so i am assuming i cannot update an interface object either if i just threw the code of doThis() inside the Handler since i am just using it as a go between. When i was using LiveListeners and the onMessageReceived() was within my Activity, rather than a separate service, i just called doThis() directly and it worked great.
for the BroadcastReceiver:
There is a lot of code to show so instead i will just explain my issue for it and you may be able to answer from that. apparently you have to register/unregister on onResume()/onPause(). That would prevent me from being able to process information when the phone goes to sleep. the whole point of running a service is so i can do stuff when the phone is asleep or the activity is not in the foreground.
Before i was doing "LiveListeners" and it worked fine, so long as activity was in the foreground and phone was not sleeping. only way to have it work while sleeping is to engage a service to work in the background.
So my question is, what is best way to handle this situation so that i can process the information that the wearable is sending to the mobile while the mobile is asleep. or is there another method to send data i did not find?
If you extend WearableListenerService, you are creating a special Service which runs as part of your app's process. You can use this to communicate with another Service in your app which does all the processing, or use broadcasts (as you noted.) In either case, the Service is running in the context of your process and on the main thread - so if you need to do any heavy processing you'll need to offload it to a background thread.
Since your WearableListenerService is declared in the manifest and its lifecycle managed by Android Wear (by default), it's going to be simplest to either create a secondary Service or use a BroadcastReceiver to do your processing. Just note that "processing" must be lightweight if in a BR. If you use a BR, look into using LocalBroadcastManager as it is more efficient than sending the broadcast via the usual Context.sendBroadcast(). It's roughly the equivalent of sending a message to your app, it just happens to be in Intent form.
I certainly do not want to oversimplify greatly, but I like the easy way. Having intent I just awaken mobile or wearable from Sleep, and then the other threads also perforce awaken and process data.
#Override
protected void onHandleIntent(Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
String tmp = " ";
PowerManager.WakeLock wakeLock = null;
// wakeLock.acquire();
if (intent.getAction() != null) {
tmp=intent.getAction();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), TAG);
wakeLock.setReferenceCounted(true);
if(! wakeLock.isHeld()) {
wakeLock.acquire();
}
Code snippet from https://github.com/NickZt/E52/blob/master/wear/src/main/java/ua/zt/mezon/e52/core/MySpcIntentService.java

How to implement application idle timeout in android application?

Is there a way to implement timeout feature in the following scenarios?
A web application with html pages and native screens.
1.When the application is in the background for 5 min -> destroy the application.
2.When the application is in the foreground but not receiving any user interaction for 5 min ->destroy the application.
I think you can use this.
ApplicationConstants.TIMEOUT_IN_MS will be 300000 //5 min
private void timeout() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
System.exit(0);//close aplication
}
}, ApplicationConstants.TIMEOUT_IN_MS);
}
#Override
protected void onPause() {
super.onPause();
timeout();
}
Cheers,
Regarding background state:
There is no need to kill the app's process manually by default. The Android OS does this by itself if there is a need to free up resources for the other applications.
See this guide for a reference.
Though if you need to perform some background work during this "idle time", you may start a Service to perform those operations and then stop it from code.
Regarding foreground state:
I think the best approach to use here is to send Messages to a Handler of the Main thread of your application, since you do not know if the user will interact with the UI again after they leave. When the user comes back to the UI, you may clear the message queue, using Handler's removeMessages method.
I do not recommend you to finish the process with System.exit(0) in Android.

How to turn keyguard on in reliable way?

DUPLICATE WARNING: this problem deals with details of Android API, suitable for calling both from some frontend and services, there are many similar threads on SO, but focused only on frontends.
Problem
I would like to turn on keyguard programmatically, so for example user clicks a button in my app and the phone gets locked (to use phone user has to unlock it first).
The catch is -- I would like to find rock-solid way, that works in every valid case.
Attempts
I tried:
lockNow with DevicePolicyManager -- when the screen is off (but phone is not locked) this call is ignored (i.e. the keyguard is not activated)
reenableKeyguard with KeyguardManager.KeyguardLock -- the call to the method is ignored in every possible case
goToSleep with PowerManager -- I cannot call it, because of the problem with permission, it requires DEVICE_POWER despite I already have this permission set
So far I pursue the first way (lockNow) with extra hacks that somehow deal with the case when the screen is off, but it extremely ugly, thus I am hoping there is some straightforward way.
One solution could be using thread on postdelayed handler.
the catch here is, thread will stay alive even after the screen is off, where your application would be under paused state (unless process is killed)
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
keyLock.reenableKeyguard();
Log.i("LOCK","key guard back on");
finish();
}
}, 300);
Another way of doing this would be to use timer task, but timer task might get killed sometimes (don't know for sure, but my past experiences says not sure)
TimerTask Active = new TimerTask() {
#Override
public void run() {
keyLock.reenableKeyguard();
Log.i("LOCK","key guard back on");
finish();
}
};
Timer starter = new Timer();
starter.schedule(Active, 300);
I can't be 100% sure this is the "rock solid way" you were looking for, but I've been working with the device policy manager along with the keyguard manager for some while and I came across similar problem that locknow() method would turn off screen and then turns back on devices with android 4.0 above.
I came across this solution while looking through the DDMS debug logs, and hopefully, testing on some devices. So far, it hasn't failed me so here a tip anyway.
Disable keyguard
call locknow()
reenable keyguard in a 300ms or so, with the above methods... ( I prefer the handler and it worked like a charm for me)

Android - manually stoppable Service in a separate thread

I'm writing an app that plays an audio file and I want it to continue doing so while minimized. I've done this, but I want the audio playback to be on a separate thread, because according to the Android developer website, CPU-heavy services work better on a separate thread.
First I tried using IntentService (this was the perfect solution). However, for some stupid reason, the service destroys itself once the code executed - which is immediately after it starts playing the file. I couldn't prevent this.
Then I created a Thread that runs the Service. However, I don't know how to make the Thread stop the service when needed - the best thing I could do is this:
serviceThread = new Thread() {
public void run() {
while (true) {
if (playAudio) {
startService(new Intent(getApplicationContext(),
MusicService.class));
playAudio = false;
}
if (stopAudio) {
stopService(new Intent(getApplicationContext(),
MusicService.class));
stopAudio = false;
}
}
}
};
Evidently, after that I set startService to true to start the service and I set stopService to true to stop it. However, I believe the Thread has to keep doing the check all the time, thus doing a lot of useless work all the time. I'm not even sure why is the app working, isn't it doing like million checks every second?
How can I properly do this?
Assuming you can't block the thread that the service runs in, you can add a java.lang.Thread.Sleep at the end of the loop if you're worried about doing too much work.
You might also want to read up thread scheduling and time slicing to understand why your app is still working (but probably using a lot more CPU than necessary).

start service from activity and wait until its ready

I want to start a Service from an Activity.
First I tried it with a LocalBinder. This works, but the service was bound to the activity. I don't want to stop the service when the activity is gone. I found no solution with the LocalBinder so I removed it and tried this:
use a singleton instance in the service
call the startService methode in a new thread and waits until the instance is available:
final Intent recordService = new Intent(RecordActivity.this, RecordService.class);
Runnable r = new Runnable() {
#Override
public void run() {
startService(recordService);
}
};
new Thread(r).start();
Log.i(MMLF.T, "service instance: "+serviceInstance);
final ProgressDialog mProgressDialog = ProgressDialog.show(
RecordActivity.this, "Waiting", "wait until record service is loaded",
true);
while (serviceInstance == null) {
serviceInstance = RecordService.get();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(MMLF.T, "could not sleep", e);
}
}
mProgressDialog.dismiss();
But this doesn't work, too. It stucked in the waiting loop. If I remove this waiting stuff and the new new Thread(r).start() line is the last, the activity and service start fine.
How to start a service independent from an activity? I also let them to communicate with each other. The activity should call two methods (start and stop recording) and the service should send messages. For the second I can use LocalBroadcast.
Your question is a little confusing, because Services already live independently of Activities. Note, however, that Services run in the main thread by default. If you want to run the Service in a different thread (and in this case it looks like you do), you will have to set up a Messenger object and send messages between your worker thread and your UI thread. You can also look into using AIDL (on top of which Messenger is really built anyway). Your communication, if you don't use a Messenger, could use intents. If this is the case, you should look into IntentService. However, this only works when you are sending messages to the Service, not back and forth. If you want back and forth communication, you will have to use some sort of Messenger or similar pattern.
By the way, using an IntentService for things like 'stop' and 'start' is pretty common. Typically there is also a background thread, which communicates with the Service using a Messenger or something similar, and then sends / receives messages to instruct the worker thread as to what should be done.
You might also look into AsyncTask, as it makes this kind of thing much simpler.

Categories

Resources