I have an Android background service that report positions from time to time. When I test locally over wifi it works pretty well, however when testing in 3G connection for example (sometimes on Edge) I have perceived that the application apparently enters in a bottleneck and do not execute the onLocationChanged method. That's okay because maybe lost signal or so on. However after a while (maybe when connection is re-established) it start updating all requests at once, in a matter of a few seconds many many times the method onLocationChanged is executed.
Does anyone have ideas how to solve that? Is it possible to add timeout into the method locationManager.requestLocationUpdates?
My Listener
public class MyListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
//report location to server
HttlCallToUpdatePostion(loc.Latitude, loc.Longitude, loc.Accuracy);
}
}
My Service
Handler handler = null;
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
MyListener listener = new MyListener();
protected void doWork() {
Looper.prepare();
handler = new Handler();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, listener);
Looper.loop();
}
I wrote an app, exactly what you need.
When it was a service only I met the same problem. While the UI went to background and screen off the service went to background and it scheduled the system calls, once when triggered the buffer was flushed and I had like 10-50 updates.
The solution it is: an Alarm must be set and scheduled with 5000 value and a BroadcastRreceiver will receive and it will handle properly. Than you will meet other problems, which is not asked here.
For me this was a SOLUTION and the app is in use!
Edit:
Alarm setup code part:
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
// In reality, you would want to have a static variable for the request
// code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(this, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
// am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
am.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(), timerInterval, sender);
AndroidManifest.xml :
<receiver android:process=":remote" android:name=".broadcastreceiver.AlarmReceiver"/>
class implementation part:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Context appContext = context.getApplicationContext();
...
check for power saving mode in adorid system setting: it must be disable to permit location manager to generete update location when the screen is off
Related
Recent changes in Androids background task running behaviour makes it very difficult to keep Services alive and continue work in applications when the phone is locked. My Service is only working properly when the screen is on or the phone gets charged. When the phone is locked, the Service shuts down almost immediately or runs way too slow to be useful in any way.
I tried to use "START_STICKY" flag and a startForeground() Notification to keep the Service alive but this doens't help at all. I'm using a Handler that calls dowork() every 5 seconds, which then checks if theres something to do.
I want to perform a simple task on a certain time event: wake up every half/quarter or full hour, do some quick work without CPU limitation, then shut down until next time. The phone should wake up reliable and accurate on time and get "whitelisted" to use some CPU power for around half a minute. I don't do any intense work, that could affect user performance.
public class MyService extends Service {
public MyService() {
super();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("MyService")
.setContentText("Service is running")
.setPriority(IMPORTANCE_HIGH)
.setContentIntent(pendingIntent).build();
startForeground(1, notification);
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
dowork();
handler.postDelayed(this, 5000);
}
}, 1500);
return START_STICKY;
}
For this question i want to refer to Alarm Manager Example
. This one is doing it's job pretty well, i finally got it working that way.
i have a class to get notification from my server I don't use firebase cloud messaging so I am getting data with the intentservice class. However I want to check the notification in per 60 seconds but timer is not work in
protected void onHandleIntent(Intent intent) {
it starts normally when I start the app but after that it doesn't check in time.
is there any way to check the notification every 60 seconds at the background ?
note: i don't use GCM firebase and I will never use it
IntentService starts the service when you send it an intent, runs whatever you define for that intent, then ends the service. If you are intending for the timer to be run then perhaps do it outside of the service. Perhaps you could use a Handler and post a delayed runnable firing the intent, although I must strongly advise against this in the long term since doing 60 second checks using the phone's radio will drain its battery fast. GCM's Firebase is meant to handle that issue since it "batches" the network requests, and if you don't want to do that then perhaps use a JobScheduler. Android manages the phone's radio pretty nicely and efficiently so unless 60 seconds is absolutely necessary, then it's not really advisable to do this; users could complain of battery drain.
On that handler thing:
private static Handler handler = new Handler(Looper.getMainLooper);
In your activity, then
private Runnable runnable = new Runnable() {
#Override
public void run() {
try{
//Start your intent service here.
} finally {
handler.postDelayed(runnable, 60000);
}
}
};
The try finally block is if your process somehow may trigger an error. If not necessary then you can remove it.
Then in your Activity's onCreate() or wherever you need to start the repeated trigger:
runnable.run();
You can use Alarm manager
Intent alarmIntent = new Intent(context, MyService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
manager.setRepeating(AlarmManager.RTC_WAKEUP, 60000, 60000, pendingIntent);
I'm developing an app, as mentioned in title. I need somehow to manage that application will be running/counting time even when user starts/switches to another application. Well, as I learned from another discussion at stackoverflow.com, there is no need to create service that works in background and pointlessly burden processor with counting time when app is not active.
Everything what is needed to be done is to store current time when user switch to another app, compare it to time when he switches back and update the UI according to difference between these times. That's for stopwatch mode. When in timer mode, I need to automatically switch back to application according to time, that is app's UI showing when going o background. What could be the best solution suitable for this and can you give me please some simple examples for this?
Use AlarmManager for that. AlarmManager allows you to schedule tasks and get notified when they are fired.
So use AlarmManager
public class MainActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//call function where you want
timeout();
}
public void timeout()
{ //time in milliseconds 1 minute
Long time = new GregorianCalendar().getTimeInMillis()+60*1000; //i.e.60*1000=1minute
// create an Intent and set the class which will execute when Alarm triggers, here we have
Intent intentAlarm = new Intent(this, AlarmReciever.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,time, PendingIntent.getBroadcast(this,1, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT));
}
}
Here is broadcast class:
public class AlarmReciever extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
// show dialog or what you want
}
}
Don't forgot to edit AndroidMainfest:
//permission
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
//our receiver
<receiver android:name=".AlarmReciever"/>
I have a button that when pressed, starts a service. This service starts logging information from the device. However, when I press the run, the screen temporarily freezes for about 8 seconds whilst it logs, and then once it is finished the screen unfreezes, a toast message shows (that's meant to show as soon as you press the button) and then I can do whatever. If i go on the application screen again, when the application is logging (note: the service is always running so that doesnt freeze it, just the logging) then the activity is frozen again and doesnt let me do anything until the logging is complete.
I have tried asynctasks and running on a new runnable/new thread but none of these have seemed to work for me. Whether i am implementing them correctly or not I'm unsure, but I'd like to fix the problem.
Here is my onStartCommand in the service class:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// THIS WOULD BE THE METHOD THAT RUNS WHATEVER YOU WANT TO DO EVERY SO OFTEN SO FOR ME THIS IS GETTING ALL DATA ETC
getProcessInfo();
// LOG DELAY = SECONDS BETWEEN RUNNING SERVICE/METHOD. SET AT THE TOP
myPendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Alarmmgr.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+LOG_DELAY*1000, myPendingIntent);
Intent notificationIntent = new Intent(this, LogOrCheck.class);
PendingIntent contentIntent = PendingIntent.getActivity(this,
101, notificationIntent,
PendingIntent.FLAG_NO_CREATE);
NotificationManager nm = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources res = this.getResources();
Notification.Builder builder = new Notification.Builder(this);
builder.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.arrow_up_float)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.arrow_down_float))
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentTitle("Androigenius")
.setContentText("Service running OK");
Notification n = builder.getNotification();
startForeground(100, n);
return Service.START_STICKY;
}
And here is where I call startService:
but1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (isClicked) {
Context context = getApplicationContext();
Toast toast = Toast.makeText(context, "Please press 'MINIMIZE' at the top to continue logging.", Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP|Gravity.RIGHT, 10, 55);
toast.show();
System.out.println("Start logging");
but1.setText("Stop Logging");
but1.setTextColor(Color.RED);
// START SERVICE, DONE. (STOP IS BELOW).
startService(myIntent);
isClicked = false;
}
else if (!isClicked) {
System.out.println("Stop Logging");
but1.setText("Start Logging");
// STOP SERVICE, DONE.
stopService(myIntent);
but1.setTextColor(getResources().getColor(color.cornblue));
isClicked = true;
}
Services run on the UI thread which is causing the 'freeze'. Using an IntentService will create a service that automatically runs in the background, not on the UI thread. Here is some details of the IntentService class:
IntentService Class
By default, the Service also run in the main thread of your applicaiton, in which your UI operations occur. Therefore, if you perform a long task in your onStartCommand() method, it will block the main thread.
To avoid the problem, you have to migration the logging task into a separate thread. You may use AsycTask class to do so. Please refer to http://developer.android.com/reference/android/os/AsyncTask.html for how to use the class.
In my application, I've got an alarm which triggers a service which downloads information from the internet and shows a notification.
Here's a simplified version of my code:
MyActivity contains this:
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 20);
Intent intent = new Intent(this, AlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 20000, pendingIntent);
And AlarmService looks like this:
public class AlarmService extends Service {
#Override
public void onCreate() {
new myAsyncTask().execute();
}
private class myAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... args) {
//Download stuff
return null;
}
#Override
protected void onPostExecute(Void arg) {
//Show notification
}
}
}
I don't really understand when to use wake-locks, so my question: in this case, should I use a wake-lock and if so, where should I start and stop it?
Thanks in advance
Yes, you will need to use a WakeLock to ensure that your service can finish its work.
If using an IntentService meets your design requirements, I would take a look at WakefulIntentService. It manages the alarms and the WakeLocks on your behalf and is easy to set up. The WakeLock is acquired when the alarm fires, and the WakefulIntentService library takes care of releasing it when the service is finished.
If you go this route, you won't want to use AsyncTask -- you'll need to keep the service actively busy (in its doWakefulWork() method) in order to hold the WakeLock.