Start activity from service takes too long - android

I have a Service that when one function gives to me true it will start a new Activity but it takes like 5 seconds...
I've read about this issue, and I've found on StackOverflow this example to "avoid" this bug..
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
but sadly it doesn't start the Activity faster, I don't need to be inmmediate (better if it's possible), but I don't want to wait +5 seconds to launch the new Activity, do you knwo any trick to avoid this?
I'm using PendingIntent because I've found that guy that said that it should solve this issue :
Starting an activity from a service after HOME button pressed without the 5 seconds delay
Note
If I press back button it launch it autommatically, 0 delay, but I'm looking pressing the home button.

I cannot comment everywhere yet, so I'm putting this solution of a similar problem as an answer
After much digging, found out the cause of the problem. Apparently
it's not a bug, it is a feature which does not allow Services or
BroadcastReceivers to launch activities for up to 5 seconds after home
button is pressed. No easy way to overcome this.
More info here:
https://code.google.com/p/android/issues/detail?id=4536
I replaced the activity with a Window added to the window manager of
the running service. This does not cause any delay.
Source link Stackoverflow

First thing we cannot update any UI related stuff in service, neither calling activity nor updating any UI elements, 
Same problem i too have faced.
Then i have used EventBus library to communicate UI elements from service 
Below is the sample example
public class SendSPLocationService extends Service {
Handler mHandler = new Handler();
Thread downloadThread;
boolean isRunning = true;
private VolleyHelper volleyHelper;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
// Toast.makeText(this, " MyService Created ", Toast.LENGTH_LONG).show();
volleyHelper = new VolleyHelper(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
Log.d("run: ", "service is running!");
try {
EventBus.getDefault().post(new FutureJobEvent(false, error.networkResponse.statusCode, errorJson.getString("message")));
} catch (JSONException e) {
e.printStackTrace();
}
// t.cancel();
Log.d("run: ", "service is stopped!");
}
}, 0, 5000);
return START_STICKY;
}
}
Use below code for triggered event to observe..either in activity/fragment
#Override
public void onStart() {
super.onStart();
if (!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
if (EventBus.getDefault().isRegistered(this))
EventBus.getDefault().unregister(this);
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(TrackSPEvent event) {
if (event.success) {
startActivity(new Intent(this,MainActivity.class));
}
}

I tested with the PendingIntent approach and couldn't find anything wrong. That seems to be working fine. However, for reference, here is what I tried at my end:
public class MyService extends Service {
public static final String SERVICE_COMMAND = "COMMAND";
public static final String TAG = "MyService";
public static final int SERVICE_START = 0x01;
public static final int START_ACTIVITY = 0x02;
private class ServiceHandler extends Handler {
public ServiceHandler(HandlerThread thread) {
super(thread.getLooper());
}
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case START_ACTIVITY:
Intent ActivityIntent = new Intent(getApplicationContext(), TestActivity.class);
ActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
0, ActivityIntent, 0);
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
Log.e(TAG, "Service started activity -> " + System.currentTimeMillis());
default:
break;
}
super.handleMessage(msg);
}
}
private HandlerThread mThread;
private ServiceHandler mHandler;
public MyService() {
mThread = new HandlerThread("ServiceThread");
mThread.start();
mHandler = new ServiceHandler(mThread);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int id = intent.getIntExtra(SERVICE_COMMAND, SERVICE_START);
switch (id) {
case START_ACTIVITY:
Log.e(TAG, "onStartCommand Service -> " + System.currentTimeMillis());
mHandler.sendEmptyMessage(START_ACTIVITY);
break;
default:
break;
}
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Activity Code:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Main";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate main activity -> " + System.currentTimeMillis());
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause main activity -> " + System.currentTimeMillis());
Intent intent = new Intent(this, MyService.class);
intent.putExtra(MyService.SERVICE_COMMAND, MyService.START_ACTIVITY);
startService(intent);
}
}
You can try the same code at your end. May be it can help.

Related

A simple Service that never stop. Why?

