Writing Firebase database after app is swiped from recent list - android

I need to write three items of data in Firebase Realtime Database in case the user kill the app
from recent list while it's still running; I implemented a service in order to
update the database when onTaskRemoved is called.
In the manifest the service is declared with the option android:stopWithTask="false"
Here is the service
public class ServiceAppMonitoring extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
SharedPreferences mSettings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
//Get some datas from Shared Preferences...
String path1 = "first/node/path";
mDatabase.getReference(path1).setValue(false);
if (condition) {
// Compose array of datas
List<Object> data2 = Arrays.asList(new Object[]{ ... });
String path2 = "second/node/path";
mDatabase.getReference(path2).setValue(data2);
// Compose array of datas
List<Object> data3 = Arrays.asList(new Object[]{ ... });
String path3 = "third/node/path";
mDatabase.getReference(path3).setValue(data3);
stopSelf();
} else {
stopSelf();
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) { return null; }
}
Strangely only the first instruction is successful, the other two seem to be ignored... at least no data is written into database.
Further I've noticed another "unusual" behaviour, if I arrange all the DatabaseReferences in the
following way:
mDatabase.getReference("first").child("node").child("path").setValue(false);
no one of the instructions end up writing into database, to get (at least) the first one working I've to arrange this way:
mDatabase.getReference("first/node/path").setValue(false);
Can anybody kindly help me to understand why this happens?
Thanks

This is almost certainly because Firebase operations are asynchronous, and return immediately before the writes are complete. onTaskRemved is going to return before either of the database writes fully finish.
I'm guessing that your app process is going to die very soon, if not immediately, after onTaskRemved returns. This means that your database writes might not finish. Android doesn't know that these writes are pending, and it's not going to wait for them.
Since you don't have way from your service to tell Android to wait for these writes, you will have to schedule them for later. I suggest looking into using WorkManager to schedule the writes to happen in the background, whenever Android allows it. It might not be immediate, but WorkManager will make sure that any scheduled tasks will eventually complete.

Hey based on your answer I updated a small thing on database from onTaskRemoved like this
I already initialized the DatabaseReference in the onCreate method
DatabaseReference temp = FirebaseDatabase.getInstance.getReference().child("temp");
and in onTaskRemoved
temp.setValue(true);
this is getting executed and I added a onchange listener in onCreate method to listen for this values change and it worked like a charm. If you don't understand anything feel free to ask and let me know how you got over this problem:)
EDIT:
This is not working in all devices...
EDIT AGAIN: I simply used on Destroy method in my service and killed the service after completing the task and is working for now...
EDIT AGAIN AND AGAIN: OnDestroy is not working in android 6 or below I guess. I tested in Android 6 and it didnt work.

Related

IntentService: how to add and remove intents from the worker queue?

in Android they make it seem like an IntentService is the way to go when uploading a list of pdfs in the background.
How does one actually access the worker queue in order to delete a particular item from the worker queue? I also would like to re-add an item to the queue if uploading that item fails for some reason.
Any ideas?
You can't delete something from the queue, but you could flag things as skippable with something like this:
private static Collection<Object> cancelledThingIds;
public static void cancelThing(Object thingId){
cancelledThingIds.add(thingId);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final Object thing = intent.getExtra(EXTRA_THING);
if(cancelledThingIds.contains(thing.getId()))
cancelledThingIds.remove(thing);
else{
processThing(thing);
}
}
}
The retrying of items is much more straightforward though - simply create a new fresh intent for your intentservice and start it again. You could include something like a "attempt number" extra within the intent so you can do something else if you've tried too many times.

Make a POST call every 10 seconds for an infinite time?

