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.
Related
I implemented a Service and I use a Messenger with its handler as a communication bridge.
Every time that I start an activity I have to follow these steps:
1) create the service connection
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
try {
Message msg = Message.obtain(null, ConstantStuff.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
egoService.send(msg);
} catch (RemoteException e) {
Log.e("HELPER", "FAIL - Service crashed" + e.getMessage());
}
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
}
};
2) create the messenger
final Messenger mMessenger = new Messenger(new ActivityOne.IncomingMessageHandler());
class IncomingMessageHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ConstantStuff.MACRO_SEND_PWD:
if (msg.arg1 == 1) {
Log.e("PWD", "SUCCESS");
} else if (msg.arg1 == 0) {
Log.e("PWD", "FAIL");
}
break;
default:
super.handleMessage(msg);
}
}
}
3) bind the service to my activity
public void doBindService() {
this.bindService(new Intent(this, NetworkService.class), mConnection, Context.BIND_AUTO_CREATE);
isBound = true;
Log.e("HELPER", "DO BIND");
}
4) start using the service
private void sendPwd(String pwd) {
if (isBound) {
if (mService != null) {
try {
Bundle b = new Bundle();
b.putByte("Command", (byte) ConstantStuff.MACRO_SEND_PWD);
b.putString("Password", password);
b.putString("Param0", password);
b.putString("Param1", "dummy");
b.putString("Param2", "dummy");
b.putString("Param3", "dummy");
Message msg = Message.obtain(null, ConstantStuff.MSG_MACRO);
msg.setData(b);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (Exception e) {}
}
}
}
5) at the end of my task unbind the service from my activity
public void doUnbindService() {
if (isBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, ConstantStuff.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
Log.e("HELPER", "FAIL - DO UnBIND" + e.getMessage());
}
}
this.unbindService(mConnection);
isBound = false;
Log.e("HELPER", "DO UnBIND");
}
}
I need to communicate to my service in almost all the activities of my app and I'd like to not repeat all the code every time. Does extend all the activities to a father activity a good solution? Is it possible to write all the communication code in the "Application"?
In whichever Activities you want the service to interact with the UI, use "bindService", its callback methods "onServiceConnected" and "onServiceDisconnected" on those Activities. If you want the service to run even if app is closed, use startService with startsticky/startnonsticky/startforeground. For all the Activities you just need one service class. In your case you have already coded the service class which is perfect, and also an Activity. Now bind in rest of the Activities as mentioned in the beginning. I haven't used Messenger yet, so kindly make sure of that.
I want to create a simple app which runs in the background using a service.
Using SpeechRecognizer it would listen for application names, and when it finds existing one it would open it. Also if it does not find coincidence or the result is not clear, it would suggest some options showing them in a list or via voice.
I already know how to use SpeechRecognizer, but what I would need is to set this service to maintain running on background and avoid it from being killed. Could this be done?
In addition to all this, I'd add at least this point:
SpeechRecognizer is better for hands-free user interfaces, since your app actually gets to respond to error conditions like "No matches" and perhaps restart itself. When you use the Intent, the app beeps and shows a dialog that the user must press to continue.
My summary is as follows:
SpeechRecognizer
Show different UI or no UI at all. Do you really want your app's UI to beep? Do you really want your UI to show a dialog when there is an error and wait for user to click?
App can do something else while speech recognition is happening
Can recognize speech while running in the background or from a service
Can Handle errors better
Can access low level speech stuff like the raw audio or the RMS. Analyze that audio or use the loudness to make some kind of flashing light to indicate the app is listening
Intent
Consistent, and easy to use UI for users
Easy to program
This is a work around for android version 4.1.1.
public class MyService extends Service
{
protected AudioManager mAudioManager;
protected SpeechRecognizer mSpeechRecognizer;
protected Intent mSpeechRecognizerIntent;
protected final Messenger mServerMessenger = new Messenger(new IncomingHandler(this));
protected boolean mIsListening;
protected volatile boolean mIsCountDownOn;
private boolean mIsStreamSolo;
static final int MSG_RECOGNIZER_START_LISTENING = 1;
static final int MSG_RECOGNIZER_CANCEL = 2;
#Override
public void onCreate()
{
super.onCreate();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
mSpeechRecognizer.setRecognitionListener(new SpeechRecognitionListener());
mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
this.getPackageName());
}
protected static class IncomingHandler extends Handler
{
private WeakReference<MyService> mtarget;
IncomingHandler(MyService target)
{
mtarget = new WeakReference<MyService>(target);
}
#Override
public void handleMessage(Message msg)
{
final MyService target = mtarget.get();
switch (msg.what)
{
case MSG_RECOGNIZER_START_LISTENING:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
{
// turn off beep sound
if (!mIsStreamSolo)
{
mAudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, true);
mIsStreamSolo = true;
}
}
if (!target.mIsListening)
{
target.mSpeechRecognizer.startListening(target.mSpeechRecognizerIntent);
target.mIsListening = true;
//Log.d(TAG, "message start listening"); //$NON-NLS-1$
}
break;
case MSG_RECOGNIZER_CANCEL:
if (mIsStreamSolo)
{
mAudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, false);
mIsStreamSolo = false;
}
target.mSpeechRecognizer.cancel();
target.mIsListening = false;
//Log.d(TAG, "message canceled recognizer"); //$NON-NLS-1$
break;
}
}
}
// Count down timer for Jelly Bean work around
protected CountDownTimer mNoSpeechCountDown = new CountDownTimer(5000, 5000)
{
#Override
public void onTick(long millisUntilFinished)
{
// TODO Auto-generated method stub
}
#Override
public void onFinish()
{
mIsCountDownOn = false;
Message message = Message.obtain(null, MSG_RECOGNIZER_CANCEL);
try
{
mServerMessenger.send(message);
message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING);
mServerMessenger.send(message);
}
catch (RemoteException e)
{
}
}
};
#Override
public void onDestroy()
{
super.onDestroy();
if (mIsCountDownOn)
{
mNoSpeechCountDown.cancel();
}
if (mSpeechRecognizer != null)
{
mSpeechRecognizer.destroy();
}
}
protected class SpeechRecognitionListener implements RecognitionListener
{
#Override
public void onBeginningOfSpeech()
{
// speech input will be processed, so there is no need for count down anymore
if (mIsCountDownOn)
{
mIsCountDownOn = false;
mNoSpeechCountDown.cancel();
}
//Log.d(TAG, "onBeginingOfSpeech"); //$NON-NLS-1$
}
#Override
public void onBufferReceived(byte[] buffer)
{
}
#Override
public void onEndOfSpeech()
{
//Log.d(TAG, "onEndOfSpeech"); //$NON-NLS-1$
}
#Override
public void onError(int error)
{
if (mIsCountDownOn)
{
mIsCountDownOn = false;
mNoSpeechCountDown.cancel();
}
mIsListening = false;
Message message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING);
try
{
mServerMessenger.send(message);
}
catch (RemoteException e)
{
}
//Log.d(TAG, "error = " + error); //$NON-NLS-1$
}
#Override
public void onEvent(int eventType, Bundle params)
{
}
#Override
public void onPartialResults(Bundle partialResults)
{
}
#Override
public void onReadyForSpeech(Bundle params)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
{
mIsCountDownOn = true;
mNoSpeechCountDown.start();
}
Log.d(TAG, "onReadyForSpeech"); //$NON-NLS-1$
}
#Override
public void onResults(Bundle results)
{
//Log.d(TAG, "onResults"); //$NON-NLS-1$
}
#Override
public void onRmsChanged(float rmsdB)
{
}
}
}
As commented, I think that you don't need to use Broadcast Receiver for what you are trying to do. Instead you should define a service to be continuosly listening for speech. You can find a implementation here:
And for that about android killing services, you cannot prevent a service from being killed by the system, even system services can be killed.
Anyway, you can use the Service's startForeground() method:
By default services are background, meaning that if the system needs
to kill them to reclaim more memory (such as to display a large page
in a web browser), they can be killed without too much harm. You can
set this flag if killing your service would be disruptive to the user,
such as if your service is performing background music playback, so
the user would notice if their music stopped playing.
You can see the implementation here.
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>
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.
I am implementing an application which is kind of VOIP application. So my application is kind of network application. Now I want to implement two part in my application, one is GUI part and one is network part. My GUI part will just contain activities and handling of user interaction. My Network part should handle all network related activities like handling incoming network data and sending data to network based on GUI interaction. Now whenever there is any incoming data, I want to update some activity whose reference is not there in Network module. So what could be the best way to update activity from some other class? In my case some other class is my Network class. So in short I would like to ask that what should be the architecture in such scenario? i.e. Network part should run in separate thread and from there it should update GUI?
Depending on the type/size of data you need to send to the activity, you can use one of a number of options.
Use one of the methods described here.
Use a BroadcastReceiver: register it in the Activity and then fire off matching Intents in the Service that handles the networking code.
Make your Activity bind to your Service and then pass in a Handler that you send Messages to.
I have written apps like this, and I prefer the Handler method. In fact I have written an Abstract Activity class to do all the hard work and simply extend it in any activity that want to be notified of a change.
To Use the following code, just get your Activity to extend UpdatableActivity and override the dataUpdated() method. This method is called when your Service notifies the handler that data has been updated. In the Service code put your code to do an update in the update() method (Or modify to call your existing code). This allows an activity to call this.updateService() to force an update. The service can call the sendMessageToUI() method to notify all interested activities that the data has been updated.
Here is what the abstract activity looks like:
public abstract class UpdatableActivity extends Activity {
public static final String TAG = "UpdatableActivity (Abstract)";
private final Messenger mMessenger = new Messenger(new IncomingHandler());
private Messenger mService = null;
private boolean mIsBound;
protected class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
if (Constants.LOG_DEBUG) Log.d(TAG, "Service has notified us of an update: ");
switch (msg.arg1) {
case UpdateService.MSG_DATA_UPDATED:
dataUpdated();
break;
default: super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
try {
Message msg = Message.obtain(null, UpdateService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been unexpectedly disconnected - process crashed.
mService = null;
}
};
/**Override this method in you acctivity to handle the update */
public abstract void dataUpdated();
void doBindService() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Binding to service...");
bindService(new Intent(this, UpdateService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
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, UpdateService.MSG_UNREGISTER_CLIENT);
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;
}
}
public void updateService() {
if (Constants.LOG_DEBUG) Log.d(TAG,"Updating Service...");
if (mIsBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, UpdateService.MSG_SET_INT_VALUE, UpdateService.MSG_DO_UPDATE, 0);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
if (Constants.LOG_ERROR) Log.e(TAG,Log.getStackTraceString(e));
}
}
} else {
if (Constants.LOG_DEBUG) Log.d(TAG, "Fail - service not bound!");
}
}
pu
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.doBindService();
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
doUnbindService();
} catch (Throwable t) {
if (Constants.LOG_ERROR) Log.e(TAG, "Failed to unbind from the service", t);
}
}
}
And here is what the Service looks Like:
public class UpdateService extends Service {
public static final String TAG = "UpdateService";
public static final int MSG_DATA_UPDATED = 0;
public static final int MSG_REGISTER_CLIENT = 1;
public static final int MSG_UNREGISTER_CLIENT = 2;
public static final int MSG_DO_UPDATE = 3;
public static final int MSG_SET_INT_VALUE = 4;
private static boolean isRunning = false;
private Handler handler = new IncomingHandler();
private final Messenger mMessenger = new Messenger(handler);
private ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_INT_VALUE:
switch (msg.arg1) {
case MSG_DO_UPDATE:
if (Constants.LOG_DEBUG) Log.d(TAG,"UI has asked to update");
update();
break;
}
break;
default:
super.handleMessage(msg);
}
}
}
private void sendMessageToUI() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Notifying "+mClients.size()+" UI clients that an update was completed");
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, MSG_DATA_UPDATED, 0));
} catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
public static boolean isRunning()
{
return isRunning;
}
#Override
public void onCreate() {
super.onCreate();
isRunning = true;
if (Constants.LOG_DEBUG) Log.d(TAG, "Service Started");
update();
}
#Override
public void onDestroy() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Service Destroyed");
isRunning = false;
}
private void update() {
/**Your code to do an update goes here */
}
}
Yes, personally i think that the network and UI should be in separate threads. The way I tend to communicate between the two, which is probably not the recommended proper way, but it works for me, is to create a global variable in your application class. hope this helps a little
I would directly post to the main UI thread,
Handler mHandler = new Handler(Looper.getMainLooper());
mHandler.post(new Runnable() {...});