I am developing a very simple app that play a song forever until the user stop it.
I am using the bind/unbind service functions just to send a simple message ( hello ) from the activity to the service.
The problem is that when I tap to stop the song, it doesn't stop ( even if in the Logcat I see the "stop" string ). Why ?
This is my code:
MainActivity:
public class MainActivity extends AppCompatActivity {
boolean started = false;
boolean musicBound = false;
TextView button;
private Intent playIntent;
private PlayerService musicSrv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (TextView) findViewById(R.id.playstopbutton);
playIntent = new Intent(this, PlayerService.class);
}
#Override
public void onResume(){
super.onResume();
// put your code here...
if(!started) {
// button.setText(">");
}else{
// button.setText("||");
}
}
//connect to the service
private ServiceConnection musicConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("My App", "conn");
PlayerService.MusicBinder binder = (PlayerService.MusicBinder)service;
//get service
musicSrv = binder.getService();
//pass list
musicSrv.tryit("hello");
musicBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i("My App", "disc");
musicBound = false;
}
};
public void playstop(View v)
{
if(!started) {
Log.i("My App", "start");
started = true;
// button.setText("||");
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
}else{
Log.i("My App", "stop");
started = false;
// button.setText(">");
stopService(playIntent);
musicSrv=null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onDestroy() {
if (musicConnection != null) {
unbindService(musicConnection);
}
stopService(playIntent);
musicSrv=null;
super.onDestroy();
}
}
PlayerService:
public class PlayerService extends Service
{
MediaPlayer mediaPlayer = null;
String title = "aaaa";
String msg = "bbbb";
String ticker = "just a ticker";
private final IBinder musicBind = new MusicBinder();
#Override
public void onCreate() {
mediaPlayer = MediaPlayer.create(this, R.raw.song);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.setLooping(true);
mediaPlayer.start();
}
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle(title)
.setContentText(msg)
.setSmallIcon(R.drawable.note2)
.setContentIntent(pendingIntent)
.setTicker(ticker).setColor(0xff222222).build();
startForeground(11, notification);
return START_STICKY;
}
//binder
public class MusicBinder extends Binder {
PlayerService getService() {
return PlayerService.this;
}
}
//activity will bind to service
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
//release resources when unbind
#Override
public boolean onUnbind(Intent intent){
mediaPlayer.stop();
mediaPlayer.release();
return false;
}
public void tryit(String stringa){
Log.i("My App", stringa);
}
public void onDestroy() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
stopForeground(true);
Log.i("PROVA SERVICE", "Distruzione Service");
}
}
when I tap to stop the song, it doesn't stop
Because you are only calling stop() on the MediaPlayer if either:
the client unbinds from it (onUnbind()), which is not what your client is doing, or
the client unbinds from it and you stop it (onDestroy()), which is not what your client is doing
A service will be destroyed when both of the following statements are true:
Each client that had bound to is unbinds, and
If startService() had been called for this service, stopService() is called
In this case, you are calling stopService(), but you are still bound to the service, so onDestroy() is not called.

How to set limit when user enter wrong pattern many time?

