android service stops when main activity is destroyed - java

I am making an app that gives the user a notification when it is time for a monster egg to be hatched again. Up to 10 eggs can be hatched per day every 5 minutes. I thought I'd make a service that keeps a track of how much time has passed, but every time MainActivity closes on the emulator the service stops and calls onDestroy(). I made a test service to see if I could get the service to display log messages, or do something when onDestroy() is called. I was able to get the service to run a thread in onDestroy(), but obviously this is dangerous if I were to implement it.
I was also reading around the site and notice people recommend either Handler or Alarm Manager. Should I use these instead of service? And could someone also explain why my service stops when MainActivity is destroyed? Also would it be recommended to retrieve/store data from app preferences within this service or whatever class I end up using so that the service and MainActivity can talk to each other? Like for example a seed based on whenever the timer is up so that MainActivity can create an egg from the seed whenever it is started?
(edit)oops almost forgot: I also need it so that notifications appear whenever an egg is ready to hatch and whenever another batch of eggs is ready for the day. Whenever the user starts the app, the app should also display how long is left for another egg or another batch if the user has already used up their eggs for the day. Figured this context was important in determining whether I should use a service, alarm manager, or handler.
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
public class egg_notifications extends Service {
public static int time = -1;
public egg_notifications() {
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
AsyncTask datatask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
for(int c=0;c<300;c++){
Log.i("d","Time is "+c);
try {
Thread.sleep(1000);
} catch (Exception e) { }
}
return null;
}
}.execute();
return Service.START_STICKY;
}
#Override
public void onDestroy() {
Log.i("d","Service onDestroy");
AsyncTask datatask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
for(int c=0;c<300;c++){
Log.i("d","Time is "+c);
try {
Thread.sleep(1000);
} catch (Exception e) { }
}
return null;
}
}.execute();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}

Services end after 2 minutes in modern Android. If you just need a 5 minute timer, use an Alarm and AlarmManager to set one.

Related

show a custom message every 10 second from background service

I want to implement a feature in my application to show a custom message after every 10-20 second also when app is not started and phone is in wake up state...
I am sharing you a screenshot and a refer app which has this functionality in their app I want same functionality in my app.
App name is Auto- Athkar for muslims
An android toast could work in a while loop?
Your have to register when the app is pushed minimised which is normally done by
public void onPause () {
}
You'd have to start a service in your Application class to run it constantly. Even if user force closes then it should run.
Create your own service class :
public class Servicey extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int begin(Intent intent, int flags, int beginId) {
// do that shiny stuff with toasts
return super.begin(intent, flags, beginId);
}
Then start your service on the onCreate() of your activity
startService(new Intent(this, Servicey.class));

How to display a toast message in only one activity?

In an application I am developing I have some code that attempts to submit information to the internet. If the connection can not be made, I pop up a toast message instructing the user to check the network connection.
Toast.makeText(getApplicationContext(), "Check network connection.", Toast.LENGTH_SHORT).show();
The problem I have is the toast message comes up no matter what the user is looking at! Even if the user is in a different app and my app is running in the background! This is not the desired behavior as I send a notification to the user if network activity fails. I only want the toast message to appear if the user is in the activity that is generating the network activity. Is there a way to do this?
If this is not possible my idea was to just put some kind of visual element in my activity - rather than display a toast message.
Thank You!
You can use a boolean class member in order to keep track of activity state changes.
public class YourClass extends Activity {
private boolean mIsResumed = false;
#Override
public void onResume() {
super.onResume();
mIsResumed = true;
}
#Override
public void onPause() {
super.onPause();
mIsResumed = false;
}
public boolean isResumed() {
return mIsResumed;
}
}
Then you can use something like this:
if (isResumed()) {
//show Toast
}
Use a dynamic BroadcastReceiver. Your background service will broadcast an Intent when something happens. All of your app's activities will register a dynamic BroadcastReceiver which will listen for these events. When such event occurs it will show a toast. When none of your activities are running nothing will happen.
Inside your service
public static final ACTION_SOMETHING = BuildConfig.APPLICATION_ID + ".ACTION_SOMETHING";
public void doSomething() {
// ...
// Show toast if app is running. Or let the app react however you please.
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_SOMETHING));
// ...
}
Of course you can put additional information in the Intent as extras and access them in the BroadcastReceiver.
Inside your activities
private final IntentFilter onSomethingIntentFilter = new IntentFilter(MyService.ACTION_SOMETHING);
private final BroadcastReceiver onSomething = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// This check seems redundant but it's not. Google it.
if (MyService.ACTION_SOMETHING.equals(intent.getAction()) {
// Show toast here.
}
}
};
public void onResume() {
super.onResume();
// Start listening for events when activity is in foreground.
LocalBroadcastManager.getInstance(this).registerReceiver(onSomething, onSomethingIntentFilter);
}
public void onPause() {
super.onPause();
// Stop listening as soon as activity leaves foreground.
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(onSomething);
} catch (IllegalArgumentException ex) {}
}
You may want to pull this code to a common activity parent, a BaseActivity, so you don't repeat yourself.
This is a common case of Provider-Subscriber pattern. Another implementation would be an EventBus.
Keeping it simple, try adding a boolean flag in Activity and set its value as true in onResume & false in onPause. Then display the toast if the boolean flag is true.

