I need an ad screen(revmob) to show once daily when called from the onCreate method. I grabbed the idea from How do I get an Android application's method to run a method daily with Eclipse? but it is not working since the ad is loading every time the onCreate is called.
The code I have is:
if(runOnceDaily()){
revmob = RevMob.start(this, REVMOB_APP_ID);
revmob.showFullscreen(this);
}
private boolean runOnceDaily(){
boolean result = false;
SharedPreferences prefs = this.getSharedPreferences(
"com.blogspot.blog.myapp", Context.MODE_PRIVATE);
long minStartTime = System.currentTimeMillis() - 1000*60*60*24;
long lastTimeRan = prefs.getLong("lastTimeRan", -1);
if (lastTimeRan >= minStartTime) {
// a day passed.
//also save the new 'lastTimeRan' in prefs
result = true;
prefs.edit().putLong("lastTimeRan", System.currentTimeMillis()).commit();
}
return result;
}
You can use AlarmManager to run a Method daily
Use Alarmmanager with BroadcastReceiver class.
Call your method which needs to be run everyday in the OnReceive method of receiver.
This method would be very easy.
Related
Android Periodic work will run periodically but i need to schedule a task within specific time. Suppose i want to run a task every day for 20 days only. I didn't find any way to do that.
How can i do that?
The offered API allows to cancel a work unconditionally:
If you no longer need your previously enqueued work to run, you can ask for it to be cancelled. Work can be cancelled by its name, id or by a tag associated with it.
But you can use your favorite storage to tack the number of days until they reach to 20 days. And every time the work is performed; i.e. when the doWork() callback gets called; you can increment the no. of days.
Here's an example of SharedPreference:
public static final String WORK_TAG = "WORK_TAG";
public static final String DAY_NO = "DAY_NO";
#androidx.annotation.NonNull
#Override
public Result doWork() {
SharedPreferences prefs = getApplicationContext().getSharedPreferences("prefs", MODE_PRIVATE);
int dayNo = prefs.getInt(DAY_NO, 1);
if (dayNo == 23) {
// cancel the work
WorkManager.getInstance(getApplicationContext()).cancelAllWorkByTag(WORK_TAG);
Log.d(TAG, "The periodic work has been stopped");
} else {
// Increment the number of days
dayNo++;
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("DAY_NO", dayNo);
editor.apply();
// Do your work here
}
return Result.success();
}
Make sure that you tag the work with the same tag when you initialize the workRequest:
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
MyWorkerclass.class, // Worker class
.......
.addTag(WORK_TAG)
.build();
Also notice that any other work with the same tag will be cancelled as well, so make sure it's a unique tag.
i try to schedule 2 tasks, the first need to done everyday - to check birthdays,
the second task need to be only if today is the first day of the month..
i tried to make 1 schedule that will done everyday at 8:00 am , and when its done to check if its the first day of month.
if its true make the method of the second task.
my problem is that the method starts every time that onCreate() done & its the first day t the month, so if i open the app 10 times at the 1/10/16 , the method will happen 10 times, instead of 1 time.
my code:
onCreate()
startTimers();
startTimers method:
private void startTimers() {
d = new Date();
d.setTime(System.currentTimeMillis());
d.setHours(8);
d.setMinutes(0);
d.setSeconds(0);
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
if(d.getDate() == 1){
// TODO: 19/10/2016 find good if that will make it work only 1 time per month..
saveSalariesBeforeStartNewMonth();
resetSumOfMinutes();
Log.d("TAG","Started new Month good luck!##!#");
}
checkBirthdays();
}
};
timer.schedule(timerTask,d.getTime(),1000*60*60*24);//every day at 8:00 at morining..
}
Thank for helpers.
Try to store a simple boolean to the SharedPreferences after successfully scheduling so that before you call startTimers() just check with the stored value. Sth like:
public void onCreate(){
if (!isScheduledAlready()) {
startTimers();
}
}
public boolean isScheduledAlready(){
SharedPreferences prefs = getPrefs().getPreferences();
return prefs.getBoolean("schedule_keys", false);
}
public void setSchedule(boolean scheduled) {
SharedPreferences prefs = getPrefs().getPreferences();
prefs.edit().putBoolean("schedule_keys", scheduled).apply();
}
Also I'm not sure if in your situation you might want to tweak the value when the month change? If then you can just need add more a bit more conditions I guess.
I have a requirement to get data from server by sending a call after specified interval like 5 minutes. So app would keep checking for new data after 5 minutes. It is just like gmail or facebook. Which automatically get new feeds or emails after some time and show in list. I am using service for this like following:
public class MessagesLoaderService extends Service {
// constant
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = null;
//********************************************************************************************************************************/
#Override
public IBinder onBind(Intent intent) {
return null;
}
//********************************************************************************************************************************/
#Override
public void onCreate() {
// cancel if already existed
if (mTimer != null)
{
mTimer.cancel();
}
else
{
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new MessageLoaderTask(), 0, Commons.TIME_INTERVAL_REFRESH_MESSAGES);
}
//********************************************************************************************************************************/
class MessageLoaderTask extends TimerTask
{
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable()
{
#Override
public void run() {
//Get Data from Server and store in local db
}
});
}
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Utils.showToast_msg(getApplicationContext(), "Service Destroyed");
}
//********************************************************************************************************************************/
}
//////////////////////////////////////////////////////////////////
Starting service from main activity MainActivity:
startService(new Intent(this, MessagesLoaderService.class));
I want service to run (send calls after 5 minutes) only when the app is running or in foreground/background. But the problem is that it keeps running even if I exit from the application. I want service to stop when Application is closed. Any solution for this?
Shouldn't you stop your timer in "OnDestroy" with mTimer.cancel() if you want it to stop ?
This method works when you enter the activity which actually queries the server. Call the method in onCreate. If value returned is true, then fetch data from server, if false, do whatever is in youf flow.
This Example below uses Singleton class. The current system time, plus five minutes is stored in singleton class variable, while local variable stores the current time. If current time exceeds the time of Singleton variable, then true is returned and it is time to call server.
SingletonClass app;
app = (SingletonClass ) getApplication();
public boolean serverQueryFrequency() {
boolean isTimeElapsed;
Calendar cal = Calendar.getInstance();
long time = cal.getTimeInMillis();
// If No Time is set, only then Set the Current time + 10 into
// application variable. This should fire only once, until 10 minutes
// have passed
if (app.getServerCallTime() == 0) {
Calendar cal2 = Calendar.getInstance();
// updating calendar to get current time + 10
cal2.add(Calendar.MINUTE, 5);
long timeTen = cal2.getTimeInMillis();
app.setServerCallTime(timeTen);
// returning true, to enable server check
return true;
}
// Log.v("******", "Current : " + time);
// Log.v("******", "App Time : " + app.getServerCallTime());
// Comparing current time with SeverCalltime which is set 10 minutes
// ahead. Code below fires conditionally as stated
if (time == app.getServerCallTime() || time > app.getServerCallTime()) {
isTimeElapsed = true;
// Once true fired from here, reset serverCallTime
app.setServerCallTime(0);
} else {
// 5 minutes have not passed
isTimeElapsed = false;
}
// returning the related value
return isTimeElapsed;
}
you can stop service by using this line
stopService(new Intent(this, MessagesLoaderService.class));
so your service get stopped
you need to identify in your app from where your exiting the app at that point you need to call above code also OS automatically kill the service in certain circumstances like low battery and so on but this is not good solution so you can stop it by above line in your exit point of application
I have learned when the app is closed the service get closed also because they are in a one thread, so the service should be on another thread in order fot it not to be closed, look into that and look into keeping the service alive with alarm manager here an example http://www.vogella.com/articles/AndroidServices/article.html this way your service won't be shown in notification.
lastly, after all the research I've done I'm coming to realize that the best use of a long running service is start foreground(); because it is made for that and the system actually deals with your service well.
when the user presses back button on the first page of your app..means they want out.
override the onbackpressed and put the stopService call there.
else..
use an exit button..give it an onclick and inside it put the stopService there
in my app next to the splash screen i need to show an activity called Tips Page. This activity to be shown once in a day. When the user opens the app again within 24 hrs it should not be shown.
First i tried to show based on the current date, when the first the activity shown i will store the current date in shared preference and next time when the app gets opened i will check whether the current date and date in shared preference are equal or not. If equal i will not show the activity if not i will show the activity.
But here there is a logic mistake, if the user opens the app first in midnight of 11 PM in a date, and again opens the app after t hour the Tips activity will be shown, but i need to show it after 24 hrs, how can it be done. pls help me in this ligic
I think you need such a flow, see this the implementation of Jason Hessley's Answer
SharedPreferences settings = getSharedPreferences("Preferences",
MODE_PRIVATE);
long timeFromPrefs = settings.getLong("time", System.currentTimeMillis());
final long TIME_DIFF = 24*60*60*1000;
if ((System.currentTimeMillis()-timeFromPrefs)>TIME_DIFF) {
// show Activity...........
Editor editor = settings.edit();
editor.putLong("time", System.currentTimeMillis());
editor.commit();
}
Android applications can run periodic timers using android.os.Handler & java.lang.Runnable classes. As simple example is shown below.
Key Points
1. Service classes extending android.app.Service should implement onBind, onCreate & onDestroy, life cycle methods.
2. periodicTask is an instance of Runnable implementation, that runs a Thread. Execution of run() will print the message "Awake".
3. mHandler is an instance of Handler, that is attached the periodicTask thread.
4. The Handler is informed to execute the thread every minute, by postDelayed.
5. When the service is destroyed, the periodicTask instance is removed from the Handler, by invoking removeCallbacks.
Sample Code
public class PeriodicTimerService extends Service {
private Handler mHandler = new Handler();
public static final int ONE_DAY = 86400000;
private Runnable periodicTask = new Runnable() {
public void run() {
Log.v("PeriodicTimerService","Awake");
mHandler.postDelayed(periodicTask, ONE_DAY );
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
mHandler.postDelayed(periodicTask, ONE_DAY );
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(periodicTask);
Toast.makeText(this, "Service onDestroy() ", Toast.LENGTH_LONG).show();
}
}
Save the last time the activity was started in a shared pref as you stated in your question. Then subtract the last time from the current time. If it is greater then 24 hours, show your tips.
Edit: here's the source on PasteBin. I feel like I might need to just redesign the entire Service.. :(
I'm the developer of RingPack. The basic idea is that there is a Service launched in the background that takes care of switching the ringtone out for the user. I'm having issues with losing my reference to an ArrayList within the Service. I think I may be misunderstanding how the lifecycle works. My intent was for it to be started whenever the user selects a pack from the Activity.
Intent i = new Intent(RingActivity.this, RingService.class);
i.putExtra(RingService.ACTION, RingService.PACK_SET);
i.putExtra(RingService.PASSED_PACK, currentPackId);
RingActivity.this.startService(i);
I tell the Service to set the Default Notification Tone to the first tone of the pack corresponding to "currentPackId".
When the user wants to turn off RingPack, the disabling is done like so:
Intent i = new Intent(RingActivity.this, RingService.class);
RingActivity.this.stopService(i);
Toast.makeText(RingActivity.this.getBaseContext(), RingActivity.this.getString(R.string.ringPackDisabled), Toast.LENGTH_SHORT).show();
So the Service's onCreate looks like so:
public void onCreate() {
db = new DbManager(this);
db.open();
vib = (Vibrator) getSystemService(VIBRATOR_SERVICE);
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_TICK);
registerReceiver(tReceiver, intentFilter);
timeTick = 0;
//figure out the widget's status
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
widgetEnabled = prefs.getBoolean(WIDGET_ALIVE, false);
//save the ringtone for playing for the widget
Uri u = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
r = RingtoneManager.getRingtone(this.getBaseContext(), u);
playAfterSet = false;
super.onCreate();}
Then it passes it off to onStartCommand, which returns START_NOT_STICKY (since I will be creating and destroying the Service manually), who passes it off to handleStart().
#Override private void handleStart(Intent intent) {
final Intent i = intent;
if (isSdOk()) {
int action = i.getIntExtra(ACTION, -1);
if (action != -1) {
if (action == PACK_SET) {
playAfterSet = true;
Thread packSetThread = new Thread() {
#Override
public void run() {
int passedPackId = i.getIntExtra(PASSED_PACK, -1);
//we were passed the id
if (passedPackId != -1) {
checkPrefs();
if (!enabled)
initControl(passedPackId);
else
setPack(passedPackId);
packSetHandler.sendEmptyMessage(0);
}
}
};
packSetThread.start();
}
else if (action == NEXT_TONE) {
checkPrefs();
swapTone();
}
else if (action == PLAY_TONE) {
playCurrentTone();
}
else if (action == WIDGET_STATUS) {
widgetEnabled = intent.getBooleanExtra(WIDGET_ALIVE, false);
if (toneName != null)
RingWidget.update(getBaseContext(), toneName);
}
}
}}
The isSdOk() method just checks if the SD card is mounted, since the ringtones are stored on it. initControl() just saves the user's default ringtone, so that we can give it back when they disable us. The setPack() method looks like this:
private void setPack(int packId) {
//save the current pack id in the prefs for restarting
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(RingService.this.getBaseContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(SAVED_PACKID, packId);
editor.commit();
//get the info we need to work with this pack
//it's path on the SD
//build the tones ArrayList to work from
grabPath(packId);
if (tones == null)
tones = new ArrayList<Integer>();
else
tones.clear();
mapTones(packId);
currIndex = 0;
setNotificationTone(tones.get(currIndex));}
The tones ArrayList is what I've been losing. This is where it is initialized. It holds the ids of all the enabled ringtones within a pack. The NullPointerException I've been seeing is in swapTone():
private void swapTone() {
//locked
if (lockPref)
return;
//shuffle on
else if (shufflePref) {
int randIndex = currIndex;
while (randIndex == currIndex)
randIndex = (int) Math.floor(Math.random() * tones.size());
currIndex = randIndex;
}
//shuffle off
else {
if (currIndex != (tones.size() - 1))
currIndex++;
else
currIndex = 0;
}
setNotificationTone(tones.get(currIndex));}
They way I intended it work is for swapTone() to never be called if setPack() hasn't already. Again, my users keep getting this error, but I can't reproduce it myself. Any help would be greatly appreciated. I apologize for the code wall, but I am very confused. Perhaps I'm not using the concept of a Service correctly?
Well, despite the "code wall", your listings are incomplete (e.g., you say your problem is with tones but never show where it is defined). I am going to take a guess that it is a data member of your Service.
In that case, it will be null if the service was stopped between PACK_SET and NEXT_TONE operations. This can easily occur, if Android stops the service because it has been running too long. Even with START_NOT_STICKY, if the next startService() call after Android stops the service is NEXT_TONE, not PACK_SET, you will have this problem.
IOW, your data model (the chosen ring pack) is not stored in a persistent location, but rather is held in RAM (tones). You have two choices:
Try to figure out a way that you do not need to be an always-running service, and load the tones out of a persistent store (e.g., database) as needed. This would be ideal, as you are chewing up a bunch of RAM while not delivering value for that RAM every microsecond. For example, you could use AlarmManager with an IntentService.
Use startForeground() to make it less likely that Android will stop your service. The trade-off is that you will need to place a Notification on the screen, so the user knows you are constantly running. You might make that Notification lead the user to the activity where they can configure or shut down the service.