How can I make a certain function execute after every 10 seconds for an infinite time?
What I have done till now: I am getting the location values of the user from the App and storing them on the server. I am using a service, so that, the code keeps running for an infinite time, I am using a Broadcast receiver, so that, if the phone is booted, the service should start again and starts sending me the location.
The issue Everything works perfectly fine for about first 10-15 minutes, but, after this, the service gets stopped by itself. Also, when the user signs up for the App, authorized tokens are generated. These tokens are also sent in the POST call as one of the parameters, for security purposes. Even these tokens are lost, despite working perfectly fine for the initial 10 minutes. I am storing these tokens in SharedPreferences. Any help in this regard would be highly appreciated.
Code for SharedPreferences
Log.i("onCreate", "onCreate");
Log.i("atoken value", ConfirmToken.avalue);
Log.i("utoken value", ConfirmToken.uvalue);
atoken = ConfirmToken.avalue;
utoken = ConfirmToken.uvalue;
Log.i("atoken value", atoken);
Log.i("utoken value", utoken);
Log.i("Starting SharedPref", "Starting SharedPref");
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("atoken", atoken);
editor.putString("utoken", utoken);
editor.commit();
if (settings.contains("atoken")) {
atoken = settings.getString("atoken", "nulll");
Log.i("Inside SharedPref", atoken);
}
if(settings.contains("utoken")) {
utoken = settings.getString("utoken", "nulll");
Log.i("Inside Sharedprefs", utoken);
}
//Calling UpdateData here so that values of lat, lng get updated, before they are used by MyService.java
UpdateData();
startService(new Intent(this, MyService.class));
Now, the update data function simple makes a POST call, using these tokens and Location values as parameters.
This is how I run a task every few seconds. Note that it runs in another thread, so accessing UI elements needs runOnUiThread call, but since you are in a service, you will not have any issues with that.
private ScheduledThreadPoolExecutor taskExecutor;
private void stopTimerTask() {
if (taskExecutor != null)
taskExecutor.shutdownNow();
// keep one task at any given time
taskExecutor = new ScheduledThreadPoolExecutor(1);
}
private void startTimerTask() {
stopTimerTask();
taskExecutor.scheduleWithFixedDelay(Timer_Tick, TIMER_INITIAL_DELAY, TIMER_PERIOD, TimeUnit.MILLISECONDS);
Log.d("Pool", "Timer Task Running");
}
private Runnable Timer_Tick = new Runnable() {
#Override
public void run() {
// Do something
}
};
You should however be aware that Android OS may terminate your service at any time when running low on resources or it feels like the service is doing too much work. You should start focusing on how to restore it's state, just like every one else does.
I think the following is the easiest way.
Also remember if you are making a network call, make an asynchronous request so that your app doesn't stop working while your app waits for the response.
for(long startTime = new Date().getTime();new Date().getTime() - startTime ==10000; startTime++)
{ /*your code goes here*/ };
No matter what you do, if the system is low on resources, it will terminate your app.Please let me know weather this works for you or not :)

restoring alarm after device powered off