how can you stop a service outside of an activity?

I'm making a litle game in android studio where I want background music to play when the user is interacting with the application (and have it turned on in the settings). For this I used a service for playing backgroundmusic. As you can see below
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
public class BackgroundMusicService extends Service {
MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
player = MediaPlayer.create(this, R.raw.backgroundmusic);
player.setLooping(true); // Set looping
}
public int onStartCommand(Intent intent, int flags, int startId) {
player.start();
return 1;
}
#Override
public void onDestroy() {
player.stop();
player.release();
}
#Override
public void onLowMemory() {
}
}
I want my backgroundmusic to play on all my activities, but stop when the user leaves the application, as it is impossible to detect a menu button press or a home button press in android. I tried to solve it like this.
import java.util.Timer;
import java.util.TimerTask;
public class LeaveAppDetector extends BackgroundMusicService{
private boolean Deactivated;
private int Time = 700;
private int wait = 0;
private Timer timer = new Timer();
public void Activate() {
Deactivated = false;
timer.schedule(new TimerTask() {
#Override
public void run() {
if (wait >= 1) {
if (!getDeactivate()) {
//app has been closed
StopPlaying();
StopTimer();
} else {StopTimer();} //app has not been closed
}
wait++;
}
}, Time);
}
public void Deactivate() { //call at the start of each activity
Deactivated = true;
}
private boolean getDeactivate() {
return Deactivated;
}
private void StopTimer() {
if (timer != null) {
timer.cancel();
timer.purge();
}
}
}
The idea is that when an activity starts, it calls Deactivate(); and when it closes, it calls Activate(); so that the value of Activated is updated after a short period of time. I added the following method to my BackgrondMusicService class in order to be able to turn it off remotely
public void StopPlaying() {
player.stop();
player.release();
}
Now the problem, it gives me the error that the reference to the mediaplayers in the method I just showed, is one referring to a null object, and I don't know why or why it won't work. Can someone help?
You need to use a Bound Service like this answer suggest:
https://stackoverflow.com/a/2660696/3742122
If you only want the service running while activities are using it, consider getting rid of startService(). Instead, use bindService() in the onStart() methods of the activities that need the service, and call unbindService() in their corresponding onStop() methods. You can use BIND_AUTO_CREATE to have the service be lazy-started when needed, and Android will automatically stop the service after all connections have been unbound.

If an user is using app, then how to stop showing notification?

I am designing an android app which uses notification.
Before this, I was using a full screen activity, so if a notification came, in full view I didn't get any alert.
Now I am using a blank activity with notifications enabled.
I don't want to show notifications when I am already inside the app (like skype).
Or else, I want to cancel them immediately once flashed.
How to achieve this?
Thank you in advance.
You can define a superclass for all of your activities and track the state of the app. If all activities are in stopped state - app in the background, otherwise - in the foreground. In onStart() and onStop() methods of your super activity you can increment and decrement the number of visible activites.
public class SuperActivity extends Activity {
private static int sVisibleActivitiesCount;
#Override
public void onStart(){
super.onStart();
sVisibleActivitiesCount++;
}
#Override
public void onStop(){
super.onStart();
sVisibleActivitiesCount--;
}
public static boolean isAppInForeground() {
return sVisibleActivitiesCount > 0;
}
}
Now you can check somewhere for an application status and not create notification if SuperActivity.isAppInForeground returns true.
The second approach is to use ActivityLifecycleCallbacks (min API 14) for monitoring activities lifecycle and track application state in a single place without having a super class for all activities. So I would rather use this approach if your app has minSdkVersion="14".
You can try to get the running processes list and check if the one in foreground is your app.
private boolean isAppInForeground() {
ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> mRunningProcesses = mActivityManager
.getRunningAppProcesses();
Iterator<RunningAppProcessInfo> i = mRunningProcesses.iterator();
while (i.hasNext()) {
RunningAppProcessInfo runningAppProcessInfo = i.next();
if (runningAppProcessInfo.uid == getApplicationInfo().uid && runningAppProcessInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
{
return true;
}
}
return false;
}

android Thread and Service

I am using below code.
import android.app.Activity;
import android.os.Bundle;
import android.provider.ContactsContract.Data;
import android.util.Log;
public class ActivityDemoActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Thread(new Runnable() {
#Override
public void run() {
int i=0;
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i("DATA", "Data.CONTENT_TYPE......"+(i++));
}
}
}).start();
}
#Override
public void onBackPressed(){
finish();
}
}
When I press Back button of device still thread is working in background.
My questions are...
when thread will stop?
Then why we required services in android?
Thank You.
Answers:
1 - it will stop after 100 milliseconds
2 - you need something to work in the background like a service that wakes up and
performs a function without there being a user to initiate it. Or you want to have
a progressDialog that tells the user some work is happening rather than let the user
assume the UI is frozen. Without the background service, your UI is left with an app
that doesn't respond while the work is happening.
Services are basically used for performing long-running application on the background.If you are using any network operations or playing musing or something like that, services are very much helpful..

Categories

Resources