Android will kill some service when memory is not enough.
Like this:
I know I can use foreground service to prohibit android to kill my service
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
try {
Notification notification = new Notification(R.mipmap.ic_launcher,"this is service", System.currentTimeMillis());
Intent intent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,intent , 0);
notification.setLatestEventInfo(this, "myapp", "myservice", contentIntent);
notification.flags =Notification.FLAG_AUTO_CANCEL;
startForeground(123,notification);
}
catch(Exception e)
{
stopSelf();
}
}
#Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
But this will display a notification on screen
I would rather kill service than display notification, but I also don't want to display stopped message.
I found some app, it can display no message when android kills it.
e.g. Screen Dimmer
How can I prohibit android to display app stopped message?
Check this: https://stackoverflow.com/a/32229266/2965799
According to that I have used the following code to handle the exception. I wanted to display another message so I added my own message however if you use his answer there will be no messages.
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
new Thread() {
#Override
public void run() {
Looper.prepare();
Toast.makeText(getActivity(),"Your message", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
try
{
Thread.sleep(4000); // Let the Toast display before app will get shutdown
}
catch (InterruptedException e) { }
System.exit(2);
}
});
One way is to implement a UncaughtExceptionHandler with your own custom failure code. The API to install your handler is this:
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh);
The class is documented here. As a very basic example:
import java.lang.Thread.UncaughtExceptionHandler;
public final class CrashHandler implements UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
android.util.Log.wtf("My app name", "Oops, caught it dying on me!");
}
}
A full working example is available here.
Related
In my app, I am getting my messages instantly from my server via pusher. I have created a service designated to handle connections and firing broadcast messages to other activities in my app.
The problem that I face now is to have this service run in a new thread to have it still run even when my app goes to the background. I've found from this that I should create and connect it to the "service thread", but I cannot find examples for it with pusher.
If anyone can, could you please provide an example to do so? If not, insights to writing code with these "service threads" would be helpful as well. Thanks in advance for the help :D
PusherService.java
public class PusherService extends Service {
private static final String TAG = "PusherService";
private Pusher pusher = new Pusher("myKey");
private Channel channel = pusher.subscribe("cafe_channel");
private JSONObject pusherJSONObj;
private Order order;
public PusherService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//this service will run until we stop it
setupPusher();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
private void setupPusher() {
Log.d(TAG, System.currentTimeMillis()+"");
channel.bind("customer_order", new SubscriptionEventListener() {
#Override
public void onEvent(String channelName, String eventName, final String data) {
Intent broadcastIntent = new Intent();
try {
pusherJSONObj = new JSONObject(data);
order = new Order(pusherJSONObj);
broadcastIntent.setAction("customer_order");
broadcastIntent.putExtra("message", "success");
broadcastIntent.putExtra("order", order);
} catch (JSONException e) {
e.printStackTrace();
Log.d("Pusher", "conversion failed");
broadcastIntent.setAction("customer_order");
broadcastIntent.putExtra("message", "JSON conversion error");
}
sendBroadcast(broadcastIntent);
}
});
pusher.connect();
}
}
OrdersActivity.java
private BroadcastReceiver pusherReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase("customer_order")) {
adapter.newOrder((Order) intent.getParcelableExtra("order"));
}
}
};
It turns out that multithreading on one process does not solve my problem.
So instead, I split the service into a new process, which will keep the service running independent of the status of the main thread & process. Tested and found that service does not stall when my activities go background.
I have a button on which following code is written
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 10);
Intent intent = new Intent(Formact.this, MyService.class);
MyService.pintent = PendingIntent.getService(Formact.this, 0, intent, 0);
MyService.alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
MyService.alarm.setRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), 5000, MyService.pintent);
now once the services is created it has to destroy on a specific action but after each time it destroy it starts again.
here is my service class
public class MyService extends Service {
public static int counter = 0;
public static PendingIntent pintent;
public static AlarmManager alarm;
Boolean save=false;
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
return new Binder() ;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service was Created", Toast.LENGTH_SHORT).show();
}
#Override
public void onStart(Intent intent, int startId) {
counter++;
Toast.makeText(this, " Service Started" + " " + counter, Toast.LENGTH_SHORT).show();
SaveForm handler = new SaveForm(getApplicationContext());
handler.setobj(getApplicationContext());
handler.setText(Formact.sendform, Formact.listString);
handler.stratConnection();
String m = "";
int val = 0;
try{
Log.e("val",SaveForm.msg);
if(SaveForm.msg!=null)
{
m=SaveForm.msg.substring(SaveForm.msg.length() - 1);
}
val=Integer.parseInt(m);
Log.e("val",m);
if(val>0)
{
Toast toast = Toast.makeText(getApplicationContext(), "Data saved", 100);
toast.show();
save=true;
MyService.this.stopSelf();
// alarm.cancel(pintent);
if(alarm!=null)
{
try{
alarm.cancel(pintent);
}
catch(Exception e)
{
Toast toasdst = Toast.makeText(getApplicationContext(), "Massi", 100);
toasdst.show();
}
alarm=null;
}
}
}
catch(Exception e)
{
Toast toast = Toast.makeText(getApplicationContext(), "Data Not saved", 100);
toast.show();
///responseStr = responseStrr;
}
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
super.onDestroy();
if(save)
{
try{
stopSelf();
}
catch(Exception e)
{
Toast.makeText(this, "Head Bang", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
}
}
}
I had set the alarm.cancle but it throws exception because alarm is already null
I had also tried this
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try{
// String parameter = intent.getStringExtra("param_name");
if(save){
stopSelf();
}
}catch(Exception ex){
}
return startId;
}
But nothing works service starts again and again.
One more thing if I did not close the application than every thing works perfect the alarm is canceled but when I close the application and expect to run it same it background it start creating again and again.
Help please.
1.Do not use onStart(), in docs:
onStart(Intent intent, int startId)
This method was deprecated in API level 5. Implement onStartCommand(Intent, int, int) instead.
Use onStartCommand instead and return START_NOT_STICKY or START_STICKY not startId.
2. It seems that you are starting a connection handler.stratConnection(); if you are binding anything to it using bindService(), then you need to unbind it from the service using unbindService(mConnection). As given in docs:
Disconnect from an application service. You will no longer receive calls as the service is restarted, and the service is now allowed to stop at any time.
If you are not binding anything then return null in onBind().
#Override
public IBinder onBind(Intent intent) {
return null;
}
3. Use super.onDestroy() like this:
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
super.onDestroy();
/***** No need to put this as it is already going to be destroyed
if(save)
{
try{
stopSelf();
}
catch(Exception e)
{
Toast.makeText(this, "Head Bang", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
}
}
*****/
}
4. Cancel the alarm by alarm.cancel(pintent) before calling stopSelf().
if(alarm!=null)
{
try{
alarm.cancel(pintent);
}
catch(Exception e)
{
Toast toasdst = Toast.makeText(getApplicationContext(), "Massi", 100);
toasdst.show();
}
alarm=null;
}
MyService.this.stopSelf();
5. You are using alarm and pintent without initializing it. It is not initialized in your code.
6. Stop service in your activity by using context.stopService(intent), using the same intent as Intent intent = new Intent(Formact.this, MyService.class);.
As you are storing the data to the server by using
handler.setText(Formact.sendform, Formact.listString);
Simply once the data is saved make
Formact.sendform=null
Formact.listString=null
when these values are null the application will throw a exception catch it in a catch block and use this line to close
MyService.alarm.cancel(MyService.pintent);
MyService.this.stopService();
service will not start again.
I want to check some web API and do something per x minutes. I think I should write a service on Android (is there any other solution?).
But how can do that?
I am thinking about writing a service class and in the manifest file I should add this line:
<service
android:name="com.xx.yy.noti_check"
android:enabled="true"
>
</service>
And in my noti_check class I check my web API like this on onStartCommand:
public class noti_check extends Service {
Context mcont;
private Handler myhandler ;
private long RETRY_TIME = 15000;
private long START_TIME = 2000;
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onStart(Intent intent, int startId) {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mcont=this;
myhandler= new Handler();
myhandler.postDelayed(myRunnable, START_TIME);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
try {
myhandler.removeCallbacks(myRunnable);
}
catch (Exception e) {
// TODO: handle exception
}
}
private Runnable myRunnable = new Runnable() {
public void run() {
try {
new get_notifyalert(mcont).execute("") ;
}
catch (Exception e) {
// TODO: handle exception
}
myhandler.postDelayed(myRunnable, RETRY_TIME);
}
};
}
Is this is the right way?
Is this the right way?
No. 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. Use AlarmManager for periodic work like this.
I'm using a NotificationListenerService in my android app that was developed from kpbird's example. The service runs in the background even after the app is destroyed. Is there a way to stop this service and start it when app is started?
NotificationListenerService can not be stopped, because after we start the service system will call bindService() . The service will keep a ServiceConnection, then it will not response to the stopService or stopSelf.
As my search result , we also can not remove ServiceConnection from a Service instance.
Create a broadcast receiver inside service which extends NotificationListenerService
like this
public class Block_All_Notification2 extends NotificationListenerService {
boolean check=false;
CancelNotificationReceiver mReceiver = new CancelNotificationReceiver();
public static final String Package_Name = "com.muhaiminurabir.notificationblocker";
#Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
#Override
public void onNotificationPosted(StatusBarNotification sbn){
// Implement what you want here
// Inform the notification manager about dismissal of all notifications.
Log.d("Msg", "Notification arrived");
start_blocking();
/* if (false){
cancelAllNotifications();
}*/
//Block_All_Notification2.this.cancelAllNotifications();
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn){
// Implement what you want here
Log.d("Msg", "Notification Removed");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String block = intent.getStringExtra("block");
Log.d("checking service 1",block+"");
if (block.equals("yes")){
check=true;
}else if(block.equals("no")){
check=false;
}
Log.d("checking service 1",check+"");
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction(Package_Name);
registerReceiver(mReceiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
public void start_blocking(){
Log.d("checking service",check+"");
if (check==true){
cancelAllNotifications();
}
}
class CancelNotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("received service","received");
String action;
if (intent != null && intent.getAction() != null) {
action = intent.getAction();
if (action.equals(Package_Name)) {
String block = intent.getStringExtra("block");
if (TextUtils.equals(block, "no")) {
Log.d("checking service 1",block+"");
if (block.equals("yes")){
check=true;
cancelAllNotifications();
}else if(block.equals("no")){
check=false;
}
Log.d("checking service 1",check+"");
} else if (TextUtils.equals(block, "yes")) {
Log.d("checking service 1",block+"");
if (block.equals("yes")){
check=true;
cancelAllNotifications();
}else if(block.equals("no")){
check=false;
}
Log.d("checking service 1",check+"");
}
}
}
}
}
}
and in your activity add this code to communicate with service which create above
Intent intent = new Intent();
intent.setAction(Block_All_Notification2.Package_Name);
intent.putExtra("block", "no");
context.sendBroadcast(intent);
Perhaps this problem has been solved.
However, I recently found a way to start or stop NotificationListenerService, and I would like to share it.
Of course, this is not the official method I think.
Therefore, I think you can just look at it for reference that there is also this way.
I got a hint from the fact that in order to run NotificationListenerService, users must be authorized manually.
When the Start Button is pressed, the NotificationListener permission window is displayed, and a Toast Message is displayed to guide the user to request permission.
On the contrary, when the Stop Button is pressed, the NotificationListener permission window is displayed, and at the same time, a Toast Message is displayed to guide the user to revoke permission.
My code is like belows.
main_start_service_btn.setOnClickListener {
if(isNotificationPermissionAllowed()) {
Toast.makeText(this, "Already Starting Service.", Toast.LENGTH_LONG).show()
}
else {
Toast.makeText(this, "Please allow permission in the next window", Toast.LENGTH_LONG).show()
startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
}
main_stop_service_btn.setOnClickListener {
if(isNotificationPermissionAllowed()) {
Toast.makeText(this, "Please deny permission in the next window", Toast.LENGTH_LONG).show()
startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
else {
Toast.makeText(this, "Already Stopped Service.", Toast.LENGTH_LONG).show()
}
}
The NotificationListenerService extends Service so yes you can stop a service by calling stopSelf() method in Service class.
Look at this: NotificationListenerService and this Services
Hope it Helps,
I have try build a android application that use a thread inside a service, the service and the thread run with well, but when i stop and destroy the service, the thread still live, so when i run again the application there are 2 thread in the application, so i wannt to know how i can destroy the thread.
anybody can help me to solve the problem ?
here my service class :
public class MyService extends Service{
Handler handler;
static String toast_msg;
Thread t;
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Congrats! MyService Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onStart(Intent intent, int startId) {
/* Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
//Note: You can start a new thread and use it for long background processing from here.*/
toast_msg = "Horas";
super.onStart(intent, startId);
Toast.makeText(getApplicationContext(), toast_msg, Toast.LENGTH_LONG)
.show();
handler = new Handler() {
public void handleMessage(android.os.Message msg) {
super.handleMessage(msg);
Toast.makeText(getApplicationContext(), toast_msg,
Toast.LENGTH_LONG).show();
}
};
t = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
t.sleep(5000);
// Toast.makeText(getApplicationContext(), "Horas",
// Toast.LENGTH_LONG).show();
handler.sendEmptyMessage(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
t.start();
}
#Override
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
//t.interrupt();
handler.removeCallbacks(t);
super.onDestroy();
t.currentThread().interrupt();
}
}
t = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
if(flag){//here add a flag
return;
}
t.sleep(5000);
// Toast.makeText(getApplicationContext(), "Horas",
// Toast.LENGTH_LONG).show();
handler.sendEmptyMessage(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
t.start();
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
//t.interrupt();
handler.removeCallbacks(t);
super.onDestroy();
flag = false;//here set flag to false
}
You may want to consider using Service or IntentService instead, as these provide better management of threads, pausing, restarting etc.
See the Android IntentService documentation, or this other StackOverflow question and answer session. There's not much call to be kicking off your own threads these days, as there's better threading/service management features provided by the Android API/SDKs.
These are much more stable, optimised, and (in my opinion) neater and cleaner to use than spinning up a raw thread and trying to manage it yourself, especially if you're not catering for your app suddenly being killed because the battery went flat or the user doing something unexpected.