Currentlly I am implementing pattern lock application and I want to set limit when user enter wrong pattern many time.Example,If user enter wrong pattern at that time set limit(3 or 4 time limit) and set delay 30 second and after 30 second give permission to enter pattern.
So,If anyone know how i can do this please give idea of that.
Here this my Reciever
public class LockScreenReceiver extends DeviceAdminReceiver {
Context context;
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i("Action...","..."+action);
//If the screen was just turned on or it just booted up, start your Lock Activity
if(action.equals(Intent.ACTION_SCREEN_OFF) || action.equals(Intent.ACTION_BOOT_COMPLETED))
{
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
#Override
public void onPasswordFailed(Context ctxt, Intent intent) {
DevicePolicyManager mgr = (DevicePolicyManager) ctxt.getSystemService(Context.DEVICE_POLICY_SERVICE);
int no = mgr.getCurrentFailedPasswordAttempts();
if (no >= 3) {
context.startActivity(new Intent(context,ChangeActivity.class));
}
}
}
Service
public class LockScreenService extends Service {
DeviceAdminReceiver receiver;
#Override
public IBinder onBind(Intent intent) {
return null;
}
// Register for Lockscreen event intents
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
receiver = new LockScreenReceiver();
registerReceiver(receiver, filter);
startForeground();
return START_STICKY;
}
// Run service in foreground so it is less likely to be killed by system
private void startForeground() {
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getResources().getString(R.string.app_name))
.setTicker(getResources().getString(R.string.app_name))
.setContentText("Running")
.setContentIntent(null)
.setOngoing(true)
.build();
startForeground(9999,notification);
}
#Override
#SuppressWarnings("deprecation")
public void onCreate() {
KeyguardManager.KeyguardLock key;
KeyguardManager km = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);
//This is deprecated, but it is a simple way to disable the lockscreen in code
key = km.newKeyguardLock("IN");
key.disableKeyguard();
//Start listening for the Screen On, Screen Off, and Boot completed actions
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
//Set up a receiver to listen for the Intents in this Service
receiver = new LockScreenReceiver();
registerReceiver(receiver, filter);
super.onCreate();
}
#Override
public void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
}
}
Activity
public class MainActivity extends ActionBarActivity {
private Lock9View lock9View;
private static String MY_PREFS_NAME = "PatternLock";
private static String PATTERN_KEY;
SharedPreferences prefs;
Button btnChange;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startService(new Intent(MainActivity.this, LockScreenService.class));
makeFullScreen();
setContentView(R.layout.activity_main);
btnChange = (Button)findViewById(R.id.btnChange);
btnChange.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent in = new Intent(MainActivity.this,ChangeActivity.class);
startActivity(in);
}
});
prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);
lock9View = (Lock9View) findViewById(R.id.lock_9_view);
lock9View.setCallBack(new Lock9View.CallBack() {
#Override
public void onFinish(String password) {
PATTERN_KEY = prefs.getString("Pattern", "invalid");
if (PATTERN_KEY.equals("invalid")) {
Toast.makeText(MainActivity.this, "Options --> Create new Pattern", Toast.LENGTH_LONG).show();
} else {
if (password.equals(PATTERN_KEY)) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
}else{
Context context = getApplicationContext();
// Create layout inflator object to inflate toast.xml file
LayoutInflater inflater = getLayoutInflater();
// Call toast.xml file for toast layout
View toastRoot = inflater.inflate(R.layout.layout_toast3, null);
Toast toast = new Toast(context);
// Set layout to toast
toast.setView(toastRoot);
toast.setGravity(Gravity.HORIZONTAL_GRAVITY_MASK | Gravity.BOTTOM,
0, 0);
toast.setDuration(Toast.LENGTH_LONG);
toast.show();
}
}
}
});
}
private void makeFullScreen() {
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
if(Build.VERSION.SDK_INT < 19) { //View.SYSTEM_UI_FLAG_IMMERSIVE is only on API 19+
this.getWindow().getDecorView()
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
} else {
this.getWindow().getDecorView()
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE);
}
}
#Override
public void onBackPressed() {
return; //Do nothing!
}
public void unlockScreen(View view) {
//Instead of using finish(), this totally destroys the process
android.os.Process.killProcess(android.os.Process.myPid());
}
}
So,How i can achieve this...
Have a int field like failedCounter and increment it each time user inputs invalid patterns check if reached the limit then disable the input interface and have a handler to reset the value after the time delay.
int failedCount = 0;
final static int LIMIT = 5; //set your limit here
private void invalidPattern() {
if (++failedCount == LIMIT) {
//disable the input
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//reset the failed count
faildCount = 0;
//Enable the input interface here
}
}, 30000); // 30Sec delay
}
}
Use this two methods -
ScheduledThreadPoolExecutor c1;
private void IncorrectCallCounter() {
if (failedCounter>=0)
{
c1.shutdownNow();
LockScreenFor30Second();
}else
{
if (c1!=null)
c1.shutdownNow();
}
c1 = new ScheduledThreadPoolExecutor(1);
c1.schedule(new Runnable() {
#Override
public void run() {
failedCounter=0;
c1.shutdownNow();
}
}, 15, TimeUnit.SECONDS);
}
ScheduledThreadPoolExecutor c2;
private void LockScreenFor30Second() {
//Lock Screen Here
c2 = new ScheduledThreadPoolExecutor(1);
c2.schedule(new Runnable() {
#Override
public void run() {
//Unlock Screen Here
c2.shutdownNow();
}
}, 30, TimeUnit.SECONDS);
}
Declare failedCounter globally
private int failedCounter=0;
And call this method when you detect wrong pattern -
failedCounter=failedCounter+1;
IncorrectCallCounter();
If user enter wrong pattern 4 times in 15 seconds then this will call LockScreenFor30Second method. and inside LockScreenFor30Second add your code.

