I have activity which needs to be active all the time. I have thread which sleep 10 sec, and monitors values taken from database, compare them and start method. I'm wondering if user go back to other applications and activities, does my activity and thread still work, or they are handled by activity manager and go to pause-stop-destroy?? How to stay them a live??
Thank you.
here is code for that thread:
new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep(10000);
myHendler.post(new Runnable() {
public void run() {
// TODO Auto-generated method stub
final Calendar cal = Calendar.getInstance();
int godina2 = cal.get(Calendar.YEAR);
int mesec2 = cal.get(Calendar.MONTH);
int dan2 = cal.get(Calendar.DAY_OF_MONTH);
int sati2 = cal.get(Calendar.HOUR_OF_DAY);
int minuti2 = cal.get(Calendar.MINUTE);
trenutniDatum = new StringBuilder().append(dan2).append("-").append(mesec2 +1).append("-").append(godina2);
trenutnoVreme = prepraviVreme(sati2) + ":" + prepraviVreme(minuti2);
for(int i = 0; i < primljenoIzBazeDatum.length; i++){
String bazaBroj = "";
String bazaText = "";
if(primljenoIzBazeDatum[i].toString().equals(trenutniDatum.toString()) && primljenoIzBazeVreme[i].toString().equals(trenutnoVreme)){
int bazaId = Integer.parseInt(primljenoIzBazeId[i]);
bazaBroj = primljenoIzBazeBroj[i].toString();
bazaText = primljenoIzBazeText[i].toString();
String datumPromena = "*" + primljenoIzBazeDatum[i].toString() + "* SENT *";
datumVreme.open();
datumVreme.updateData(bazaId, datumPromena);
datumVreme.close();
sendPoruka(bazaBroj, bazaText);
}
} // end for
} // end run
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
Based on my understanding of what you want to do, here is what I would do :
First, create a BroadcastReceiver
public class Poller extends BroadcastReceiver {
private final String TAG = "Poller";
#Override
public void onReceive( Context context, Intent intent ) {
Log.i(TAG, "Poller broadcastintent received");
Intent myIntent = new Intent( context, PollerService.class );
context.startService( myIntent );
}
then , create the service that is called and then shuts itself down
public class PollerService extends Service {
final String TAG = "PollerService";
#Override
public void onStart(Intent intent, int startId) {
Log.i(TAG, "Service onStart()");
pollingTask.execute();
}
AsyncTask<Void, Void, Void> pollingTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... param) {
// Do what you want in the background
}
#Override
protected void onPostExecute(Void result) {
stopSelf();
}
};
}
then, set an AlarmManager to wake the service every minute
AlarmManager am = ( AlarmManager ) getSystemService( Context.ALARM_SERVICE );
Intent alarmIntent = new Intent( "CHECK_DATABASE" );
PendingIntent pi = PendingIntent.getBroadcast(context, 0 , alarmIntent, 0 );
int type = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long interval = POLLING_INTERVAL_IN_MILLISECONDS;
long triggerTime = SystemClock.elapsedRealtime() + interval;
// For short intervals setInexact repeating is same as exactRepeating, use at least fifteen minutes to make it more efficient
am.setInexactRepeating( type, triggerTime, interval, pi );
Log.i(TAG, "Set inexact alarm through AlarmManager");
}
setup the receiver in Android manifest
<receiver android:name="Poller">
<intent-filter>
<action android:name="CHECK_DATABASE"/>
</intent-filter>
</receiver>
finally, unset the AlarmManager to stop polling once your required SMS is received
AlarmManager am = ( AlarmManager ) getSystemService( Context.ALARM_SERVICE );
Intent intent = new Intent( "CHECK_DATABASE" );
PendingIntent pi = PendingIntent.getBroadcast( context, 0 , intent, 0 );
am.cancel(pi);
I do think that Peter is right though and this will kill you battery unless you'll only be checking until you get the required info and then don't poll and that's a short time.
Also, if you can get the exact time when you want to send the SMS with a single call from the database you can just set up the AlarmManger to wake up the service at that time, perform the action and be done with it. That would be the best approach (I can't quite make out if that is the case from you code but it does seems to be from you comments).
No, no application code on Android is not guaranteed to run all the time. Android OS can kill off aplications and services any time it feels it needs to.
Your best bet to periodically execute code would be to use AlarmManager, which makes your code execute periodically. Also a proper flag must be set to execute your code when device is asleep.
Note, since your period is very short (10s), it would keep CPU running all the time, draining the batterry very quickly.
If it has to be active all the time you have to use a Service: http://developer.android.com/guide/topics/fundamentals/services.html
I'm wondering if user go back to other applications and activities,
does my activity and thread still work, or they are handled by
activity manager and go to pause-stop-destroy?? How to stay them a
live??
They won't be kept "alive". If the system needs the resources your activity is destroyed. If you want to keep things running in the background even after your app is finished you have to use a Service.
In Java language you can scheduling your programs by traditional way:
java.util.Timer
java.util.TimerTask
for more information you can see:
http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html
http://www.ibm.com/developerworks/java/library/j-schedule/index.html
but better practice is using a scheduling framework such as Quartz, you can see http://www.quartz-scheduler.org/.
Spring framework also integration with Quartz framework.
Related
How to run this in background , I mean even I move to other app or go to home screen of my android or close the screen , the button will still clicking itself
please help me
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
button1.performClick();
}
}, 5000);
Things to know
I will try to elaborate as much as I can in a layman terms so that you have a better grasp the Idea of Threads and async tasks
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//business logic
}
}, 5000);
is an Blocking method, which runs on the UI thread (I am supposing you are new to programming/android)[please read about Threads to understand what I am saying in deapth],
which means, in short, your application is executing some logic on the thread ("A worker" which is responsible for the rendering the UI on-screen),
By using Threads you can achieve efficiency in your application by dividing multiple tasks to multiple workers "Threads" but you can't run your application in the background.
How to make your application work in the background?
Google introduced some background limitations in Android Oreo. so to keep your application alive you need
foreground service by showing an ongoing notification.
1. The way you should implement service is like
public class YourService extends Service {
private static final int NOTIF_ID = 1;
private static final String NOTIF_CHANNEL_ID = "Channel_Id";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
// do your jobs here
startForeground();
return super.onStartCommand(intent, flags, startId);
}
private void startForeground() {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
startForeground(NOTIF_ID, new NotificationCompat.Builder(this,
NOTIF_CHANNEL_ID) // don't forget create a notification channel first
.setOngoing(true)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(getString(R.string.app_name))
.setContentText("Service is running background")
.setContentIntent(pendingIntent)
.build());
}
}
2. Also you need to start the service
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
startService(new Intent(this, YourService.class));
}
}
3. Add your service in the "application" tag of your AndroidManifest.xml
<service android:name=".YourService"/>
4. And also this permission request in the "manifest" tag (if API level 28 or higher)
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
In this way, you can keep your service in the background. I suggest you read articles and see GitHub repositories, and also practice practice practice a lot to be good at Android :)
I am stuck in a problem in which I need to compute some concurrent calculation in the background and notify the user when each execution is completed.
I read a lot of articles. In which I found Service Class, Intent Service, and other ones. But I found crash above 24 android os versions.
Nowadays which method is best to execute the background service in android and why?
For the above problem you can use Work Manager. For better understanding please review the following link
https://developer.android.com/topic/libraries/architecture/workmanager
Best Method to execute the Background service is to use the system AlarmManager class and invoke alarm after every XXX seconds but it will drain the bettery but solution definately work for you.
step to follow ,
create alarm
public static void setUpalarm(Context context) {
Intent intent = new Intent(context, RestartServiceFromTimer.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(context , 0,
intent,0);
// Setup periodic alarm every every half hour from this point onwards
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
long delay = 5 * 1000 * 60; // time sets to 5 minute change accordingly
long time = System.currentTimeMillis() + delay;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
alarm.set(AlarmManager.RTC_WAKEUP, time, pIntent);
else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
alarm.setExact(AlarmManager.RTC_WAKEUP, time, pIntent);
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pIntent);
}
2 create Broadcast receiver and restart service again also schedule alarm again
public class RestartServiceFromTimer extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Task Trigger","Task is triggered");
if(!isMyServiceRunning(DetectIncomonCallService.class,context.getApplicationContext()))
{ Intent myserviceIntent = new Intent(context.getApplicationContext(),Service.class);
//start your background service here
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O)
{
ContextCompat.startForegroundService(context.getApplicationContext(),myserviceIntent);//this is for forground service
}
else
{
context.startService(myserviceIntent);
}
}
MainActivity.setUpalarm(context.getApplicationContext());
}
private boolean isMyServiceRunning(Class<?> serviceClass,Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}
3 call method from main activity like this
setUpalarm(MainActivity.this)
You can use Foreground Service for android OREO and higher
versions and for below OREO Android version, you can use background STICKY, NON_STICKEY services. From the service, you can broadcast your action with value when your calculation is completed.
My goal is to have a service polling a Server from the background and notifying the user he gets interesting data. Basically just like WhatsApp does (WhatsApp can be closed and the phone can be sleeping and you are still notified whenever you get a message).
I know about the Service class as well as the IntentService class and that they can do background operations and extend above the lifecycle of an activity.
To make myself familiar with them I wrote a test project with a server which basically just accepts socket connections and prints its input into the console.
Client-side, though, I just cannot get the service to stick around. After 5 seconds of the app being closed the service stops (onDestroy is not even called).
I've tried returning START_STICKY in the onStartCommand() method. I've also tried different approaches polling the data, such as using google's Volley library to fire requests every 5 seconds, as well as an ongoing, lasting Socket connection sending packets of data to the Server every 5 seconds. None of those attempts have been working, though, and the service always is killed. The sticky mode will . I've read some things about AlarmManager to restart the killed process, but some people said that this approach would be bad practice since the AlarmManager can be quite unreliable.
Is there something I am missing or doing wrong? Here is my client-side code:
This is the service's onStartCommand:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "Service has started");
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("chId", "chName", NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true);
channel.enableVibration(true);
notificationManager.createNotificationChannel(channel);
}
showNotification("Service has started");
long start = System.currentTimeMillis();
long now;
BufferedReader input = null;
PrintWriter output = null;
try {
Socket connection = new Socket("192.168.178.21", 6789);
input = new BufferedReader(new InputStreamReader(connection.getInputStream()));
output = new PrintWriter(connection.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
while (true) {
now = System.currentTimeMillis();
if ((now - start) >= 5000) {
output.write("Hi" + System.lineSeparator());
output.flush();
start = now;
}
}
}
}).start();
return START_STICKY;
}
and its onDestroy method
#Override
public void onDestroy() {
showNotification("on Destroy");
super.onDestroy();
}
The showNotification method just pushes a new notifcation forward:
private void showNotification(String text) {
NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "chId")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setTicker("Ticker")
.setWhen(System.currentTimeMillis())
.setContentTitle("Titel")
.setLights(Color.BLUE, 3000, 3000)
.setContentText(text);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setContentIntent(pendingIntent);
notificationManager.notify((int) System.currentTimeMillis(), notification.build());
}
I have been reading about this topic a lot so I hope this is not a duplicate question. Thank you guys for your help!
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.
Hi i need to call a method every 4 seconds, even when the device is sleeping, i use alarm manager with service Start_stick, the service name is TransactionService. the code works well when the device is active and the method is called every exact 4 second, but when the screen is locked and device sleep the calling becomes inaccurate. so the method is now called every 2 seconds, sometimes every 1 sec,5 ....
this is how i run the thread to call method every 4 seconds
AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(
Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(getApplicationContext(),
TransactionService.class);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 0, notificationIntent, 0);
mgr.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), 4000, pendingIntent);
this is the log of calling the method when device is active and screen is on
12-30 13:23:00.565 17397-17479/com.ids.simcardrefill D/url: calling
12-30 13:23:04.565 17397-17537/com.ids.simcardrefill D/url:calling
12-30 13:23:08.565 17397-17411/com.ids.simcardrefill D/url:calling
12-30 13:23:12.565 17397-17655/com.ids.simcardrefill D/url:calling
and this is how the method is calling when device is sleeping
12-30 13:09:12.565 17397-17655/com.ids.simcardrefill D/url:calling
12-30 13:09:17.785 17397-17598/com.ids.simcardrefill D/url:calling
12-30 13:09:20.565 17397-17479/com.ids.simcardrefill D/url:calling
12-30 13:09:25.775 17397-17537/com.ids.simcardrefill D/url:calling
12-30 13:09:28.565 17397-17411/com.ids.simcardrefill D/url:calling
here the difference between calling is inaccurate: 2 seconds, 5 seconds, 3 seconds
this is how the service look like :
public int onStartCommand(Intent intent, int flags, int startId) {
mshared = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
edit = mshared.edit();
hostname = mshared.getString(
getApplicationContext().getString(R.string.hostname), "0");
contin = true;
cost
= mshared.getString(getString(R.string.test), "0.09");
if (contin) {
getTransactions get = new getTransactions(getApplicationContext());
get.execute(hostname);
}
return START_STICKY;
}
`
any solution ??
You should crate a service for working in background: https://developer.android.com/guide/components/services.html
You should use Handler in order to implement every 4 second functionality.
Handler handler = new Handler();
Runnable test = new Runnable() {
#Override
public void run() {
//do work
handler.post(test, 4000); //wait 4 sec and run again
}
};
public void stopTest() {
handler.removeCallbacks(test);
}
public void startTest() {
handler.post(test,0); //wait 0 ms and run
}
EDIT: i have tried the code below and it works for me
MyService.java
public class MyService extends Service {
Handler handler;
Runnable test;
public MyService() {
handler = new Handler();
test = new Runnable() {
#Override
public void run() {
Log.d("foo", "bar");
handler.postDelayed(test, 100); //100 ms you should do it 4000
}
};
handler.postDelayed(test, 0);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
AndroidManifest.xml
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
//some code
startService(new Intent(this, MyService.class));
}
And remember if you want start-stop functionality take loot at my first example.
The correct way to do this is using a Handler (as already mentioned in the other answer), but I will take the liberty to add a few points to it.
The problem
I had a similar situation, where the AlarmManager was firing erratically. Digging deeper into the issue led to me to understand that since the AlarmManager operation wakes up the CPU by holding a CPU wake-lock and is intensive on the battery (given that the device is inactive), the OS tries to batch different alarms from different apps and fires all pending alarms when the device wakes up. This leads to the erratic behaviour of the AlarmManager. The documentation also specifies that we shouldn't be using this to trigger events at exact timestamps. There are Android APIs which are supposed to work for exact intervals, eg AlarmManager.setExact(), but the OS optimises itself to ignore the exactness if the interval duration is less than a minute. [not documented, but speaking from my personal experiences]
The fix
I fixed the issue using a Handler only, as shared in the other answer. But there is a small caveat. In the edge case that the Handler is killed (due to any reason), it won't trigger itself and your polling would stop.
The caveat
The fallback is to keep a AlarmManager as well, running every minute to trigger the Handler back again in case it was stopped prematurely by the OS. So, you have a Handler running every n seconds. Store the timestamp of the last time the Handler was called in SharedPreferences. Have a backup AlarmManager running every x minutes (ideally x = 5*n, so that you don't miss more than 5 polling calls). The AlarmManager checks when the Handler last ran. If it's within the margin, the AlarmManager does nothing and reschedules itself after x minutes. If it's been more than x minutes, the Handler must have been killed by the OS and the AlarmManager starts the Handler back again.
Adding some code to give you context as well.
public class PollingAlarmReceiver extends WakefulBroadcastReceiver {
final long POLLING_FREQUENCY_MARGIN = 5 * 1000; //margin kept in case the System delays any threads
Context mContext = ServicesApp.getContext();
/*
Splash/BootReceiver starts the Alarm and the Handler for polling.
The Handler starts the polling service and schedules the next run after an delay of the polling interval.
Before starting the service, the Handler also checks when the service was last run and whether it is time for the next call or not (with a margin of 5 seconds [POLLING_FREQUENCY_MARGIN]).
The Handler should cover all the cases and run smoothly. In case it fails, the Alarm acts as a failsafe.
The Alarm runs at an interval of 1 minute checking when the Handler was last called.
If it is past the time of the next scheduled call (with a margin of 5 seconds [POLLING_FREQUENCY_MARGIN]), the Alarm starts the runnable and makes the Handler queue the next run.
*/
#Override
public void onReceive(Context context, Intent intent) {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext == null)
mContext = context.getApplicationContext();
if (mContext != null) {
if (getLastPolledTimestamp(mContext) > 0 && (System.currentTimeMillis() > (POLLING_FREQUENCY_MARGIN + getPollingInterval(mContext) + getLastPolledTimestamp(mContext)))) {
startPollingHandler();
}
}
}
Runnable mPoller = new Runnable() {
#Override
public void run() {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext != null) {
try {
if ((System.currentTimeMillis() >= (getPollingInterval(mContext)) - POLLING_FREQUENCY_MARGIN + getLastPolledTimestamp(mContext))) {
if (!isServiceRunning(PollingService.class, mContext)) {
mContext.getSharedPreferences(CommonLib.APP_SETTINGS, 0).edit().putLong(LAST_POLLED_TIMESTAMP, System.currentTimeMillis()).commit();
Intent service = new Intent(mContext, PollingService.class);
startWakefulService(mContext, service);
}
}
} finally {
ServicesApp.getHandler().postDelayed(mPoller, getPollingInterval(mContext));
}
}
}
};
public void startAlarmToCheckForHandler() {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext != null) {
AlarmManager alarmMgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(mContext, PollingAlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 60 * 1000, alarmIntent);
}
}
public void startPollingHandler() {
mPoller.run();
}
public void cancelAlarm() {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext != null) {
AlarmManager alarmMgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(mContext, PollingAlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
alarmMgr.cancel(alarmIntent);
}
}
}
P.S. : I have this code running on production for thousand of devices whose main functionality rely on the exactness of the polling and it seems to be working great for me.