How to pause and resume thread in android - android

When I get UserRecoverableAuthIOException in AbstractThreadedSyncAdapter, I'm creating a notification as below.
Here's how I'm creating the service:
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
Log.i("Service", "Thread started");
return this.getSyncAdapter().getSyncAdapterBinder();
}
private GoogleTasksSyncAdapter getSyncAdapter() {
if (syncAdapter == null)
{
Log.i("Service", "syncAdapter started");
syncAdapter = new MySyncAdapter(this);
}
return syncAdapter;
}
Once the thread is started, I'm raising a notification. But once user clicks on the notification, they can see the authorization activity. After authorising how to resume from the last point. I.e how to get notified once the activity is closed in Syncadapter.

The SyncAdapter thread are running, and you want to get notification when SyncAdapter ends, right?
So, you can comunicate the SyncAdapter thread with BroadCast.
In your SyncAdapter class:
Intent i = new Intent(SYNC_FINISHED);
context.sendBroadcast(i);
Log.i(TAG, "Network synchronization complete");
In a activity or a fragment:
private BroadcastReceiver syncFinishedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Sync finished!!");
// Here you can send your notification or another thing that you want
}
};
#Override
public void onStart() {
super.onStart();
getActivity().registerReceiver(syncFinishedReceiver, new IntentFilter(SyncAdapter.SYNC_TASK_FINISHED));
}
#Override
public void onStop() {
super.onStop();
getActivity().unregisterReceiver(syncFinishedReceiver);
}
NOTE: The SYNC_FINISHED constant, you can define previously in your SyncAdapter
I hope I've helped you.
Greetings!

In your SyncAdapter you do something like:
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.i(TAG, "Beginning network synchronization");
if(extras.getBoolean(RUN_METHOD_1) || extras.getBoolean(RUN_ALL)) {
method1();
}
if(extras.getBoolean(RUN_METHOD_2) || extras.getBoolean(RUN_ALL)) {
method2();
}
}
public void method1(){
try{
// do something
} catch (Exception e) {
e.printStackTrace();
// here you can send your notification when exception occours.
}
}
public void method2(){
try{
// do something
} catch (Exception e) {
e.printStackTrace();
// here you can send your notification when exception occours.
}
}
in your "authorization" code you do something like:
Bundle b = new Bundle();
b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
b.putBoolean(SyncAdapter.RUN_METHOD_1, true);
ContentResolver.requestSync(account, CONTENT_AUTHORITY, b);
so you can run where the sync stopped.
Greetings!!!

Here is the solution,
we need to use the syncResult.stats.numAuthExceptions to tell about exception, it throws message automatically. syncResult.delayUntil will wait and restart sync after elapsing time
How to show sync failed message

Related

Android create thread for pusher to run at background

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.

How to prevent Android displaying app stopped message

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.

Android ordered syncs

