Q: Android Dev - Single Background Timer in Service plus Action After - java

Hello,
I've done some research, but to no avail. Also my previous question didn't work as planned.
So here is exactly what I want to do:
1.) On my MainActivity, the User enters a Numerical value in an EditText.
2.) When they press an "OK" Button, it starts a Service to run a Timer for how long they entered.
3.) When the the Timer time runs out, the Service completes some additional Actions.
Questions:
1.) Can I simply use the Button to start the Service via an Intent, then in the Service put the code?
1b.) Can't figure out exactly how to get the User input from the EditText, from within Service.
2.) Can I run the "additional Actions" when the Timer runs out from WITHIN the Service?
2b.) Or, when the Timer is up, do I need to fire a BroadcastReceiver to complete the Actions?
3.) Do I need to add anything special such as Intent-Filters in my Manifest?
Basically, I'm having trouble figuring out what code goes where.
Currently I'm using a combination of Alarm Manager, PendingIntent, and Intent.
Any help would be greatly appreciated, as I've been trying to do this correctly for nearly a month.
I may be somewhat new to programming Android, but I'm eager to learn, so thank you in advance!
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void timerButtonClick(View view) {
EditText timerValue = (EditText) findViewById(R.id.timerValue);
assert timerValue != null;
int timerInt = Integer.parseInt(timerValue.getText().toString());
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent timerIntent = new Intent(this, TimerService.class);
PendingIntent timerPendingIntent = PendingIntent
.getService(this.getApplicationContext(), 234324243, timerIntent, 0);
alarmManager.set(AlarmManager.RTC,
System.currentTimeMillis() + (timerInt * 1000), timerPendingIntent);
finish();
}
}
NOTE: Keep in mind, I'm trying to put the Timer INSIDE my Service, NOT in my Main Activity.. So I assume much of this Code needs to be moved to my Service. But again, not sure exactly how to do this.
Thanks!

1.) Yes you can (see here).
1b.) No you can not. Service has no UI interactions at all, but you can create an activity for "after actions". (Edit: But You can pass EditText data from MainActivity to Service using Intent Extras) (see starting activity from service.)
2.) You can do almost anything or "additional Actions" when the Timer runs out from within the Service, without UI. (see services tutorial)
2b.) No, you dont need that.
3.) It depends on your timer logic, intent-filters are only needed when you are receiving any broadcasts. If you write timer logic by simply taking difference between time, there is no need, but if you do it with something like ACTION_TICK logic which triggers after each minute, you do need to declare intent filter. (see declare action tick intent filter)
You will also need to declare service in AndroidManifest.xml. If your java class name is MyBackgroundService, simply put this in AndroidManifest.xml:
<service android:name=".MyBackgroundService">
</service>
Do ask me if anything remains unclear.
Update:
I myself am in learning phase and one thing I learned is to look at the official docs first. There is a class CountDownTimer in android, which gives you countdown implementation.
use onFinish() of this class to perform whatever action you want to perform.
first argument of constructor is how long you want to run countdown, second is how much time you want for tick() event to occur.
start countdown by calling .start() method.
Update:
For putting extras and start service:
Intent serviceIntent = new Intent(this, MyBackgroundService.class);
String time = editText.getText().toString();
serviceIntent.putExtra("TIME_INTERVAL", time);
startService(serviceIntent);
No need for pending intent. You can start with this:
Create an activity that has : EditText and a Button.
Create onClick button listener code, which will first check the numeric input is correct or not (number format, negative value etc.).
If the input is valid you create an Intent for Service class, add data to intent using intent.putExtra("key","numericValue")
Start service (calling start service method) with intent.
In service class receive data from intent, then do calculation in time difference code.
In service, start a while loop that will check time difference at each loop, and when desired time is elapsed start an activity that will do your action after.
Please note that service class has a bit different implementation than activity class.
If your minimum time difference is in minutes, you can use action tick logic link above to see how you implement a service that can run your logic code every minute. In your case logic is also given in above links (time difference). Also I have provided how you retrieve data from intents.
Please try to dig into some code, then comeback here if you get stuck, I (and we the SO community) will surely help, if you are still stuck, I can only write whole codes on weekends, so you will have to try yourself until then.

Related

Android - System.exit(0) and restart activity and service

