I think i have coded myself into a bit of a corner here. but I will try to explain my issue as best as I can. basically I am building an application on android that is supposed to be a copy of the alarm app on the phone. I have an object that represents the alarm. it includes time, and days as booleans etc. i persist these objects by serializing them and saving them to a file. then, on boot, I have a broadcastreciever which starts a boot service. basically the bootservice has a loop that iterates over my list of alarms. iam trying to call a method on each alarm object called "setSysAlarm()", which is supposed to recreate each android system alarm at the saved time. at present, the "setSystemAlarm" method is only creating a toast for testing purposes. BUT this is causing the application to crash. there is obviously a flaw in my design and I think that trying to use the app context is causing the crash. My thinking is that I should possibly create all alarms via the service through the GUI when is running, aswell as recreating the alarms on boot? therefore alarms creation can be done regardless of wheather the app is running, also the alarms will be created in one place ? below is my boot service code which is executed on boot.
public class BootService extends Service {
private Thread setallarams;
private file_acces_int fileaccess;
private ArrayList<alarm_entity> alarmlst;
private Runnable setalarmsrunnable = new Runnable() {
#Override
public void run()
{
for(alarm_entity alarm : alarmlst)
{
alarm.setSystemAlarm();
}
}
};
#Override
public void onCreate()
{
fileaccess = new file_access_model(getApplicationContext());
alarmlst = fileaccess.readFromFile();
setallarams = new Thread(setalarmsrunnable);
cont = this;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
setallarams.start();
try {
setallarams.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
stopSelf();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
and here is the setSystemAlarm() method from my alarm_entity class. basically this is meant to create a toast on boot but at present the app is crashing
public void setSystemAlarm()
{
Toast.makeText(cont, "hi there", Toast.LENGTH_SHORT);
}
if someone could help me out here id appreciate it. the methods i was using to get the context were
1. pass it in from the bootService. doesnt seem doable to me?
2. cretaing an instance on of Applicationin the constuctor of each alarm_entity and using that as the context. this also seems pretty stupid to me. lol
anyway thanks in advance and sorry for the long winded question!
Anyway, we´ve discussed too much for how You get the Logcat output :) . The basic question is, why You get this error. Maybe this is not the full answer, but I need to show some code. You are initializing Your context inside onCreate() of the service:
#Override
public void onCreate()
{
fileaccess = new file_access_model(getApplicationContext());
alarmlst = fileaccess.readFromFile();
setallarams = new Thread(setalarmsrunnable);
cont = this;
}
But like described in the API:
Do not call this method directly.
I don´t know if this is the reason for Your crash, we have no Logcat, it could be any other reason. But it´s recommended to initialize in onStartCommand(), so put Your initializations inside onStartComand():
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
fileaccess = new file_access_model(getApplicationContext());
alarmlst = fileaccess.readFromFile();
setallarams = new Thread(setalarmsrunnable);
setallarams.start();
.
.
.
The other thing is, I can´t see initializing alarm_entity class, maybe I am blind (?), but I can´t see nowhere that You pass a context to this class. For example, if You are initializing this class, it must be something like this inside Your onStartCommand();
mAlarm_entity = new alarm_entity(this);
Because Service holds context, then simply call this. Delete the onCreate() and then You don´t need to initialize a context, because the service has it allready.
Add this permission to your manifest
> android.permission.RECEIVE_BOOT_COMPLETED
Related
I need to write three items of data in Firebase Realtime Database in case the user kill the app
from recent list while it's still running; I implemented a service in order to
update the database when onTaskRemoved is called.
In the manifest the service is declared with the option android:stopWithTask="false"
Here is the service
public class ServiceAppMonitoring extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
SharedPreferences mSettings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
//Get some datas from Shared Preferences...
String path1 = "first/node/path";
mDatabase.getReference(path1).setValue(false);
if (condition) {
// Compose array of datas
List<Object> data2 = Arrays.asList(new Object[]{ ... });
String path2 = "second/node/path";
mDatabase.getReference(path2).setValue(data2);
// Compose array of datas
List<Object> data3 = Arrays.asList(new Object[]{ ... });
String path3 = "third/node/path";
mDatabase.getReference(path3).setValue(data3);
stopSelf();
} else {
stopSelf();
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) { return null; }
}
Strangely only the first instruction is successful, the other two seem to be ignored... at least no data is written into database.
Further I've noticed another "unusual" behaviour, if I arrange all the DatabaseReferences in the
following way:
mDatabase.getReference("first").child("node").child("path").setValue(false);
no one of the instructions end up writing into database, to get (at least) the first one working I've to arrange this way:
mDatabase.getReference("first/node/path").setValue(false);
Can anybody kindly help me to understand why this happens?
Thanks
This is almost certainly because Firebase operations are asynchronous, and return immediately before the writes are complete. onTaskRemved is going to return before either of the database writes fully finish.
I'm guessing that your app process is going to die very soon, if not immediately, after onTaskRemved returns. This means that your database writes might not finish. Android doesn't know that these writes are pending, and it's not going to wait for them.
Since you don't have way from your service to tell Android to wait for these writes, you will have to schedule them for later. I suggest looking into using WorkManager to schedule the writes to happen in the background, whenever Android allows it. It might not be immediate, but WorkManager will make sure that any scheduled tasks will eventually complete.
Hey based on your answer I updated a small thing on database from onTaskRemoved like this
I already initialized the DatabaseReference in the onCreate method
DatabaseReference temp = FirebaseDatabase.getInstance.getReference().child("temp");
and in onTaskRemoved
temp.setValue(true);
this is getting executed and I added a onchange listener in onCreate method to listen for this values change and it worked like a charm. If you don't understand anything feel free to ask and let me know how you got over this problem:)
EDIT:
This is not working in all devices...
EDIT AGAIN: I simply used on Destroy method in my service and killed the service after completing the task and is working for now...
EDIT AGAIN AND AGAIN: OnDestroy is not working in android 6 or below I guess. I tested in Android 6 and it didnt work.
I am currently resuming a project I had been working on, and starting from scratch to recreate it.
However, upon creating a Service class, I noticed something - in my old project, a method inside the Service called onStartCommand contains all of the code that needs to be fired, whereas in my new project when I create a Service class, this method is nowhere to be found.
- Do I need to manually ADD this "onStartCommand" method to contain my service code?
- If not, where exactly would my code go? It seems in my "old" project's code, I completely comment-block public TimerService, and pass null into IBinder, and create onStartCommand etc instead.. and I can't quite figure out why.
- While i'm here, can someone please double-check my CountdownTimer code below? and if it's correct, should I be putting it inside of a Thread?
When I create a new Service Class, it looks like this:
public class TimerService extends Service {
public TimerService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
However in my old Project, my Service class looks like this:
public class TimerService extends Service {
/*
public TimerService() {
}
*/
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
intent.getStringExtra("TIMER_VALUE");
String string_timerValue;
string_timerValue = intent.getStringExtra("TIMER_VALUE");
long long_timerValue;
long_timerValue = Long.parseLong(String.valueOf(string_timerValue));
// I DO NOT WANT ANY TICK VALUE, SO GIVE IT FULL TIMER VALUE
long long_tickValue;
long_tickValue = Long.parseLong(String.valueOf(string_timerValue));
new CountDownTimer(long_timerValue, long_tickValue) {
public void onTick(long millisUntilFinished) {
// DO NOTHING
}
public void onFinish() {
Toast.makeText(TimerService.this, "TIMES UP", Toast.LENGTH_LONG).show();
stopService(intent);
}
}.start();
return START_STICKY;
// END OF onStartCommand
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
// END OF ENTIRE SERVICE CLASS
}
THANK YOU!!
Do I need to manually ADD this "onStartCommand" method to contain my service code?
Yes.
can someone please double-check my CountdownTimer code below?
Only create a service when one is absolutely necessary. It is unclear why this service is necessary.
Beyond that:
Use stopSelf(), not stopService(), to stop a service from inside that service.
Examining Intent extras and using START_STICKY is not a good combination. START_STICKY says "if you terminate my process to free up system RAM, please restart my service when possible, but pass null for the Intent". That will cause your service to crash with a NullPointerException.
I'm trying to periodically check with a web service if a new item has been added to a database. If there's a new item a listview that the user sees should be updated.
I'm using PCL and I have accomplish it creating a new Task with a timer inside. But this only works if the app is open. I want to do the same when the app is closed so the user gets a notification when a new item is added remotely.
I've been doing some research and I found andoid services, the info said that the service will continue, regardless of the app state, until you tell it to stop. But i haven't found many examples in how to implement it.
Here's the code that I had that works only when the app is opened:
Task.Run(() =>
{
Device.StartTimer(TimeSpan.FromSeconds(secs), checkUpdates);
});
bool checkUpdates()
{
if (isOnline)
{
var lastUp= Application.Current.Properties["lastUpdate"] as string;
//returns true if a new item is added
if (service.newItem(DateTime.Parse(lastUp)))
{
var itm = service.getNewItem(DateTime.Parse(lastUp));
Device.BeginInvokeOnMainThread(() =>
{
notification.ShowNotification(itm.Title, 1000);
listView.Insert(0, itm);
}
});
}
App.Current.Properties["lastUpdate"] = DateTime.Now.ToString();
}
return true;
}
I'm trying to do the same with an Android service using dependency services, here's what I've got so far:
public interface IService
{
void Start();
}
[Service]
public class DependentService : Service, IService
{
public void Start()
{
var intent = new Intent(Android.App.Application.Context, typeof(DependentService));
Android.App.Application.Context.StartService(intent);
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
// From shared code or in your PCL
return StartCommandResult.NotSticky;
}
}
The problem is that I don't know how to implement the code that I had in the timer to the service, can someone please help?
For what you want to achieve, you should probably look at the AlarmManager
Have a look at this StackOverflow post, where there's an example for one and maybe this one as well. The second one is Java but it might give you an idea of what you might deal with
EDIT:
You might also want to have a look at these Xamarin.Android documents around Services and BroadcastReceivers, to get better understanding with what you're dealing
I will do something when service stopped in my app
for example:
i have a countdown code in my service,and then i will when that countdown stopped random button set visible.
i don't know how i can do something by service,i can't set button in service's body so how i can set it?and where i should do it?
in this following code i wrote my countdown in //your code line but i don't know how i can set button visible when count down stopped
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
strong text // your code
return Service.START_FLAG_REDELIVERY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
What you are trying to do is communicate between a running service and an Activity. There are multiple ways to do this. The most easiest would be to pass an event from the service and catch that event in the activity. You can implement it from scratch or use an Event Bus. I would recommend using this library EventBus. Using this library you can pass an object containing some info (about what happened in the service) to the activity and based on that you can perform the action you need. I'm not posting any code. Please try doing it yourself, it will be a good learning experience.
I have a DialogFragment that can be launched from anywhere, let’s call it UploadDialogFragment. This fragment allows the user to accomplish two related tasks:
Upload an image (can take up to 1min)
Upload a JSON object with some text and a reference to the saved image
This two tasks need to be accomplished in sequence - you can’t do 2. without having completed 1.. So what really happens is:
I start uploading the image (1.)
Meanwhile, the user writes the text and adds other info
When all is ready, dismiss the dialog and start the second task (2.).
I used to do this with background tasks, but now I’d like to switch to a Service: the whole operation should be completed even if, after dismissing, I force quit the app.
Current design
In my experience I have always used IntentService, so I am a complete newbie. The current flawed design I am moving forward is something like:
public class UploadService extends Service {
private final Binder binder = new Binder();
public class Binder extends android.os.Binder {
UploadService getService() {
return UploadService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public void completeFirstTask() {
...
}
public void completeSecondTask() {
// wait for first task to complete if necessary...
...
stopSelf();
}
}
And here’s my UploadDialogFragment:
public class UploadDialogFragment extends AppCompatDialogFragment implements
ServiceConnection {
private UploadService uploadService;
private boolean boundService;
#Override
public void onServiceDisconnected(ComponentName name) {
uploadService = null;
boundService = false;
}
private void bindService() {
Intent i = new Intent(getActivity().getApplicationContext(), UploadService.class);
getActivity().getApplicationContext().bindService(i, this, Context.BIND_AUTO_CREATE);
boundService = true;
}
private void unbindService() {
if (boundService) {
getActivity().unbindService(this);
boundService = false;
}
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
uploadService = ((UploadService.Binder) service).getService();
uploadService.completeFirstTask();
}
// THEN, LATER:
// OnClick of a button, I call uploadService.completeSecondTask();
// and this.dismiss();
}
This is deeply flawed right now.
I need to reliably unbind() when the dialog fragment is closed/dismissed/recreating itself, otherwise I am going to leak it because of the ServiceConnection (right?). I don’t know when to do it?. onDismiss, onDestroyView, onSaveInstanceState ... I have tried many options but I often end up with a IllegalArgumentException saying that the service connection is not registered.
The service might never reach the completeSecondTask() part, and so no one is going to stop it, leaking it for no reason. I should probably call stopService() somewhere, but where? These are different scenarios:
I force-quit the app / recreate the fragment after a completeSecondTask() call: the Service should keep going until it ends.
I recreate the fragment without having called completeSecondTask() : the Service should keep going until it ends. (There’s proper logic inside my fragment to handle this)
I force-quit the app without having called completeSecondTask() : the Service should stop.
Questions
Now, you might see this as two questions: how to handle unbind(), and how to handle stopService().
However, because I am finding so hard to set up this little task, I am thinking that this is deeply flawed and I should use a totally different approach. I hope you can shed some light on this for me.