I am investigating on how to call sync adapters in a precise order.
Indeed, I have several providers for items such as clients and contracts.
Syncing one of those means:
Sending local modifications to the server for updating its database (such as new clients, updated contracts and so on)
Receiving sever modifications and updating local database
So, I have to sync clients and THEN sync contracts. Indeed, if I start syncing contracts first, one of them could refer to a client that has not yet been synced and inserted in the smartphone database.
After having performed some tests, I found that sync requests on different providers are performed at the same time.
For example, calling :
ContentResolver.requestSync(account, ClientsProvider.AUTHORITY, syncBundle);
ContentResolver.requestSync(account, ContractsProvider.AUTHORITY, syncBundle);
will result in parallel (thus, unordered) syncs of clients and contrats.
Do someone know how to perform sync requests one after the other or have an idea for solving this issue?
The only solution I have found so far is to use a service and the wait() and notify() methods in order for the service to pause between sync calls.
If I have 2 providers named ClientsProvider and ContractsProvider, I create and declare 2 SyncAdapters, each one having the following onPerformSync() method:
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
{
boolean callerIsMySyncService = extras.getBoolean(GlobalDataSyncService.EXTRA_CALLER_IS_MY_SYNC_ADAPTER, false);
if (callerIsMySyncService)
{
performSync(account, extras, authority, provider, syncResult);
}
else
{
Intent intent = new Intent(context, MySyncService.class);
intent.putExtra(MySyncService.EXTRA_ACCOUNT, account);
context.startService(intent);
}
}
performSync() is the method where I put my sync logic. The only difference is the need to call MySyncService.releaseLock() in order to tell the service that sync is finished:
public void performSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
{
try
{
// Sync logic goes there
}
finally
{
MySyncService.releaseLock();
}
}
The service code is:
public class MySyncService extends Service
{
public static String EXTRA_CALLER_IS_MY_SYNC_ADAPTER = "isCaller";
public static String EXTRA_ACCOUNT = "account";
private static Boolean isSyncing = Boolean.FALSE;
private static Object lock = new Object();
public MySyncService() {}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
synchronized (isSyncing) {
Account account = (Account)intent.getParcelableExtra(EXTRA_ACCOUNT);
// Sync only if it not already in progress and if there is an account
if ( ! isSyncing && account != null)
{
isSyncing = Boolean.TRUE;
new Thread(new SyncRunner(account)).start();
}
}
return START_REDELIVER_INTENT;
}
public static void releaseLock()
{
synchronized (lock) {
try
{
lock.notify();
}
catch (IllegalMonitorStateException e)
{
// Log error
}
}
}
#Override
public IBinder onBind(Intent intent)
{
throw new UnsupportedOperationException("Not yet implemented");
}
class SyncRunner implements Runnable
{
private Account account;
public SyncRunner(Account account)
{
this.account = account;
}
public void run()
{
try
{
Bundle syncBundle = new Bundle();
syncBundle.putBoolean(EXTRA_CALLER_IS_MY_SYNC_ADAPTER, true);
ContentResolver.requestSync(account, ClientsProvider.AUTHORITY, syncBundle);
synchronized (lock) {
lock.wait();
}
ContentResolver.requestSync(account, ContractsProvider.AUTHORITY, syncBundle);
synchronized (lock) {
lock.wait();
}
}
catch (InterruptedException e)
{
// Log error
}
finally
{
synchronized (isSyncing) {
isSyncing = Boolean.FALSE;
}
}
}
}
}

service in infinite loop android

