I'm reading a lot of conflicting information on this topic, so going to ask myself with some specific code examples. My Android app is getting "Network Unavailable" errors when trying to make an HTTP request from a background service, only when the phone is asleep. The phone is using the mobile network only when I get these errors (no wi-fi in the building).
I use this code to schedule my service:
static private void SchedulePoll(Context context,int minsFromNow)
{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, minsFromNow);
Intent intent = new Intent(context, PSDroidBroadcastReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
}
My service acquires a PARTIAL_WAKE_LOCK and then calls:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
At that point I'm getting a Network Not Available exception, only when phone in sleep mode.
Is it normal to have issues like this in sleep mode, or should I be able to make an Internet connection from my service? It seems like lots of apps check email and other things, so it should be normal and work most of the time?
I looked through the phones settings and made sure anything that was related to background connections was enabled. It is a Sprint HTC, Evo I think.
Turns out it was an application on the phone called "Juice Defender". I guess it is designed to save battery life, as soon as we disabled it, my app works. GMai also wasn't working with it enabled, so I feel pretty safe that there isn't much I could have done to design my app better... other than making the error message more intuitive.
Even with a Partial_Wake_Lock you need something like:
Settings.System.putInt(getContentResolver(),
Settings.System.WIFI_SLEEP_POLICY,
Settings.System.WIFI_SLEEP_POLICY_NEVER);
Taken from: How do I keep Wifi from disconnecting when phone is asleep?
Related
(Before you mark this question duplicate, please note that I'm facing this problem in a specific API Level (API R), the app shows normal expected working behaviour on other API levels below R).
When running the app on Pixed 3a API R
I'm trying out the the Alarm Manager in android, by building a basic Alarm app. I have an AlarmPageActivity that I tried to start from my custom Broadcast Receiver (AlarmReceiver.java)
I have code in my MainActivity where I set the alarm using Alarm Manager. When the alarm goes off, the pending intent goes to the AlarmReceiver class where I try to start an activity using context.startActivity(context, alarmIntent).
The problem: [Before you go there, yes I have the appropriate flags required (Intent.FLAG_ACTIVITY_NEW_TASK)]. When I set a time for the alarm, and keep the app open, the AlarmPageActivity (the activity which is supposed to pop open when the alarm goes off) launches and the app executes normal behaviour. But when I set a time, and close the app (onDestroy()), the code follows through to AlarmReceiver.java (my Broadcast receiver), the ringtone starts playing, but my AlarmPageActivity doesn't show up (In fact, even it's onCreate() method does not execute). Neither does it show any error in the Log/run window. I tried changing everything from pending intent parameters, to adding new activity flags to the intent object, etc. but nothing worked! You can see below in the code that there is no syntax error that should be stopping the code from starting a new activity through broadcast receiver (when the user is outside the app).
I faced this issue for nearly 2 days. I read every article/post on the internet about starting an activity from a broadcast receiver class. But it wouldn't work, and I got so frustrated. Then MIRACULOUSLY, I thought why not try running the app on a different emulator. And guess what? it worked. sigh... I kept thinking I was doing something wrong or that my code was whack because I'm only so beginner-ish in android studio. But little did I know, that my code was correct all that time.
When running the app on Pixed 3a API 26
The app shows normal expected behaviour. Even after onDestroy(), the BroadCast receiver receives and launches the AlarmPageActivity, with the ringtone :)
My Question: This is the same code (I didn't change/add anything else) that was not working on the emulator device running API R, but works now in API 26. Can somebody explain why it wouldn't work? I would really appreciate. Or maybe my code wasn't compatible with API R in some way... who knows? Enlighten me!
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
...
other code...
...
// Alarm manager code ----------------------------------------
alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 56);
calendar.set(Calendar.SECOND, 0);
long startTime = calendar.getTimeInMillis();
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
final PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(this, 0,
alarmIntent, 0);
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, startTime, alarmPendingIntent);
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Log.d("asdfasdf", "BroadcastReceiver (alarmReceiver) activity reached");
Intent alarmIntent = new Intent(context.getApplicationContext(), AlarmPageActivity.class);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarmIntent);
alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
// ringtone code ...
ringtone.play();
Log.d("asdfasdf", "Reached end of alarmReceiver ");
}
} // mind the wrong indenting here
AlarmPageActivity.java
has the default empty activity code...
And yes, I know I shouldn't run an activity from a Broadcast receiver as it shouldn't do heavy task that takes > 10s and everything, but I just wanted to see how to it would look like before improving on that code later.
I think it not work from android 10 and higher. Please read more detail about Restrictions on starting activities from the background. Try to request permisison SYSTEM_ALERT_WINDOW for this case
I am using a foreground service to track the live location of the user. it is working fine in stock android devices, but in brands like oppo, vivo, Mi etc, the app is killed when the device comes into doze mode. I also tried to use FCM notifications still of no use. I am just wondering has Uber or Ola been able to crack this, bcuz i have seen most of the drivers have been using these brands. How are the able to keep their app alive in doze mode?
you need enable auto start permission for apps in oppo , vivo and mi
try below code worked for me
private void keepServicesInChineseDevices() {
Intent intent = new Intent();
String manufacturer = android.os.Build.MANUFACTURER;
switch (manufacturer) {
case "xiaomi":
intent.setComponent(new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
break;
case "oppo":
intent.setComponent(new ComponentName("com.coloros.safecenter",
"com.coloros.safecenter.permission.startup.StartupAppListActivity"));
break;
case "vivo":
intent.setComponent(new ComponentName("com.vivo.permissionmanager",
"com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
break;
}
List<ResolveInfo> arrayList = getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (arrayList.size() > 0) {
AppDataHolder.getSession(MyApplication.getAppContext()).setPermissionForChineseDevices(true);
startActivity(intent);
}
}
this article is also helpful
Thank you so much guys, for your responses. I would like to tell you that I wrote an email to google support and highlighted the issue to google support, in reply they mentioned below reply:
"Thanks for reaching out.
It seems that you can’t receive a push notification on some Android devices. Upon checking the affected device, it is affected by a device specific (known) issue, and it's caused by OEM features for battery optimization. When the app is swiped away, in some of OEMs which has implemented such a feature, the application is treated similar to "force-stopped" mechanism and services registered with the app that's swiped, is stopped.
For now, I strongly recommend contacting the support team of those affected OEMs to help get it resolved from their end.
You can read more about this issue and a possible way of solving it in this blog post(https://www.freecodecamp.org/news/why-your-push-notifications-never-see-the-light-of-day-3fa297520793/).
I build an application that manage a database of messages and show them to the user, i have a service that basically connect to web server and asks for updates.
I need that service to run every minute even if the application is closed.
so far i wrote the following code:
protected void registerAlarm() {
Intent getUpdatesService = new Intent(this, UpdatesService.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 0, getUpdatesService, 0);
long firstTime = SystemClock.elapsedRealtime();
firstTime += 60 * 1000;
AlarmManager am = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, firstTime, 60 * 1000, sender);
}
I call registerAlarm() from an activity that shows the messages.
That suppose to use AlarmManager to run the service evry minute but it doesn't work.
can anyone help me solve the problem?
I need that service to run every minute even if the application is closed.
That will not be practical on Android 6.0 and higher.
can anyone help me solve the problem?
Tactically, your problem is that you are using SystemClock.elapsedRealtime() and RTC_WAKEUP. Those do not match. Use ELAPSED_REALTIME_WAKEUP.
However:
Your app will not get control every minute on Android 6.0+, unless perhaps the user adds your app to the battery optimization whitelist in Settings
AlarmManager does not work at all in some environments, notably the current developer preview of Android apps on Chrome OS (though for all I know this is a bug)
You should use IntentService instead of Service because it automatically terminates after work is done plus it run on background thread
I am working on an Android application in which I have to compare current time , with a time (saved) in a file, though everything is working fine. I have use services and in service i have use THREAD to run the service infinitely, and in addition to this i have also used PARTIAL_WAKE_LOCK to continue service even the device is sleep but the issue is that instead of acquiring PARTIAL_WAKE_LOCK my service runs for 1/2 hours and then again go to sleep. I don't want to acquire FULL_WAKE_LOCK. Is there any one who can guide me what i have to do in order to run this comparison, i.e. my service will run perfectly once the user set the time.
Thank you in advance.
You are doing it the wrong way. To create permanent service you must
declare it as foreground. No other way about it:
myService.startForeground(MY_NOTIFICATION_ID, my_notification);
If your interest with such a service is to periodically perform fast-ending
actions, and if the in between periods are long, you probably want to use
the alarm API and improve your app's battery consumption.
Edit:
To set a foreground service you must supply the system with a notification
object to be displayed at notification bar for as long as the service is in foreground
Why is that? Because foreground services cannot be killed, and Android needs to know
that the user is aware of that fact.
Setting as foreground:
static final int NOTIF_ID = 100;
// Create the FG service intent
Intent intent = new Intent(getApplicationContext(), MyActivity.class); // set notification activity
showTaskIntent.setAction(Intent.ACTION_MAIN);
showTaskIntent.addCategory(Intent.CATEGORY_LAUNCHER);
showTaskIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pIntent = PendingIntent.getActivity(
getApplicationContext(),
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notif = new Notification.Builder(getApplicationContext())
.setContentTitle(getString(R.string.app_name))
.setContentText(contentText)
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(pIntent)
.build();
startForeground(NOTIF_ID, notif);
And reverting to 'stardard' service mode:
stopForeground(true).
Both setting to foreground and reverting to background can be called by either the service itself (e.g. its onCreate() method) or by external code (e.g. the activity that initiated the service). No problems here.
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.