I think i have coded myself into a bit of a corner here. but I will try to explain my issue as best as I can. basically I am building an application on android that is supposed to be a copy of the alarm app on the phone. I have an object that represents the alarm. it includes time, and days as booleans etc. i persist these objects by serializing them and saving them to a file. then, on boot, I have a broadcastreciever which starts a boot service. basically the bootservice has a loop that iterates over my list of alarms. iam trying to call a method on each alarm object called "setSysAlarm()", which is supposed to recreate each android system alarm at the saved time. at present, the "setSystemAlarm" method is only creating a toast for testing purposes. BUT this is causing the application to crash. there is obviously a flaw in my design and I think that trying to use the app context is causing the crash. My thinking is that I should possibly create all alarms via the service through the GUI when is running, aswell as recreating the alarms on boot? therefore alarms creation can be done regardless of wheather the app is running, also the alarms will be created in one place ? below is my boot service code which is executed on boot.
public class BootService extends Service {
private Thread setallarams;
private file_acces_int fileaccess;
private ArrayList<alarm_entity> alarmlst;
private Runnable setalarmsrunnable = new Runnable() {
#Override
public void run()
{
for(alarm_entity alarm : alarmlst)
{
alarm.setSystemAlarm();
}
}
};
#Override
public void onCreate()
{
fileaccess = new file_access_model(getApplicationContext());
alarmlst = fileaccess.readFromFile();
setallarams = new Thread(setalarmsrunnable);
cont = this;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
setallarams.start();
try {
setallarams.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
stopSelf();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
and here is the setSystemAlarm() method from my alarm_entity class. basically this is meant to create a toast on boot but at present the app is crashing
public void setSystemAlarm()
{
Toast.makeText(cont, "hi there", Toast.LENGTH_SHORT);
}
if someone could help me out here id appreciate it. the methods i was using to get the context were
1. pass it in from the bootService. doesnt seem doable to me?
2. cretaing an instance on of Applicationin the constuctor of each alarm_entity and using that as the context. this also seems pretty stupid to me. lol
anyway thanks in advance and sorry for the long winded question!
Anyway, we´ve discussed too much for how You get the Logcat output :) . The basic question is, why You get this error. Maybe this is not the full answer, but I need to show some code. You are initializing Your context inside onCreate() of the service:
#Override
public void onCreate()
{
fileaccess = new file_access_model(getApplicationContext());
alarmlst = fileaccess.readFromFile();
setallarams = new Thread(setalarmsrunnable);
cont = this;
}
But like described in the API:
Do not call this method directly.
I don´t know if this is the reason for Your crash, we have no Logcat, it could be any other reason. But it´s recommended to initialize in onStartCommand(), so put Your initializations inside onStartComand():
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
fileaccess = new file_access_model(getApplicationContext());
alarmlst = fileaccess.readFromFile();
setallarams = new Thread(setalarmsrunnable);
setallarams.start();
.
.
.
The other thing is, I can´t see initializing alarm_entity class, maybe I am blind (?), but I can´t see nowhere that You pass a context to this class. For example, if You are initializing this class, it must be something like this inside Your onStartCommand();
mAlarm_entity = new alarm_entity(this);
Because Service holds context, then simply call this. Delete the onCreate() and then You don´t need to initialize a context, because the service has it allready.
Add this permission to your manifest
> android.permission.RECEIVE_BOOT_COMPLETED

Job manager in Android

I have a task to run several different jobs in Android app. Each job is long-running and cosumes network, database and file system much. Each job can be run manually by user or scheduled by AlarmManager. It is very important that each job runs till the end, so it needs to continue running after user leaves the app, or even when user does not open the app at all. Jobs have some ID attribute like this:
class Job {
int id;
}
I need this hypothetical JobManager to receive jobs and sort them by ID. If a job with id = 1 is already running, then JobManager should skip all the subsequent jobs with id = 1 until this job is finished. But if a job is submitted with id = 2, then it is accepted and can be run in parallel with the first job.
The jobs should also to keep wake lock until completed, like it is done in CommonsWare's WakefulIntentService.
I have several ideas how to implement this, but all have their drawbacks:
Subclass of the Service class that runs always in background and is automatically restarted, when killed for some reason. Drawbacks: it consumes resources even if not running anything, it is running on UI thread, so we have to manage some threads that can be killed by system as usual, each client has to start the Service and nobody knows, when to stop it.
WakefulIntentService from CommonsWare. Drawbacks: because it is IntentService, it runs only sequentially, so it cannot check for existing running job.
Boolean "running" flag in the database for each job. Check it every time we want to run a job. Drawbacks: too many requests to db, difficult to implement properly, sometimes 2 equal jobs still can run in parallel, not sure about flags staying "true" in case of any unexpected error.
Existing library disigned for this purpose. As for now except CWAC-Wakeful I have found:
Robospice: https://github.com/stephanenicolas/robospice
Android Job Queue: https://github.com/path/android-priority-jobqueue
but still I don't know, how to use these libraries to run exactly one centralized service, that whould accept jobs from any other Activity, Service, BroadcastReceiver, AlarmManager, etc, sort them by ID and run in parallel.
Please advise me what solution can be used in this case.
UPDATE: See below my own solution. I'm not sure, if it works in all possible cases. If you are aware of any problems that may arise with this, please comment.
This seems to be suited for the new JobScheduler API on Lollipop, then you will have to make a wrapper around it to implement all the features that the sdk implementation is missing.
There is a compat library if you need to implement this on versions below Lollipop.
If anybody faces the same problem, here is the solution I came up with. I used Robospice lib, because it is the most robust way of running some jobs on a Service and syncing results back to the Activity. As I did not find any ways to use this lib with WakeLocks, I extended 2 classes: SpiceManager and SpiceRequest. The new classes, WakefulSpiceManager and WakefulSpiceRequest, actually borrow CommonsWare's ideas about WakeLocks, the implementation is very similar.
WakefulSpiceManager:
public class WakefulSpiceManager extends SpiceManager {
private static final String NAME = "WakefulSpiceManager";
private static volatile PowerManager.WakeLock wakeLock;
private Context context;
public WakefulSpiceManager(Context context, Class<? extends SpiceService> spiceServiceClass) {
super(spiceServiceClass);
this.context = context;
start(context);
}
private static synchronized PowerManager.WakeLock getLock(Context context) {
if (wakeLock == null) {
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME);
wakeLock.setReferenceCounted(true);
}
return wakeLock;
}
public <T> void execute(WakefulSpiceRequest<T> request, RequestListener<T> requestListener) {
PowerManager.WakeLock lock = getLock(context);
lock.acquire();
request.setLock(lock);
// explicitly avoid caching
super.execute(new CachedSpiceRequest<T>(request, null, ALWAYS_EXPIRED), requestListener);
}
}
WakefulSpiceRequest:
public abstract class WakefulSpiceRequest<R> extends SpiceRequest<R> {
private PowerManager.WakeLock lock;
public WakefulSpiceRequest(Class<R> clazz) {
super(clazz);
}
public void setLock(PowerManager.WakeLock lock) {
this.lock = lock;
}
#Override
public final R loadDataFromNetwork() throws Exception {
try {
return execute();
} finally {
if (lock.isHeld()) {
lock.release();
}
}
}
public abstract R execute() throws Exception;
}
So basically here we acquire the lock every time we are going to send a request from WakefulSpiceManager. After that the lock is passed to the WakefulSpiceRequest. When request finishes its work, it cleans the lock with release() method - this will happen even if the activity with WakefulSpiceManager is already destroyed.
Now we use those classes in usual Robospice's manner, with the only exception that we need to pass only WakefulSpiceRequests to execute on WakefulSpiceManager:
WakefulSpiceManager manager = new WakefulSpiceManager(context, MyService.class);
manager.execute(new WakefulSpiceRequest<MyResult>(MyResult.class) {
#Override
public MyResult execute() throws Exception {
return ...
}
}, new RequestListener<MyResult>() {
#Override
public void onRequestFailure(SpiceException e) {
...
}
#Override
public void onRequestSuccess(MyResult result) {
...
}
});
The new Workmanager will help you schedule tasks in any order you want. You can easily set constraints to the job that you want to be en-queued along with many other advantages over JobScheduler API or alarm manager. Have a look at this video for a brief intro - https://www.youtube.com/watch?v=pErTyQpA390 (WorkManager at 21:44).
EDIT: Updated my ans to show the capabilities of the new API
You will not need ids to handle the jobs with this one. You can simply enqueue the task and the rest will be handled by the API itself.
Some work case scenarios are
WorkManager.getInstance()
.beginWith(workA)
// Note: WorkManager.beginWith() returns a
// WorkContinuation object; the following calls are
// to WorkContinuation methods
.then(workB)
.then(workC)
.enqueue();
WorkManager.getInstance()
// First, run all the A tasks (in parallel):
.beginWith(workA1, workA2, workA3)
// ...when all A tasks are finished, run the single B task:
.then(workB)
// ...then run the C tasks (in any order):
.then(workC1, workC2)
.enqueue();

app needs notifications of all inserts, deletes of contacts

(working code extract added below)
My app needs to be notified of all inserts and deletes (and maybe updates, but less important) of contacts. This means when the app is started it will need a list of changes. While it is running it should be notified immediately (is it even possible to make changes to contacts outside the app while it is running?).
Should I be using a ContentObserver? Do I need a Service? Is there a way at app startup to get a list of changes that occurred since the last time the app ran?
Thanks.
ContentObserver does indeed work. However, for contacts, it does much less than I hoped for. You only get a notification that something has changed (in fact, you may get several notifications). You wont know what changed. Better than no notification though, I guess.
When you receive the notificaton, you'll have to run queries to find out if any of the contacts you are interested in have changed. If you need to check all of them, I think you'll be better off using a SyncAdapter.
Here's the code I ended up using. First a ContentObserver subclass; this receives notifications from whatever provider you register with (see next block of code):
class MainContentObserver extends ContentObserver
{
public MainContentObserver (Handler handler)
{
super (handler);
}
#Override
public void onChange (boolean selfChange)
{
Message msg = handler.obtainMessage();
msg.what = CONTACTS_CHANGED; // const int declared elsewhere
msg.obj = null;
handler.sendMessage (msg);
}
}
Here's the sceond block - this is the onCreate from your activity (or it could be in onResume). There are two important parts. One, I implement and instantiate a handler. This will receive "messages" from the observer, which runs in a separate thread, and relay them to my activity. The second piece is the creation of the observer, which happens through the register call.
#Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// receive notices from our background threads.
handler = new Handler()
{
#Override
public void handleMessage (Message msg)
{
if (msg.what == CONTACTS_CHANGED) // const int declared elsewhere
System.out.println ("handler: contacts changed");
else
throw new IllegalArgumentException ("unrecognized handler message source: " + msg.what);
}
};
// register content observer for contact changes
contactsObserver = new MainContentObserver (handler);
getContentResolver().registerContentObserver (ContactsContract.AUTHORITY_URI, true,
contactsObserver);
... other initialization ...
}
Finally, one more block of code - you need to unregister the observer or (I've read) you'll have a memory leak. (If you regsiter in onResume, be sure to unregister in onPause.)
#Override
public void onDestroy ()
{
super.onDestroy();
getContentResolver().unregisterContentObserver (contactsObserver);
}
I know there is no broadcast for what you want to do. ContentObserver is what you have to go with. Also check:
Native contact change notification
I think ContentObserver is better option, you can refer following ContentOberver
dealing with contacts.
i think you will have to look into the Broadcast Receiver for your question..

Categories

Resources