I want to call a service which repeatedly queries a Parse.com database and monitors a specific attribute.Here's what Ive got so far:
public class Battle extends Service {
#Override
public int onStartCommand(Intent intent,int flags,int startId)
{
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
ParseUser currentUser = ParseUser.getCurrentUser();
username = currentUser.getString("username");
findinBackground();
return START_STICKY;
}
private void findinBackground(){
//public void run() {
// TODO Auto-generated method stub
while(true)
{
query = ParseUser.getQuery();
query.whereEqualTo("isAttacking", username);
query.findInBackground(new FindCallback<ParseUser>() {
public void done(List<ParseUser> objects, ParseException e) {
if ((e == null)&(objects.size() != 0))
{
// The query was successful.
ParseUser attacker = objects.get(0);
String attackerName = attacker.getUsername();
Log.i("ambustest",attackerName);
makeToast(attackerName);
}
else
{
Log.i("fd","Something went wrong.");
}
}
});
}
}
}
This code compiles fine but stops responding at runtime.Here's my logcat:
You need to call the service on a separate thread
#Override
public int onStartCommand(Intent intent,int flags,int startId)
{
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
ParseUser currentUser = ParseUser.getCurrentUser();
username = currentUser.getString("username");
new Thread()
{
public void run() {
findinBackground();
}
}.start();
return START_STICKY;
}
It should be noted that Intent Service is automatically called on a separate thread, however a regular service is not.
Services are run on the same thread as your UI. If you want to do time consuming operations, you need to fire them off in a separate thread.
The best solution is a Remote Service with a Handler that reports your client(s) (Activity) about changes.
http://developer.android.com/reference/android/app/Service.html
Your Service will run in a seperate process
First you need a AIDL - as an interface to communicate with service and client
// IRemoteService.aidl
package de.contecon.android.util.abstractservice;
interface IRemoteService {
void registerCallback(IRemoteServiceCallback mCallback);
void unregisterCallback(IRemoteServiceCallback mCallback);
}
Your Service can look like this
//RemoteService.java
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY_COMPATIBILITY;
}
#Override
public void onCreate() {
// While this service is running, it will continually increment a
// number. Send the first message that is used to perform the
// increment.
mHandler.sendEmptyMessage(REPORT_MSG);
}
#Override
public IBinder onBind(Intent intent) {
// Select the interface to return. If your service only implements
// a single interface, you can just return it here without checking
// the Intent.
if (IRemoteService.class.getName().equals(intent.getAction())) {
return mBinder;
}
//Example for a second Binder
// if (IRemoteServiceSecondary.class.getName().equals(intent.getAction())) {
// return mBinderSec;
// }
return null;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
#Override
public void registerCallback(IRemoteServiceCallback mCallback) throws RemoteException {
if (mCallback != null) mCallbacks.register(mCallback);
}
#Override
public void unregisterCallback(IRemoteServiceCallback mCallback) throws RemoteException {
if (mCallback != null) mCallbacks.unregister(mCallback);
}
};
/**
* Our Handler used to execute operations on the main thread. This is used
* to schedule increments of our value.
*/
private final Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
switch (msg.what) {
// It is time to bump the value!
case REPORT_MSG: {
// Up it goes.
int value = ++mValue;
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
for (int i=0; i<N; i++) {
try {
mCallbacks.getBroadcastItem(i).valueChanged(value);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mCallbacks.finishBroadcast();
// Repeat every 1 second.
sendMessageDelayed(obtainMessage(REPORT_MSG), 1*1000);
} break;
default:
super.handleMessage(msg);
}
}
};
And your Client
/**
* This implementation is used to receive callbacks from the remote
* service.
*/
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
/**
* This is called by the remote service regularly to tell us about
* new values. Note that IPC calls are dispatched through a thread
* pool running in each process, so the code executing here will
* NOT be running in our main thread like most other things -- so,
* to update the UI, we need to use a Handler to hop over there.
*/
public void valueChanged(int value) {
mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
}
};
private static final int BUMP_MSG = 1;
private Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
switch (msg.what) {
case BUMP_MSG:
mCallbackText.setText("Received from service: " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
};
public void startService() {
// Make sure the service is started. It will continue running
// until someone calls stopService().
// We use an action code here, instead of explictly supplying
// the component name, so that other packages can replace
// the service.
startService(new Intent(
"your.action.uri.code.REMOTE_SERVICE"));
}
public void stopService() {
// Cancel a previous call to startService(). Note that the
// service will not actually stop at this point if there are
// still bound clients.
stopService(new Intent(
"your.action.uri.code.REMOTE_SERVICE"));
}
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = IRemoteService.Stub.asInterface(service);
mCallbackText.setText("Attached.");
// We want to monitor the service for as long as we are
// connected to it.
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
// As part of the sample, tell the user what happened.
Toast.makeText(RemoteServiceBinding.this, "service connected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mCallbackText.setText("Disconnected.");
// As part of the sample, tell the user what happened.
Toast.makeText(RemoteServiceBinding.this,"service disconnected",
Toast.LENGTH_SHORT).show();
}
};
private void bindService(){
// Establish a couple connections with the service, binding
// by interface names. This allows other applications to be
// installed that replace the remote service by implementing
// the same interface.
bindService(new Intent(IRemoteService.class.getName()),
mConnection, Context.BIND_AUTO_CREATE);
bindService(new Intent(IRemoteServiceSecondary.class.getName()),
mSecondaryConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
mCallbackText.setText("RemoteServiceBinding.");
}
private void unbindService(){
if (mIsBound) {
// If we have received the service, and hence registered with
// it, then now is the time to unregister.
if (mService != null) {
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
unbindService(mSecondaryConnection);
mIsBound = false;
mCallbackText.setText("Unbinding.");
}
}
AndroidManifest.xml
<service
android:name=".service.RemoteService"
android:process=":remote"
android:enabled="true" >
<intent-filter>
<!-- These are the interfaces supported by the service, which
you can bind to. -->
<action android:name="de.your.path.util.abstractservice.IRemoteService" />
<!-- This is an action code you can use to select the service
without explicitly supplying the implementation class. -->
<action android:name="your.action.uri.code.REMOTE_SERVICE" />
</intent-filter>
</service>

Is the Android service still alive even after the onDestroy() be called?

For studying the Android service, I wrote a test program that have three button "bind service", "unbind service" and "send echo" on the screen. When clicked, they use bindService(), unbindService() and a Messenger to communicate with the service.
Here is the service codes:
public class MessengerService extends Service {
private final Messenger mMessenger = new Messenger(new TempHandler());
private class TempHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "Hi, there.", Toast.LENGTH_SHORT).show();
break;
case MSG_SAY_GOODBYE:
Toast.makeText(getApplicationContext(), "See you next time.", Toast.LENGTH_SHORT).show();
break;
case MSG_ECHO:
Toast.makeText(getApplicationContext(), "Received " + msg.arg1 + " from client.", Toast.LENGTH_SHORT).show();
Messenger replyMessenger = msg.replyTo;
Message replyMsg = Message.obtain(null, MSG_ECHO, msg.arg1, 0);
try {
replyMessenger.send(replyMsg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
default:
super.handleMessage(msg);
}
}
}
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "Service bound", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
#Override
public void onDestroy() {
Log.d("", "Service.onDestroy()...");
super.onDestroy();
}
}
And here is the activity code:
public class MessengerActivity extends Activity {
private Messenger mMessengerService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity2);
Button bind = (Button) findViewById(R.id.button5);
bind.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
doBindService();
}
});
Button unbind = (Button) findViewById(R.id.button6);
unbind.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
doUnbindService();
}
});
Button echo = (Button) findViewById(R.id.button7);
echo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
doSendEcho();
}
});
}
private void doBindService() {
Intent intent = new Intent(getApplicationContext(), MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private void doUnbindService() {
Message msg = Message.obtain(null, MessengerService.MSG_SAY_GOODBYE);
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
unbindService(mConnection);
}
private void doSendEcho() {
if (mMessengerService != null) {
Message msg = Message.obtain(null, MessengerService.MSG_ECHO, 12345, 0);
msg.replyTo = mMessenger;
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private final Messenger mMessenger = new Messenger(new TempHandler());
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(getApplicationContext(), "Service is connected.", Toast.LENGTH_SHORT).show();
mMessengerService = new Messenger(service);
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
mMessengerService = null;
Toast.makeText(getApplicationContext(), "Service is disconnected.", Toast.LENGTH_SHORT).show();
}
};
private class TempHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessengerService.MSG_ECHO:
Toast.makeText(getApplicationContext(), "Get the echo message (" + msg.arg1 + ")", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
}
When I click "bind service" and "send echo" button. I can see the service is connected and the message communication is good. And then click "unbind service", I saw the service onDestroy() be called, so I expect the service is stopped and should not respond to the coming message again. But actually is, the service seems still alive and I could get the echo message again when click the "send echo" button. So I'm wondering is there anything I made incorrect? Or maybe I'm not fully understand about the service?
Hope someone can help, thanks.
A service is "bound" when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it.
http://developer.android.com/guide/components/services.html
A service will shut down after all bindService() calls have had their corresponding unbindService() calls. If there are no bound clients, then the service will also need stopService() if and only if somebody called startService() on the service.
Drawing from the below link.
How to check if a service is running on Android?.
private void doSendEcho() {
if(isMyServiceRunning()) // if service is running
{
if (mMessengerService != null) {
Message msg = Message.obtain(null, MessengerService.MSG_ECHO, 12345, 0);
msg.replyTo = mMessenger;
try {
mMessengerService.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MessengerService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
unbindService(mConnection);
Log.i("Stopped!",""+isMyServiceRunning());
Log.i("stopped", "Service Stopped");
}
Example:
I tested the below it works fine.
public class MessengerService extends Service {
public static final int MSG_SAY_HELLO =1;
public static final int MSG_SAY_GOODBYE =2;
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
private final Messenger mMessenger = new Messenger(new TempHandler());
private class TempHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
mClients.add(msg.replyTo);
Toast.makeText(getApplicationContext(), "Hi, there.", Toast.LENGTH_SHORT).show();
break;
case MSG_SAY_GOODBYE:
mClients.add(msg.replyTo);
break;
default:
super.handleMessage(msg);
}
}
}
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "Service bound", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
#Override
public void onDestroy() {
Log.i("MessengerService", "Service Destroyed...");
super.onDestroy();
}
}
MainAactivity.java
public class MainActivity extends Activity {
boolean mIsBound=false;
Messenger mService = null;
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MessengerService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bind = (Button) findViewById(R.id.button1);
bind.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
doBindService();
}
});
Button unbind = (Button) findViewById(R.id.button2);
unbind.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
doUnbindService();
}
});
}
class TempHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessengerService.MSG_SAY_GOODBYE:
Toast.makeText(MainActivity.this,"Received from service: " + msg.arg1,1000).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new TempHandler());
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = new Messenger(service);
// mCallbackText.setText("Attached.");
// We want to monitor the service for as long as we are
// connected to it.
try {
Message msg = Message.obtain(null,
MessengerService.MSG_SAY_HELLO);
msg.replyTo = mMessenger;
mService.send(msg);
// Give it some value as an example.
// msg = Message.obtain(null,
// MessengerService.MSG_E, this.hashCode(), 0);
// mService.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
// As part of the sample, tell the user what happened.
Toast.makeText(MainActivity.this, "remote_service_connected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
// mCallbackText.setText("Disconnected.");
// As part of the sample, tell the" user what happened.
Toast.makeText(MainActivity.this, "remote_service_disconnected",
Toast.LENGTH_SHORT).show();
}
};
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because there is no reason to be able to let other
// applications replace our component.
bindService(new Intent(MainActivity.this,
MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound=true;
Toast.makeText(MainActivity.this, "Binding",1000).show();
}
void doUnbindService() {
if (mIsBound) {
// If we have received the service, and hence registered with
// it, then now is the time to unregister.
if (mService != null) {
try {
Message msg = Message.obtain(null,
MessengerService.MSG_SAY_GOODBYE);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
Toast.makeText(MainActivity.this, "UnBinding"+isMyServiceRunning(),1000).show();
}
}
}
I personally find the terminology/nomenclature to be dissatisfying/misleading.
"onDestroy" and "stopService" might be better understood if they were called "FlagForAndroidOSDestruction" and "FlagForAndroidStopService".
If one downloads/compiles/runs any of the following examples, one can see that even when the OnHandleIntent is finished or stopService has been called, the process and even the service can still hang around! To see this simply launch the example(s) below, and then on your phone/tablet goto
Settings->Apps->Running->Show Running Services
and
Settings->Apps->Running->Show Cached Processes
When you see these, try launching a ton of other apps on the phone and THEN you'll see Android destroying said service & process.
http://developer.android.com/guide/components/services.html#ExtendingIntentService
http://android-er.blogspot.com/2013/03/stop-intentservice.html
How to check all the running services in android?
Yes, this is a conclusion drawn out of the official docs:
A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().
From http://developer.android.com/guide/components/services.html :
These two paths are not entirely separate. That is, you can bind to a service that was already started with startService(). For example, a background music service could be started by calling startService() with an Intent that identifies the music to play. Later, possibly when the user wants to exercise some control over the player or get information about the current song, an activity can bind to the service by calling bindService(). In cases like this, stopService() or stopSelf() does not actually stop the service until all clients unbind.
So you have to call unBindService() and after stopService()
This link (Do I need to call both unbindService and stopService for Android services?) says that you need to call stopService before unbindService.
Try that.

Categories

Resources