I'm making an Android app, and I need to completely restart the app in a moment. So, to do that, the only solution that has worked (and that I can remember) is to use System.exit(0). I have no idea why I have this code there (I can't remember why I tried it or where I saw it or if it was just an accident), but I know it's working, and I now that I was reviewing the code to apply this on a service, it didn't start the activity I wanted (an activity that would completely stop the app and restart the service from zero - or a service that would do the same thing, but the service isn't called, nor the activity, so I don't know if it works by calling a service or not - an activity i know it works, at least from another activity):
MainActivity.java (in the point I want to restart it)
Intent MainRestarter= new Intent();
MainRestarter.setClass(MainActivity.this, MainRestarter.class);
MainRestarter.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
MainRestarter.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(MainRestarter);
System.exit(0);
MainRestarter.java
Intent MainActivity = new Intent();
MainActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
MainActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
MainActivity.setClass(MainRestarter.this, MainActivity.class);
startActivity(MainActivity);
finish();
But I tested and it works too with:
MainActivity.java (in the point I want to restart it)
Intent MainActivity = new Intent();
MainActivity.setClass(MainActivity.this, MainActivity.class);
MainActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
MainActivity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(MainActivity);
System.exit(0);
From an answer on another thread (Difference between finish() and System.exit(0)):
"System.exit(0) - restarts the app with one fewer activity on the stack. So, if you called ActivityB from ActivityA, and System.exit(0) is called in ActivityB, then the application will be killed and started immediately with only one activity ActivityA" - the difference here is that (using the names there) I call the ActivityB from ActivityA, and then I call System.exit(0) on ActivityA, and it restarts with ActivityB. But this doesn't work with a Service no idea why...
I thought this should just stop the entire app, but after reading that answer, it got me confused. Btw, it only works if I the startActivity() is called, or the app will close completely. Can anyone explain me why this code works, and then explain why it doesn't work if I try the exact same code in a Service?
Thanks in advance!
EDIT: I know I can do this calling AlarmManager before System.exit(0), but I'd just like to know why that works, and if I can keep using it instead of AlarmManager (on the MainActivity, since on the service, for some reason the above doesn't work and I'd like also to know why if anyone knows), because I read it consumes more battery.

Sleep VS alarmManager.set VS alarmManager.setRepeat VS Handler