How to know if phone app is closed

please explain me how does android call lock screen after closing emergency dialer. I've tried to check every second if emergency call is the top activity if it's not then i just lock device but this didn't do it's job in android 5.0 and higher. So, I need another solution.
My code:
private static final long INTERVAL = TimeUnit.SECONDS.toMillis(1/100);
private Thread t = null;
private Context ctx = null;
private boolean running = false;
public MyService2() {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
running = true;
ctx = this;
Log.i("Point","PreRun");
t = new Thread(new Runnable() {
#Override
public void run() {
Log.i("Point","preloop");
do {
Log.i("Point", "Prechech");
if (activityManager.getRunningTasks(1).get(0).topActivity.getPackageName().equals("com.android.phone") || activityManager.getRunningTasks(1).get(0).topActivity.getPackageName().equals("com.android.dialer"))
{
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
Log.i("Point", "Thread interrupted: 'KioskService'");
}
} else {
running=false;
Log.i("Task is",activityManager.getRunningTasks(1).get(0).topActivity.getPackageName());
stopSelf();
}
}while (running) ;
}
});
t.start();
Log.i("Point","Done");
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i("Point","Service is stopped");
}
}
And this:
public class MyActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent("com.android.phone.EmergencyDialer.DIAL");
startActivity(intent);
Intent intent1 = new Intent(MyActivity.this,MyService2.class);
startService(intent1);
}
});
}
}
You can launch your emergency dialer like this:
Intent intent = new Intent("android.intent.action.MAIN");
intent.setComponent(ComponentName.unflattenFromString("com.android.phone/.EmergencyDialer"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Moreover please check if you have declared your service properly in manifest.
<service
android:name=".MyService2">
</service>

Service and Chronometer Synchronization

I need to be able to start chronometer, then close activity, after that through notifications, back to that activity, and see the right time in chronometer.
What I've Done
A part of my Activity:
public void doClick(View target)
{
switch(target.getId())
{
case R.id.buttonStart:
{
Mchronometer.setBase(SystemClock.elapsedRealtime());
Mchronometer.start();
Intent intent = new Intent(RecentActivity.this, ChronometerService.class);
intent.putExtra("task_name",task_name);
intent.putExtra("task_id",task_id);
intent.putExtra("ellapsedTime",Mchronometer.getBase());
Log.d("base",""+Mchronometer.getBase());
startService(intent);
break;
}
case R.id.buttonStop:
{
stopService(new Intent(RecentActivity.this, ChronometerService.class));
Mchronometer.stop();
Mchronometer.setBase(SystemClock.elapsedRealtime());
break;
}
case R.id.button3:
{
break;
}
}
}
A part of my Service:
public class ChronometerService extends Service {
private ThreadGroup myThreads = new ThreadGroup("ServiceWorker");
private NotificationManager notificationMgr;
private int task_id;
private long ellapsedTime;
#Override
public void onCreate() {
super.onCreate();
notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
String task_name =intent.getExtras().getString("task_name");
task_id =intent.getExtras().getInt("task_id");
ellapsedTime = intent.getExtras().getLong("ellapsedTime");
Log.d("servicebase",""+ellapsedTime);
displayNotificationMessage(task_name);
new Thread(myThreads, new ServiceWorker(),"ChronometerService").start();
return START_STICKY;
}
private class ServiceWorker implements Runnable {
public void run() {
}
}
#Override
public void onDestroy()
{
myThreads.interrupt();
notificationMgr.cancelAll();
super.onDestroy();
}
public IBinder onBind(Intent intent) {
return null;
}
public void displayNotificationMessage(String message){
Notification notification = new Notification(R.drawable.emo_im_winking,message,System.currentTimeMillis());
notification.flags = Notification.FLAG_NO_CLEAR;
Intent intent = new Intent(this, RecentActivity.class);
intent.putExtra("task_id", task_id);
intent.putExtra("ellapsedTime",ellapsedTime);
Log.d("servicebase1",""+Long.toString(ellapsedTime));
PendingIntent contentintent = PendingIntent.getActivity(this,0,intent,0);
notification.setLatestEventInfo(this,"ChronometerService",message,contentintent);
notificationMgr.notify(0, notification);
}
}
I tried to send a message from activity to a service, which contains elapsed information.
If I started it first on my device (after system load) it's works right, but when I launch it again. The activity receives wrong message. It receives the time of the first service launched on the device.
As you can see I also send one more variable, and activity reads it correctly.
I've found a solution to my question.
It's simple.
It's needed to use flag(PendingIntent.FLAG_UPDATE_CURRENT)
PendingIntent contentintent = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
And it's work fine.

Checking status of a service failing because classloader

I have an Activity that starts a service which isn't local. Sometimes I check if is alive to perform actions.
My attempt at the moment was to use a static boolean variable. Reading some posts on SO I found out this not works because each process has it's own classloader.
Iterating over all running services is expensive to do a simple task like this.
Other solutions points out to use AIDL. In a very near future in my service, I'll store a WeakReference for the current running activity to execute it again in case of crash. Assuming for now I just want to check the service' state, is this an expensive solution too?
P.S.: I know it's an ugly solution to not handle exception properly. It's just a try.
EDIT: To clarify what I'm doing I post some code. This is the Service classs:
public class CrashRecover extends Service {
private volatile boolean stop = false;
private Thread backgroundThread;
private Messenger serviceMessenger = null;
private static boolean running = false;
...
#Override
public int onStartCommand(Intent intent, int flags, int startID){
serviceMessenger = new Messenger(new ServiceHandler(serviceLooper));
return START_STICKY;
}
#Override
public void onCreate(){
super.onCreate();
HandlerThread handlerThread = new HandlerThread("CrashRecoverThread", Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
serviceLooper = handlerThread.getLooper();
backgroundThread = new Thread(){
#Override
public void run(){
synchronized(this){
try {
while(!stop){
sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
running = true;
}
#Override
public void onDestroy(){
super.onDestroy();
try {
Message destroyMessage = Message.obtain();
destroyMessage.arg1 = CrashRecover.DESTROY_SERVICE;
serviceMessenger.send(destroyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
running = false;
}
#Override
public IBinder onBind(Intent arg0) {
return serviceMessenger.getBinder();
}
public static boolean isRunning(){
return CrashRecover.running;
}
...
private class ServiceHandler extends Handler{
public ServiceHandler(Looper looper){
super(looper);
}
#Override
public void handleMessage(Message message){
switch(message.what){
case REGISTER_CLIENT:
//addActivityToRespawn(null);
//respawnActivity();
Log.i("INFO", "Service is registered");
break;
case UNREGISTER_CLIENT:
activityParams = message.getData();
//respawnActivity();
if(backgroundThread.isAlive()){
stop = true;
}
Log.i("INFO", "Service is unregistered");
break;
case DESTROY_SERVICE:
Log.i("INFO", "Service is destroyed");
break;
default:
super.handleMessage(message);
}
}
}
}
And this is my class when I verify if service is running:
public class Main extends Activity {
private Button serviceButton, crashButton;
private Intent serviceIntent;
private ClientMessageHandler clientHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
...
clientHandler = new ClientMessageHandler();
serviceIntent = new Intent(Main.this, CrashRecover.class);
startService(serviceIntent);
}
...
#Override
public void onBackPressed(){
if(CrashRecover.isRunning()){
Log.i("INFO", "Service is running");
//Execute some actions
}
}
...
}
If you aren't doing this very often then I'd suggest using the "iterate over running services" method. There shouldn't be that many services running on your phone and iterating over them just accesses some internal data structures that Android keeps. Should work just fine.

Categories

Resources