My problem is make a function to set up themes in my application every 00:00 AM if there are new themes. As I know, to do this problem we must use a loop.
Here is my code:
private void updateThemes() {
Thread time = new Thread() {
public void run() {
int time = 0;
while(time > 86400000) {
//invoke method or start new activity
}
}
};
}
Please help me - Thanks.
Running a thread and waiting for a full day is not going to work. What if the phone is shutdown? What if the user switches to another app and your app is closed by Android because it needed the resources? Besides, it's not very battery friendly either.
You'd better use the Android AlarmManager to set the times at which you would like to check for updates. Also specify a BroadcastReceiver in your app that will receive and process the alarms. There's an example application that does this here or check this post for more info.
Related
I'm using NotificationCompat.Builder with .setUsesChronometer(true).setWhen(Instant.now().toEpochMilli() + timeDifference.toMillis());.
The setWhen()-timestamp is in the future, so the Chronometer value got a - before the time and it counts down.
When it reaches the timestamp, it continues to change and the value is now positive (counts up).
Is it possible to deactivate the Chronometer at 0:00 or stop it before it starts to count up?
I've found setChronometerCountDown(true) but it's API24+ (I need 19), Android Studio says it cannot resolve this method and I think it just removes the minus sign when counting down so that does not help me.
If the answer is no, is there an alternative?
Updating the notification every second would affect the battery drain I guess?
I'm using RemoteViews in my Notification so the Chronometer of RemoteViews could be an alternative but I can't find a way to stop that one either.
I used a handler to stop the chronometer.
mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mCollapsedView.setUsesChronometer(false);
mNotificationManagerCompat.notify(1, mNotificationBuilder.build());
}
}, timeDifference.toMillis());
It would still be helpful to get some feedback for my solution. I don't have much experience with Android.
I have an app that should show a notification every 2 hours and should stop if user has already acted upon the notif. Since background services are history now, I thought of using WorkManager ("android.arch.work:work-runtime:1.0.0-beta01") for the same.
My problem is that although the work manager is successfully showing the notifications when app is running, but it won't show notification consistently in the following cases(I reduced the time span from 2 hours to 2 minutes to check the consistency):
when app is killed from the background.
device is in screen off.
state device is in unplugged state(i.e not charging).
By consistency , i mean that the notifications show at least once in the given time span. for 2 minutes time span, the freq of notifications went from once every 4 minutes to completely not show any notification at all. for 2 hours timespan( the timespan that i actually want), its been 4 hours and i haven't got a single notification. Here is the Code i am using for calling WorkManger:
public class CurrentStreakActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
setDailyNotifier();
...
}
private void setDailyNotifier() {
Constraints.Builder constraintsBuilder = new Constraints.Builder();
constraintsBuilder.setRequiresBatteryNotLow(false);
constraintsBuilder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
constraintsBuilder.setRequiresCharging(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
constraintsBuilder.setRequiresDeviceIdle(false);
}
Constraints constraints =constraintsBuilder.build();
PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
.Builder(PeriodicNotifyWorker.class, 2, TimeUnit.HOURS);
builder.setConstraints(constraints);
WorkRequest request = builder.build();
WorkManager.getInstance().enqueue(request);
}
....
}
Here is the worker class(i can post showNotif(..) and setNotificationChannel(...) too if they might be erroronous):
public class PeriodicNotifyWorker extends Worker {
private static final String TAG = "PeriodicNotifyWorker";
public PeriodicNotifyWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
Log.e(TAG, "PeriodicNotifyWorker: constructor called" );
}
#NonNull
#Override
public Result doWork() {
// Log.e(TAG, "doWork: called" );
SharedPreferences sp =
getApplicationContext().getSharedPreferences(Statics.SP_FILENAME, Context.MODE_PRIVATE);
String lastcheckin = sp.getString(Statics.LAST_CHECKIN_DATE_str, Statics.getToday());
// Log.e(TAG, "doWork: checking shared preferences for last checkin:"+lastcheckin );
if (Statics.compareDateStrings(lastcheckin, Statics.getToday()) == -1) {
Log.e(TAG, "doWork: last checkin is smaller than today's date, so calling creating notification" );
return createNotificationWithButtons(sp);
}
else {
Log.e(TAG, "doWork: last checkin is bigger than today's date, so no need for notif" );
return Result.success();
}
}
private Result createNotificationWithButtons(SharedPreferences sp) {
NotificationManager manager =
(NotificationManager) getApplicationContext().getSystemService((NOTIFICATION_SERVICE));
String channel_ID = "100DaysOfCode_ID";
if (manager != null) {
setNotificationChannel(manager,channel_ID);
showNotif(manager, channel_ID, sp);
return Result.success();
}
else {
return Result.failure();
}
I am using a xiaomi miA2 androidOne device with Android Pie(SDK 28). There are a few other things that are troubling me:
What can i possibly do to know if my WorkManager is running? Other that just wait for 2 hours and hope for a notification. I actually tried something like that, keeping my phone connected to pc and checking android studio's logcat every now and then. It DOES run all the logs when the worker is actually called, but i don't think that's a correct way to test it, or is it?
In the above Code, the setDailyNotifier() is called from the onCreate() every time the app is opened. Isn't it Wrong? shouldn't there be some unique id for every WorkRequest and a check function like WorkManger.isRequestRunning(request.getID) which could let us check if a worker is already on the given task??If this was a case of AsyncTask, then boy we would have a mess.
I have also checked #commonsware's answer here about wakelock when screen is off, but i remember that work manager does use alarm manager in the inside when available. So what am I missing here?
Few comments:
WorkManager has a minimum periodic interval of 15minutes and does not guarantee to execute your task at a precise time. You can read more about this on this blog.
All the usual background limitation you've on newer Android releases are still relevant when you use WorkManager to schedule your tasks. WorkManager guarantees that the task are executed even if the app is killed or the device is restated, but it cannot guarantee the exact execution.
There's one note about the tasks being rescheduled when your app is killed. Some OEM have done modification to the OS and the Launcher app that prevents WorkManager to be able to accomplish these functionality.
Here's the issuetracker discussion:
Yes, it's true even when the phone is a Chinese phone.
The only issue that we have come across is the case where some Chinese OEMs treat swipe to dismiss from Recents as a force stop. When that happens, WorkManager will reschedule all pending jobs, next time the app starts up. Given that this is a CDD violation, there is not much more that WorkManager can do given its a client library.
To add to this, if a device manufacturer has decided to modify stock Android to force-stop the app, WorkManager will stop working (as will JobScheduler, alarms, broadcast receivers, etc.). There is no way to work around this. Some device manufacturers do this, unfortunately, so in those cases WorkManager will stop working until the next time the app is launched.
As of now , i have this app installed for last 8 days and i can confirm that the code is correct and app is working fine. as said by pfmaggi , the minimum time interval for work manager to schedule the work is 15 minutes, so there is a less chance that the WorkManager would have worked as expected in my testing conditions( of 2 minutes ) . Here are some of my other observations:
Like I said in the question that i was unable to recieve a notification for 4 hours even though i have passed the repeat interval as 2 hours. This was because of Flex Time. I passed in the flex time of 15 minutes and now it shows notifications between correct time interval. so i will be marking pfmaggi's answer as correct.
The problem of repeated work request can be solved by replacing WorkManager.getInstance().enqueue(request) with WorkManager.getInstance().enqueueUniqueWork(request,..)
I was still unable to find a way to test the work manager in the way i have described.
in the beginning I thought it would be fairly simple, but I guess it's not.
I want to call a URL every 10 minutes, either when the app is in the background or
in the foreground. How can I realize this?
I'd use a Service with a Handler inside. Using directly Threads is another approach but it's more likely it will be killed if the Android OS needs to free memory.
The Handler part would be something like this:
boolean stopHandler = false;
Runnable runnable = new Runnable() {
#Override
public void run() {
// Do whatever you need
...
if (!stopHandler) {
handler.postDelayed(this, 600000); // 10 minutes
}
}
};
In iOS 7 you can schedule background operations for periodically fetching data from the network. This tutorial is an example of scheduling background fetch operations -
I'm trying to implement a convenient-to-use system for handling status bar notifications for android, and i was thinking about the following:
Create a database, where i store when and what to show
Create a service what runs in the background using the 'interval' Service, what the API provides
In that service check if any notification needs to be shown according to the database, then show it.
The only problem is, that, i cannot detect, if i need to start the service or not. I tried these things, but none of them worked well so far:
1.) Save if the service was already started on the local storage:
// Do this on application startup
var isRunning = Ti.App.Properties.getBool("service_running", false);
if(!isRunning)
{
var service = Titanium.Android.createService(...);
service.addEventListener('start', function()
{
Ti.App.Properties.setBool("service_running", true);
});
service.addEventListener('stop', function()
{
Ti.App.Properties.setBool("service_running", false);
});
service.start();
}
This obviously won't work, because the android systems native onStop and onDestroy events will not be dispatched, if the Service doesn't terminates unusually (like the user force stops the app), so the stop event also won't be fired.
2.) Try to access any active service via Titanium.Android.getCurrentService(), but i got an error saying Titanium.Android has no method called getCurrentService(). This is pretty strange, because the IDEs code completion offered me this method.
3.) Use an Intent to clear the previously running Service
var intent = Titanium.Android.createServiceIntent
(
{
url : 'notification/NotificationService.js'
}
);
intent.putExtra('interval', 1000 * 60);
//Stop if needed
Titanium.Android.stopService(intent);
//Then start it
Titanium.Android.startService(intent);
But it seems like i need to have the same instance of Intent, that started the service to stop it, because doing this on application startup, then exiting and restaring it results in multiple Services to run.
At this point i ran out of ideas, on how to check for running services. Please if you know about any way to do this, let me know! Thanks for any hints!
EDIT
Here are the source materials which gave me the idea to try the above methods (maybe only i use them incorrectly):
The local storage: Titanium.App.Properties
The method for accessing running services: Titanium.Android.getCurrentService
The method for stoping a service with an Intent: Titanium.Android.stopService
And the full source for the NotificationHandler "class" and NotificationService.js that I wrote, and their usage: link
Use Bencoding AlarmManager and it will provide all you need to schedule an alarm notification : https://github.com/benbahrenburg/benCoding.AlarmManager
This module provides what you need. It's really easy - just set repeat to daily when sheduling a Notification or Service.
Refer https://gist.github.com/itsamiths/6248106 for fully functional code
I am checking if the service is started then show daily notification or else start service and then show daily notification
var isRunning = Ti.App.Properties.getBool("service_running", false);//get service running bool status
if (isRunning) {
Ti.API.info('service is running');
} else {
Ti.API.info('service is not running');
alarmManager.addAlarmService({
service : 'com.mkamithkumar.whatstoday.DailyEventNotificatoinService',
hour : "08",
repeat : 'daily'
});
}
I come one year late, but maybe this can help others in the future.
We had the same idea: run the service forever and do the checks on every cycle (I must check 20 different communications).
And I had the same problem: how to detect that the service is running, to don't run again to don't duplicate the checks.
To solve that problem, what I did is get the current time on every cycle and save it to store.
Then, before launch a new service, I check if the last execution was to far in time: if true, then the service was stopped, else is running.
Not very elegant, but was the only way I found to avoid the problem of the user killing the app (and the service).
This is my code for the "launcher" of the service. In my case, I test 30 seconds far away:
exports.createAndroidServiceForNotifications = function(seconds) {
var moment = require('alloy/moment');
var diffSeconds = moment().diff(Ti.App.Properties.getString('serviceLastRun', new Date().getTime() - 60000), 'second');
if (diffSeconds > 30) {
var now = new Date().getTime();
var delta = new Date(now + (seconds * 1000));
var deltaMS = delta - now;
var intent = Ti.Android.createServiceIntent({
url : 'notificationsService.js'
});
intent.putExtra('interval', deltaMS);
Ti.Android.startService(intent);
}
};
I am developing an App where I show the countdown timer. To countdown the time I am using Handler class. Once the countdown timer reaches certain time the Alarm goes off. My problem is as below,
Initially I show the timer time as 04:00:00. Once it reaches 00:00:00 then the Alarm goes off. The Alarm code is working fine. But the timer display is not reliable. It works fine until I keep the App open. If I close the App (using Home or Back) or lock the device and open App again then the timer shown is not the correct one (delaying a lot, but still alarm works on-time). (But it works sometimes very fine under the same scenario). But whenever I ping the device to the system for checking the Log in eclipse that time all works fine!!!!!!!
1. I want to know whether I am using the Handler properly or not
2. (or) Is going out of the App or locking the device causing the problem
Below is my Handler code,
Handler digiHandler;
// Method to initialize the time and define the Handler
public void initialize(int hourstime,int mintime,int sectime){
hour = hourstime;
min = mintime;
sec = sectime;
digiHandler = new Handler();
handleRunnable = new Runnable(){
public void run(){
updateTimes();
}
};
}
public void startUpdateTheread(){
digiHandler.postDelayed(handleRunnable, UPDATEDELAY);
}
// Method to update the timer times
private void updateTimes(){
timerText = String.format(timerFormat,hour,min,sec );
-------------------------
-------------------------
-- code for incrementing the time ---
--------------------------
--------------------------
--------------------------
startUpdateTheread();
}
Please give the suggestions
Thanks
Edit:
When I observed the log it shows that to countdown 1 second of timer sometimes it is taking 1 minute time. The log is as below,
09-21 21:09:18.965: DEBUG/DigitalTimer(7656): timerText**:04:22:54
****long difference here****
09-21 21:10:19.308: DEBUG/DigitalTimer(7656): timerText**:04:22:53
..................................................................................
..................................................................................
..................................................................................
09-21 21:10:23.314: DEBUG/DigitalTimer(7656): timerText**: 04:22:49
**--long difference here ---**
09-21 21:11:22.604: DEBUG/DigitalTimer(7656): timerText**:04:22:48
It is happening always. So I can rule out that locking/coming out of an App is causing the problem. Seems I need to tweak the Handler part of the code.
The problem is that if the activity dies, then so does the thread it spawned, I recommend creating a service to handle this since such timers can be long i imagine (over 4 minutes) and in that time, you need the application to not die.
take a look at http://developer.android.com/reference/android/app/Service.html and let me know if that seems like a good enough solution.