I'm looking for the most efficient way to perform a simple task. As a new android developer, I'm not too sure which of these strategies would be best for my app in terms of memory efficiency. I imagine some of these approaches might cause threading issues that I'm unaware of.
All three solutions are currently behaving as desired.
It's a really simple app. The idea is that my MainActivity starts an IntentService which will be running in the background after the app is opened. All the functionality I need right now is for a notification to be created at random intervals throughout the day(about an hour apart), indefinitely, until stopped by the user. The notification is made in a simple void method, displaying notification as text and vibrating the phone once.
My MainActivity starts the IntentService:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, NotificationService.class);
startService(intent);
}
}
My IntentService is very simple. It is called NotificationService, extends IntentService, and only overrides the onHandleIntent method. The constructor is empty except for super("Service"). The question comes in how to cause the notifications to pop up throughout the day in the background in the most efficient way. This in my implementation is done in the onHandleIntent method for all three methods.
Method One:
#Override
protected void onHandleIntent(Intent intent) {
makeNotification();
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pintent = PendingIntent.getService(
getApplicationContext(), 0, intent, 0);
alarm.cancel(pintent);
alarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 60000 * 60, pintent);
}
Note that with this, the user would have to uninstall the app to get the notifications to stop, which is not desirable (although I think I could just add a button or something that would cancel the intent)
Method Two:
protected void onHandleIntent(Intent intent) {
makeNotification();
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
PendingIntent pintent = PendingIntent.getService(
getApplicationContext(), 0, intent, 0);
alarm.cancel(pintent);
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 60*1000, 60000*60 ,pintent);
}
Method three:
#Override
protected void onHandleIntent(Intent intent) {
makeNotification();
try {
sleep(60000 * 60);
startService(intent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Can someone please help me with deciding the pros/cons of these three methods? Im not sure I understand which one would be ideal, although they all three give me proper functionality. As a side note, in my research I've noticed a "Handler" class which may also be useful here.
All the functionality I need right now is for a notification to be created at random intervals throughout the day(about an hour apart), indefinitely, until stopped by the user.
The AlarmManager, and potentially JobScheduler, are the only viable options.
The idea is that my MainActivity starts an IntentService which will be running in the background after the app is opened
Not really. An IntentService will only be running for as long as it takes to complete onHandleIntent() (including executing it N times if N commands are sent to it in rapid succession). An IntentService can run for a little while, but it is designed to handle some sort of business logic transaction. It is not designed to run indefinitely, and doing so would be bad for the user anyway.
Can someone please help me with deciding the pros/cons of these three methods?
Option three is unusable. First, it will not be reliable, as it stops working once your process is terminated. Second, it ties up a hunk of system RAM for no good reason, RAM that the user could put to more productive use. Only have a service running when it is actively delivering value to the user. Watching the clock tick is not actively delivering value to the user.
I've noticed a "Handler" class which may also be useful here
No, as it will suffer from the same problems as option three.
With regards to your two AlarmManager options, it boils down to whether you want regularly-occurring alarms (setRepeating()) or irregularly-occurring alarms (set()).
If you go the setRepeating() option, move the AlarmManager code out of the service and into the activity. There is no point — and definite costs — to calling setRepeating() on every alarm. After all, the point behind setRepeating() is that it knows to repeat, so you do not need to tell it on every occurrence "oh, hey, I know that I told you the last 1,337 times that you should repeat, but, um, don't forget to repeat, m'kay?".
With the set() option, since you are specifically not asking for the alarms to repeat, you would continue to schedule them in the service (or perhaps once from the activity, then the rest from the service), more or less as you have it.

invoke a method from activity in another

i know that this question was asked before but i had tried all the solution and get Error
i have two activity on android studio ...
the first called 'MainActivity' and contain a method ' deleteFromArrayList() '
the secound on called 'DeletButtonActivity' and contain a method ' delete(View v) '
i want to invoke 'deleteFromArrayList ()' wihtout creating another class or make the method static .... becouse i have an ArrayList inside deleteFromArrayList()
note : i send value of index i want to delete from array list using Intent ..the code in DeleteButtonActivity is
public void delete(View v) {
try {
Intent i = new Intent(DeleteButton.this, MainActivity.class);
i.putExtra("index", (int) spinner2.getSelectedItemId());
(new MainActivity()).DeletButtonActivity();
Toast.makeText(getApplicationContext(), "it was deleted", Toast.LENGTH_SHORT).show();
}
catch(Exception e){
Toast.makeText(getApplicationContext(), e+"", Toast.LENGTH_SHORT).show();
}
}
and the code in MainActivity
public void deleteFromArrayList (){
this.arrayList.remove(getIntent().getIntExtra("index",-1));
}
when i run the app i got an Error NullPointerException,,,
can anyone help me ..please
hope that i describe the problem very well
Activities in Android are no just a simple class but they also have a Lifecycle:
An activity has essentially four states:
If an activity is in the foreground of the screen (at the top of the
stack), it is active or running. If an activity has lost focus but is
still visible (that is, a new non-full-sized or transparent activity
has focus on top of your activity), it is paused.
A paused activity is
completely alive (it maintains all state and member information and
remains attached to the window manager), but can be killed by the
system in extreme low memory situations.
If an activity is completely
obscured by another activity, it is stopped. It still retains all
state and member information, however, it is no longer visible to the
user so its window is hidden and it will often be killed by the system
when memory is needed elsewhere.
If an activity is paused or stopped,
the system can drop the activity from memory by either asking it to
finish, or simply killing its process. When it is displayed again to
the user, it must be completely restarted and restored to its previous
state.
So the problem with your code is that when you want to access the array in a stopped activity, the instance you have been using before might not be alive anymore.
How to solve your problem
A very simple approach is to use parameter passing before you do the transition from one activity to the other, for this you'd pass your Array as an intent extra and then you "get the result back" when you finish the second activity by using onActivityResult() callback.
A second approach could be to use a Service that is something similar to an Activity but it has no UI and it has its own lifecycle. Being able to be alive even when you app it is not. Using a Service, you'll keep the Array inside the service and you'll communicate with the array to do the usual operations.
A third approach could be to use an EventBus. A very simple communication mechanism between Activities, Fragments, Threads, Services. There's a great talk titled Android Application Architecture on Android Dev Summit 2015 that uses EventBus as a communication mechanism and to implement a MVC architecture pattern on a REST Android App.
Back to your question. If you just need to 'share' an array between two activities, use the first approach. The second and third are just examples of different alternatives for the case you need a lot more than that.
You must not do this. There are mechanism to communicate between activities or fragments.
On can be, using startActivityForResult, this is Activity A calls Activity B, then in B you do something, and communicate the result back to Activity A.
You can have another workaround to what you want. If you can access the data in both of your activities, you can modified in ether one of them, when the activity starts, it will show the updated data.
Please first read well about an Activity here, and also provides more context of your question.

How to restrict the Android application to run only a certain time period?

I want to create an application that runs for a certain time interval.
[EDITED] By certain time interval, I mean if a user downloads an application from the play store. He can review all the features and functionality for a fixed period of time let say X hours only. After that, we can put any kind restriction (any UI/Navigation restriction so that user cannot review the features).
[The Problem]
what is the easiest as well as an efficient way of doing it? Like I don't think these solutions will work:
Calendar c = Calendar.getInstance();
int seconds = c.get(Calendar.SECOND);
Or
Time now = new Time();
now.setToNow();
What is the best way of putting restrictions (application side or server side as I have seen in some of the game application, where a synchronization is made between a server and application so that user cannot simply change the time and access the features).
So if you want to run your application for a certain period of time in the first run you need to keep a track if its a first run. So you might take set a preference variable so that it can tell you that if its a first run or not.
Now set a CountDownTimer and set it to run for an hour and when the timer is finished, close the Activity by calling finish() to it.
SharedPreferences pref = getSharedPreferences("ApplicationTag", Activity.MODE_PRIVATE);
if (pref.contains("FIRST_LAUNCH")){
finish(); // As you want, it can't be used if the application launches second time.
} else {
// Set the first launch flag to true.
pref.edit.putBoolean("FIRST_LAUNCH", true).commit();
// Start the count down timer
new CountDownTimer(3600000, 1000) {
public void onTick(long millisRemaining) {
// Do nothing
}
public void onFinish() {
// Finish the Activity
finish();
}
}.start();
So you might thinking that what if I switch between Activities. So in that case, you make create a BaseActivity class which will be extended by other Activities in your application. Place the CountDownTimer code there and take a reference of the Context you're in then call context.finish() when the timer is finished.
So in case of you don't want to limit the user for first launch, you need to save the time somehow in your application. When the Activity is finished, you'll get the callback in onDestroy function. So override the onDestroy function and set some preference again with the remaining time in mili seconds. So that you can initialize the timer again when the application starts.
Hope that helps!
Try setting an Alarm for firing any activity after any amount of time you want. Like following:
calendar = Calendar.getInstance();
Intent intent = new Intent(this, ActivityYouWantToStart.class);
PendingIntent pIntent = PendingIntent.getBroadcast(this, 101, intent, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
calendar.add(Calendar.Hour,1);
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pIntent);
Call this code when user launches your code for first time and inside ActivityYouWantToStart.class do whatever you want to do after such amount of time.

Run service every 30 minutes without using wakelocks

tl;dr: my app doesn't update my SharedPreferences with the last value from the server because sometimes the phone is sleeping.
Explanation:
I'm new in this android world, and I've been working on my first "real" application but I'm having a few issues right know...
Here's how I need my application to work:
Check every 30 minutes for new data (data is pulled from a json file on my server)
If the data is different from the stored on the phone, then store the new data and send a notification to the user. (I'm using SharedPreferences for the "storage")
Here's what I used to try to achieve that:
MainActivity.java / Activity (my main activity, duh')
cargarJson.java / AsyncTask (a class that pulls json data and returns a jsonobject). Cargar = Load (in spanish)
DolarService.java / IntentService (The service creates a loadJson object and execute it, then sends the notification).
AlarmReceiver.java / BroadcastReceiver (It's a receiver that has an AlarmManager that executes my DolarService every 30 minutes and runs everytime the phone boot up and when the user runs the app for the first time).
I kind of managed to do it, but the problem is that I don't want to use wakelocks because it drains the battery really fast.
My AlarmManager doesn't use wakelocks so when it sends the notification every 30 minutes it contains the last value stored in the SharedPreferences when the phone was "awake" and not the new data from the server.
Here's my source:
https://gist.github.com/anonymous/d5cccf5ba331f041630e
My question: how do I keep my up-to-date data in my SharedPreferences (updating it every 30 minutes) without using wakelocks. Also, is something wrong with my approach to do this app ?
Thank you in advance and sorry for my poor english, I tried my best to explain my situation!
It doesn't look like you're using wake locks. You can make sure of this, however, by removing your <uses-permission android:name="android.permission.WAKE_LOCK" /> from your manifest, and then you'll know for certain that your application isn't acquiring a wakelock, because it doesn't have permission.
Edit:
You're using your IntentService incorrectly. See the documentation on how to implement an IntentService. An IntentService already creates it's own worker thread, similar to an AsyncTask, so executing an AsyncTask within an intent service is unnecessary in your case. Instead, you should pull out everything in your AsyncTask and implement it in your IntentService's onHandleIntent(), rather than it's onCreate() and onDestroy() methods.
The other option would be to use a normal Service, and stop it in your AsyncTask's onPostExecute() method.
Also, this is a little off topic, but when passing a context to another object, you should use a WeakReference<T>:
WeakReference<Context> context;
public cargarJson(String jsonUrl, Context context) {
this.jsonUrl = jsonUrl;
this.context = new WeakReference<Context>(context);
}
All things are fine. But its good if you use a backgorund service for your server operations and start this service through the AlarmManager followed by PendingIntent in every 30 minutes.

Categories

Resources