I have an activity that demonstrates information ping results about servers. This job is done every second with runnable like below code:
pingRunnable = new Runnable() {
#Override
public void run() {
pingMethod();
resultsNotification();
handler.postDelayed(this, 1000);
}
};
on the other hand, I have to show some results in the notification realtime and I did it, But there is a problem, that in the first when the device was locked after 10 min app and activity was destroyed by OS and just notification stopped in a stagnant status. then I tried to fix it with below code:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
wl.acquire();
wl.release();
Actually, I used wl.release(); like this:
#Override
protected void onDestroy() {
wl.release();
super.onDestroy();
}
It got better when I did it, but when the device was locked this again happened after some hours.
Right now I don't know exactly how can I control these services (background(Runnable) and foreground(Notification) ) together for keeping alive activity for a long time such as two or three days or even more.
First up you shouldn't be using an Activity to do this kind of work a Service is the recommended approach. To do this kind of work intelligently you have a number of options with the Android framework, most recently the new WorkManager component. These services should offer you the ability to control when your background work is scheduled - e.g. only running when a valid network connection is present and by allowing you to select a period when the work should run.
https://developer.android.com/topic/libraries/architecture/workmanager/advanced
Secondly, polling every second will have a drastic impact on battery life - if you do this most likely your app will be flagged as a bad citizen and be a likely candidate for uninstalling.
You should consider whether polling in general is the best option for your users. Using cloud messaging would improve the amount of work your app needs to do to, i.e. you could just push out a notification when the server data changes, which avoids you having to do the manual polling. https://firebase.google.com/docs/cloud-messaging/
Related
Part of my question, how I can set up a job with less then 15 minutes interval in "Nougat", was answerd by "blizzard" in his answer here:
Job Scheduler not running on Android N
He explained the problem and suggested to use the following workaround:
JobInfo jobInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
.setMinimumLatency(REFRESH_INTERVAL)
.setExtras(bundle).build();
} else {
jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
.setPeriodic(REFRESH_INTERVAL)
.setExtras(bundle).build();
}
However, using the suggested
.setMinimumLatency(REFRESH_INTERVAL)
just starts the job once;
but how do I get it periodic with a period of around 30 seconds on an android nougat device (not using handler or alarm manager)?
If someone is still trying to overcome the situation,
Here is a workaround for >= Android N (If you want to set the periodic job lower than 15 minutes)
Check that only setMinimumLatency is used. Also, If you are running a task that takes a long time, the next job will be scheduled at, Current JOB Finish time + PROVIDED_TIME_INTERVAL
.SetPeriodic(long millis) works well for API Level below Android N
#Override
public boolean onStartJob(final JobParameters jobParameters) {
Log.d(TAG,"Running service now..");
//Small or Long Running task with callback
//Reschedule the Service before calling job finished
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
scheduleRefresh();
//Call Job Finished
jobFinished(jobParameters, false );
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
return false;
}
private void scheduleRefresh() {
JobScheduler mJobScheduler = (JobScheduler)getApplicationContext()
.getSystemService(JOB_SCHEDULER_SERVICE);
JobInfo.Builder mJobBuilder =
new JobInfo.Builder(YOUR_JOB_ID,
new ComponentName(getPackageName(),
GetSessionService.class.getName()));
/* For Android N and Upper Versions */
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mJobBuilder
.setMinimumLatency(60*1000) //YOUR_TIME_INTERVAL
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
}
UPDATE:
If you are considering your repeating job to run while in Doze Mode and thinking about JobScheduler, FYI: JobSchedulers are not allowed to run in Doze mode.
I have not discussed about the Dozing because we were talking about JobScheduler. Thanks, #Elletlar, for pointing out that some may think that it will run even when the app is in doze mode which is not the case.
For doze mode, AlarmManager still gives the best solution. You can use setExactAndAllowWhileIdle() if you want to run your periodic job at exact time period or use setAndAllowWhileIdle() if you're flexible.
You can also user setAlarmClock() as device always comes out from doze mode for alarm clock and returns to doze mode again. Another way is to use FCM.
Reference: Doze Restrictions
https://developer.android.com/training/monitoring-device-state/doze-standby
I struggled with same thing when I wanted to setup Job for refresh small part of data. I found out that solution for this problem may be setting up Job one more time with the same ID after i calledjobFinished(JobParameters, boolean). I think it should work every time on main thread.
My function to setup Job looks like this:
JobInfo generateRefreshTokenJobInfo(long periodTime){
JobInfo.Builder jobBuilder = new JobInfo.Builder(1L, new ComponentName(mContext, JobService.class));
jobBuilder.setMinimumLatency(periodTime);
jobBuilder.setOverrideDeadline((long)(periodTime * 1.05));
jobBuilder.setRequiresDeviceIdle(false);
return jobBuilder.build();
}
When I finish my work after first call of Job i call in main thread
jobFinished(mJobParameters, true);
registerRefreshJob(5*60*1000L);
This will reschedule my Job one more time for the same amount of time on the same id. When device is in idle state you still have to take under consideration lack of wake locks in doze so your job may not be started so often as you wish. It is mentioned in https://developer.android.com/about/versions/nougat/android-7.0-changes.html
If the device is stationary for a certain time after entering Doze, the system applies the rest of the Doze restrictions to PowerManager.WakeLock, AlarmManager alarms, GPS, and Wi-Fi scans. Regardless of whether some or all Doze restrictions are being applied, the system wakes the device for brief maintenance windows, during which applications are allowed network access and can execute any deferred jobs/syncs.
I'm trying to program a remote alarm clock application for Android, because my friend sometimes misses her train or is too early (I don't want to wake up, but just want her to set my alarm clock time).
I figured out how to set the alarm clock using Java in just a couple of minutes, but that function must be executed remotely. How to do that?
At the moment I'm using Googles Firebase Cloud Messaging service to send notifications including the time for the alarm clock as parameters.
However, when I receive them and the app isn't open, it doesn't execute any code, but waits until the user taps on the notification. But what I want the app to do is set the alarm clock automatically when a notification is received.
I know this does probably violate a bunch of security guidelines, but this isn't an app for the PlayStore, but just for myself.
My idea is to built some kind of service that's active all the time in the background waiting for notifications. Do you think something like that is possible?
Thanks for your help :-)
Try to pass notification payload to the service class and there you can set alarm manager in the background.
We cannot get notification information when app killed or at background, but if notification arrived, the onCreate of FirebaseMessagingService will be fired, so we could try to get notification information from your backend server in onCreate.
public class MyFirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "in onCreate, try to get informations from backend server, ex..send http request here");
}
I started building my app to send JSON strings to a server, however it is only sent when I click a button. I would like it to be sent automatically after a time that is specified by the user from a TimeDialog. I was suggested to use AlarmManager or Handler, but I do not know how to implement it with my app. I have provided the line of code that will be executes and sends to my server. Any help or suggestions?
Code used I would like it to be run after specified time:
public void onClick(View view) {
switch (view.getId()) {
case R.id.saveBtn:
if (!validate())
Toast.makeText(getBaseContext(), "Enter some data!", Toast.LENGTH_LONG).show();
// call AsynTask to perform network operation on separate thread
new HttpAsyncTask().onPostExecute("server_adress"); //was execute but changed!
break;
}
}
You can use Java Util Timer class to do what you want.
you can see here an example.
Try to use it!!!
While an alarm manager/handler is often the best way schedule future events on Android, Google suggests using a Sync Adapter when scheduling network calls like your application synching to the server at a given interval. The framework provides a predefined user authentication, background scheduling so that you app does not need to be running to make the call, improved battery performance, and handling the case when there is no network connectivity at the time scheduled. Here's their developer page on using Synch Adapters.
In my program, I'd like to check for a new version (getting data from HTTP).
The function works perfectly, but I want to have it running in background every X (configurable, one hour, one day, and so on).
So I wrote this code:
Timer mTimer1 = new Timer();
PowerManager pm = (PowerManager) this.main.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = this.pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, MainActivity.PROGRAM);
PowerManager.WakeLock wl.acquire();
TimerTask mTt1 = new TimerTask()
{
public void run()
{
mTimerHandler.post(new Runnable()
{
public void run()
{
// Do the check...
}
});
}
};
(since this function is in a separate class NOT deriving from Activity, I passed to the constructor the parent class this.main, so that I can call getSystemService. This Variable is declared as private MainActivity main).
Well, when I start the Timer it checks for new version, then, after an hour (so my settings), I check in the Logs and I see that the thread did not run...
I searched in Internet and I found, that I have to use the PARTIAL_WAKE_LOCK, and I do that...
Any idea, why I have this problem?
Thanks a lot!
Luca Bertoncello
Here is a SO answer that can help you with this using a handler and postDelayed().
However, if you want to run this even when the app isn't open then you will want to use an AlarmManger.You create a PendingIntent and create a Calendar instance to set the time you want it to check then use setRepeating() on the AlarmManger. This will have it check even when not in the app. You can also register it in the manifest as Boot_Completed so it will start running again after reboot when the device is turned off
Here is a good example to get you started with AlarmManager
If you are using a Timer, did you remember to schedule your TimerTask?
Try
mTimer1.schedule(mTt1, delay, interval);
And if you want to stop that, do mTimer1.cancel();
and mTimer1.purge(); to clear the schedule queue.
When the phone goes to sleep, execution will be paused for your activity and thus your timer will never fire. Using PARTIAL_WAKE_LOCK is probably not a good idea as it will consume battery the entire time your phone sleeps.
I would suggest taking a look at AlarmManager and specifically setInexactRepeating
Use this code
Timer timer = new Timer();
timer.scheduleAtFixedRate(
new java.util.TimerTask() {
#Override
public void run() {
// Your code
}},
1000, 5000
);
Where 1000 is a post delay , if you want delay for first time , if you don't want than put it 0
5000 is a iteration time
I need some suggestions for approaches to take...
Here's some background info:
Right now I have an Android app and a separate java program running on my server.
The java program continuously go out and gets information from different sites and stores them in 14 different entries in an SQL database on the server.
The Android app then queries the databases to retrieve the info to be displayed.
My goal:
I need suggestions on how to have the app handle checking for updates from the database, and then letting the user know that there is new information.
My first thought is that maybe I need to start a separate thread that queries the database for a time modified. Then if it finds updates, it would pop up on the screen that there is new information.
I'm not too well educated with the way threads or services work, so I guess I'm looking for how to implement this, or whether there is a completely different way to go about update checking that would be better.
Thanks in advance, I appreciate any feedback, input, or suggestions.
Hi Ryan I have also implemented a similar thing in my android app and surprisingly I also had 14 tables in my PostgreSQL Server. First of all, you would want to poll the server periodically even when the app is not in the foreground. For that you need to run a background Service - here you will have to manually create a thread in the service, because Service by default runs on the UI thread OR use an IntentService - you don't have to create a separate thread. Whatever code you write in the intent service will be handled in a different thread automatically
Now you have to make this service execute periodically. For that use an AlarmManager and use the setRepeating()function. In the arguments you have to give a PendingIntent to your Service or IntentService. But don't use an alarm manager if you are going to poll the server for every less than 1 minute. Because the battery will be wasted a lot.
Here is some code that might give you an idea :
function setalarm()
{
Intent intent = new Intent(getBaseContext(), Intent_Service.class);
PendingIntent sender = PendingIntent.getBroadcast(getBaseContext(), 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Random randomGenerator = new Random();
long interval=60000; //1 minute in milliseconds
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, cal.getTimeInMillis(),interval,sender);
}
This is Intent_Service of type IntentService :
public class BackService extends IntentService
{
Context context=this;
//public Timer t=null;
public BackService()
{
super("myintentservice");
}
#Override
protected void onHandleIntent(Intent intent)
{
try
{
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
//..CPU will remain on during this section..
//make our network connections, poll the server and retrive updates
//Provide a notification if you want
wl.release();//Release the powerlock
}
}
}
But if you want instantaneous updates, then use Google Cloud Messaging Services. To know more about how it works see this
Hope this helps you.