Need an explanation of my app's behavior - android

I've created a service that counts in the background. I'm starting the service in my MainActivity's onCreate().
Whenever i restart my app, so does my service class by setting the timer to -1. However, when I switch the orientation of my phone the timer does not reset.
As far is I know, killing an app calls the onDestroy() method and starting it up again afterwards calls the onCreate(). I've read that changing orientation calls the same two methods, so why is it that the two actions result in different behaviors, and is there any way to prevent it? My code expects the timer to reset when the app is killed, so when the orientation is changed, my timer is way off.
Here is the code of my service class:
ublic class CounterService extends Service {
private Handler handler;
private int time = -1;
private boolean isActive;
private Intent timeBroadcaster;
private Runnable counter;
private Thread serviceCounter;
private SharedPreferences.Editor editor;
public static final String EXTRA_TIME = "TIME";
#Override
public void onCreate(){
super.onCreate();
handler = new Handler();
timeBroadcaster = new Intent();
timeBroadcaster.setAction(Intent.ACTION_SEND);
SharedPreferences prefs = getSharedPreferences("SessionLogger_Preferences", MODE_PRIVATE);
editor = prefs.edit();
counter = new Runnable() {
#Override
public void run() {
isActive = ((PowerManager) getSystemService(Context.POWER_SERVICE)).isInteractive();
if (isActive) {
handler.postDelayed(this, 1000);
time += 1;
Log.i("TIME", String.valueOf(time));
} else {
editor.clear();
editor.commit();
if (time > 5) {
//log
}
time = 0;
handler.postDelayed(this, 1000);
}
timeBroadcaster.putExtra(EXTRA_TIME, time);
sendBroadcast(timeBroadcaster);
}
};
serviceCounter = new Thread(counter);
serviceCounter.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy(){
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}

Rotation doesn't kill the app. It kills the Activity. THe application still runs, but the Activity is restarted. Since the Application still runs, any Services in the app are still running, and Services are not restarted. In fact that's the entire point of a Service- to remain running even when Activities are killed.

Related

Android: Service is killed and restarted after a while

I know that is a well known subject, but I have tried lot of things. I have an simple application, dedicated to a specific user, application has an mainActivity which is displaying some status on screen and it's starting two services, one is making request from a server (at every 5 minutes) and one which is sending sms and replay to server (at every ten minutes).
The application is running on a Samsung pocket 2 with Android 4.4.2, this device is used only for this application. While the device is connected to ADB the services are working just fine, but if I disconnect the phone and let it running normally, the services are killed repeatable and restarted after a while. The messaged are send with very much delay. I would be thankful for any suggestions.
Here is my code:
Main activity:
public class MainActivity extends Activity {
private TextView _internet;
private TextView _signal;
private TextView _server;
private BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
IntentFilter intentFilter = new IntentFilter(Constants.SS);
receiverWorker();
registerReceiver(receiver, intentFilter);
startService(new Intent(this, RefreshDBService.class));
startService(new Intent(this, SmsService.class));
}
private void receiverWorker() {
receiver = new BroadcastReceiver() {
public void onReceive(Context arg0, Intent arg1) {
checkState();
}};
}
public void refreshButonClicked(View v) {
checkState();
}`
Here is my first service:
public class RefreshDBService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
if(Checks.checkInternetConnection(getApplicationContext())){
if(ServerOperations.isServerAvailable(getApplicationContext())){
String inputData = ServerOperations.makeRequest(Constants.GET_DATA_ROUTE, ServerOperations.getMessagesFromServer(getApplicationContext()));
ArrayList<DataSmsObj> dataFromServer=null;
if(inputData!=null && !inputData.isEmpty()){
dataFromServer = ServerOperations.fromJsonToObjects(inputData);
if(dataFromServer.size()>0){
_dataSource.open();
_dataSource.insertDataFromServer(dataFromServer);
_dataSource.close();
}
}
System.out.println("check server for messages in pending status, received -> "+ dataFromServer.size());
}else{
System.out.println("no server");
sentErrorToUI(Constants.NO_SERVER);
}
}else{
System.out.println("no internet");
sentErrorToUI(Constants.NO_INTERNET);
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE/2, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
}
public IBinder onBind(Intent intent) {
return null;
}
private void sentErrorToUI(String message){
Intent intent = new Intent(Constants.SS);
intent.putExtra(Constants.SS, message);
System.out.println("trimit" +message);
sendBroadcast(intent);
}
}
And this is the second one:
public class SmsService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
sendFeedbackToServer();
List<DataSmsObj> dataToSent = new ArrayList<DataSmsObj>();
_dataSource.open();
dataToSent = _dataSource.getDataToSent();
_dataSource.close();
System.out.println("messages to sent: "+ dataToSent.size());
for (int i = 0; i < dataToSent.size(); i++) {
//here the messages are send, the code is to long to put it here, but if is need i can do it afterwards
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
public IBinder onBind(Intent intent) {
return null;
}
If you are using a background Service with a scheduled task, it could be killed by the system. The only way to prevent the killing is a foreground Service. Quoting the documentation:
A foreground service is a service that the user is actively aware of and is not a candidate for the system to kill when low on memory.
You have to call the method startForeground() inside your Service using a Notification to show it. For further information you can check: https://developer.android.com/guide/components/services.html#Foreground
By the way, I recommend you to use the new JobScheduler api above api 21.
https://developer.android.com/reference/android/app/job/JobScheduler.html
Android kills service based on priority stack.
Android: keeping a background service alive (preventing process death)
What is START_STICKY,START_NOT_STICKY and START_REDELIVER_INTENT Service
Above links might help you.
Your devices will sleeps if it is unplugged from computer . So, the solutions :
Use startForeground method to prevent service to be killed and/or use AlarmManager in order to charge event.
It is possible to use start_stiky flag but it just restarts the process if it killed by system.

How do I stop my thread and will my service stop too if I do?

I'm currently working on my first android app and I've run into a problem.
My app is supposed to be counting in the background using a Service and I'm creating a new thread to handle that. If I don't stop the thread in my Service's onDestroy() method, my phone gives me the message "Unfortunately, (my app) has stopped." every time I close the app. I need to stop it somehow, and I tried to do it using :
while(!Thread.currentThread().isInterrupted()){
**my code**
}:
And then interrupting it in the onDestroy() method.
It works, but it makes my app count extremely fast, so I would like to know if it can be done any other way that does not change the functionaliy of my code.
Also, since my thread gets stopped in the onDestroy method, I guess my service stops as well. Is there any way to keep my service running even when my app has been closed?
Here's my code:
public class CounterService extends Service {
private Handler handler;
private int time = -1;
private boolean isActive;
private Intent timeBroadcaster;
private Runnable counter;
private Thread serviceCounter;
#Override
public void onCreate(){
super.onCreate();
handler = new Handler();
timeBroadcaster = new Intent();
timeBroadcaster.setAction("EXAMPLE_BROADCAST");
counter = new Runnable() {
#Override
public void run() {
isActive = ((PowerManager) getSystemService(Context.POWER_SERVICE)).isInteractive();
if (isActive) {
handler.postDelayed(this, 1000);
time += 1;
} else {
if (time > 5) {
//log
}
time = 0;
handler.postDelayed(this, 1000);
}
timeBroadcaster.putExtra("counter", time);
sendBroadcast(timeBroadcaster);
}
};
serviceCounter = new Thread(counter);
serviceCounter.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy(){
//serviceCounter.interrupt();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Is there any way to keep my service running even when my app has been closed?
you can use sync adapter which runs in background even app is stoped.
https://developer.android.com/training/sync-adapters/creating-sync-adapter.html

OnDestroy restarts service, how can I destroy my activity without killing or restarting the service?

I'm writting an app that pops up notifications from time to time.
a service is running in the background, and when I kill the app the service is restarted and a notification pops up, but I don't want this to happen.
I want the service to stay there quiet and be executed at the right time.(I'm using a TimerTask)
I don't want to kill or restart the service, I want it to stay there quiet.
when i kill the app the service is restarted and a notification pops up, but i don't want this to happen
In your service's onStartCommand() method, return START_NOT_STICKY.
(and I so wish that this were the default...)
i want the service to stay there quiet and be executed at the right time.(I'm using a TimerTask)
Use AlarmManager to arrange to get executed at the right time; do not use a TimerTask in a running service. 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 faced the same issue and resolved after reading the documentation,dozen of stack overflows, and blog posts. I created a background service and made it foreground to prevent it from restarting if the app(process) closed or opened--to prevent the data lose from the service. but again, there was persistent notification produced which was unmovable(I hated it). I wanted to remove this notification along with service started. then started surfing on updating the notification and there I found a question directed me to the documentation of updating notification. I read that and update foreground service notification and vola it worked like charm. I'm giving the complete code here.
Main Activity
public class MainActivity extends AppCompatActivity {
TextView textView;
Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.time);
Intent background = new Intent(context,TimeBroadCast.class);
context.startService(background);
LocalBroadcastManager.getInstance(this).registerReceiver(
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int message = intent.getIntExtra(UpdatTime.timUpdate,0);
textView.setText(String.valueOf(message));
}
}, new IntentFilter(UpdatTime.ACTION_LOCATION_BROADCAST)
);
}
}
Service class
public class TimeBroadCast extends Service {
private boolean isRunning;
private Context context;
UpdatTime updatTime;
Timer timer;
#Override
public void onCreate() {
this.context = this;
this.isRunning = false;
timer = new Timer();
updatTime = new UpdatTime(this);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
StartForground();
Notification notification = new NotificationCompat.Builder(this).build();
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager nMgr = (NotificationManager) getApplicationContext().getSystemService(ns);
nMgr.notify(101,notification);
nMgr.cancel(101);
return START_STICKY;
}
#Override
public void onDestroy() {
StopForgroudn();
super.onDestroy();
}
private void StartForground() {
if(!isRunning) {
isRunning = true;
timer.schedule(updatTime, 0, 1000);
}
Notification notification = new NotificationCompat.Builder(this)
.setOngoing(false)
.setSmallIcon(android.R.color.transparent)
.build();
startForeground(101, notification);
}
private void StopForgroudn()
{
timer.cancel(); // Terminates this timer, discarding any currently scheduled tasks.
timer.purge(); // Removes all cancelled tasks from this timer's task queue.
stopForeground(true);
stopSelf();
}
}
TimerTaks class
public class UpdatTime extends TimerTask {
static String timUpdate = "timecountdown", ACTION_LOCATION_BROADCAST = TimeBroadCast.class.getName() + "TimeBroadCast";
Context myContext;
int i = 0;
public UpdatTime(Context myContext) {
this.myContext = myContext;
}
#Override
public synchronized void run() {
try {
i += 1;
Log.v("Data1", ""+i);
Intent intent = new Intent(ACTION_LOCATION_BROADCAST);
intent.putExtra(timUpdate,i);
LocalBroadcastManager.getInstance(myContext).sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hops this may helps.
Sorry for the improper format of the code....

Service is being recreated each time the activity resumes

I am in quite a tough predicament here as I have an activity that starts a service which runs a countdown timer. Each time the activity is resumed, the service starts another countdown timer. I looked up services and it has method which is called on once throughout the service and is called onCreate. The only issue with that is I am receiving time values from the activity through intents which is retrieved during onStartCommand. onCreate is called before onStartCommand meaning I cannot retrieve those values and plug them into onCreate. Is there a way I can put values from onStartCommand to onCreate. The following code shows my problem.
TextView timeTextView;
int data;
public String hms;
public CountDownAct countDownAct;
public CountDownTime countDownTimer;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
//I need the CountDownTimer to start here in order to prevent a new countdown timer from being created each time the activity is resumed.`
countDownTimer = new CountDownTime(data,1000 );
countDownTimer.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//the time data is being retrieved here
data = intent.getIntExtra("the", 0);
return START_STICKY;
}
#Override
public boolean stopService(Intent name) {
Log.i("CountDownService", "Stop Service");
return super.stopService(name);
}
#Override
public void onDestroy() {
countDownTimer.cancel();
}
Starting the Service
useService = new Intent(CountDownAct.this, CountDownService.class);
useService.putExtra("the", actualTimeFiniliazedInMilliSeconds);
startService(useService);
You can use SharedPreference to store actualTimeFiniliazedInMilliSeconds. This can be retrived from service class :
useService = new Intent(CountDownAct.this, CountDownService.class);
SharedPreference mShared = getApplicationContext().getSharedPreference("myShared",Context.MODE_PRIVATE);
SharedPreferences.Editor mEditor = mShared.edit();
mEditor.putInt("data",actualTimeFiniliazedInMilliSeconds).commit();
startService(useService);
Retriving :
SharedPreference mShared = getApplicationContext().getSharedPreference("myShared",Context.MODE_PRIVATE);
countDownTimer = new CountDownTime(mShared.getInt("data",0),1000);
countDownTimer.start();

How to disable HOME button click in android

I am new in android. I am creating a Lock screen application. In my application, I want to disable all the outside keys like Home key, Back key.. I already disabled the Back key using:
#Override
public void onBackPressed() {
return;
// Do nothing!
}
But i referred a lot of sites and questions in Stack Overflow to disable the Home key in my app. But nothing worked.
My App working on API 16 .. Please help me. Any help would be appreciated.
Thanks a lot in advence
I recommend reading:
How-To Create a Working Kiosk Mode in Android
Disable the home button and detect when new applications are opened
Since Android 4 there is no effective method to deactivate the home
button. That is the reason why we need another little hack. In general
the idea is to detect when a new application is in foreground and
restart your activity immediately.
At first create a class called KioskService that extends Service and
add the following snippet:
public class KioskService extends Service {
private static final long INTERVAL = TimeUnit.SECONDS.toMillis(2); // periodic interval to check in seconds -> 2 seconds
private static final String TAG = KioskService.class.getSimpleName();
private static final String PREF_KIOSK_MODE = "pref_kiosk_mode";
private Thread t = null;
private Context ctx = null;
private boolean running = false;
#Override
public void onDestroy() {
Log.i(TAG, "Stopping service 'KioskService'");
running =false;
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Starting service 'KioskService'");
running = true;
ctx = this;
// start a thread that periodically checks if your app is in the foreground
t = new Thread(new Runnable() {
#Override
public void run() {
do {
handleKioskMode();
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
Log.i(TAG, "Thread interrupted: 'KioskService'");
}
}while(running);
stopSelf();
}
});
t.start();
return Service.START_NOT_STICKY;
}
private void handleKioskMode() {
// is Kiosk Mode active?
if(isKioskModeActive()) {
// is App in background?
if(isInBackground()) {
restoreApp(); // restore!
}
}
}
private boolean isInBackground() {
ActivityManager am = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
return (!ctx.getApplicationContext().getPackageName().equals(componentInfo.getPackageName()));
}
private void restoreApp() {
// Restart activity
Intent i = new Intent(ctx, MyActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(i);
}
public boolean isKioskModeActive(final Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
return sp.getBoolean(PREF_KIOSK_MODE, false);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Add the following method in your AppContext class to start the service
via application context creation.
#Override
public void onCreate() {
super.onCreate();
instance = this;
registerKioskModeScreenOffReceiver();
startKioskService(); // add this
}
private void startKioskService() { // ... and this method
startService(new Intent(this, KioskService.class));
}
Last, add the service declaration and the permission for retrieving
the foreground process to the manifest:
<service android:name=".KioskService" android:exported="false"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
Basically, the thread checks every two seconds if your application is
running in foreground. If not, the thread will immediately recreate
your activity.

Categories

Resources