I want to develop two apps. I need an app able to start and stop a second app. To do this I set up a messenger between these two apps using a service. The service is sticked to the second app.
I initialized the intent like this in app1:
protected void onCreate()
{
super.onCreate();
Intent mIntent = new Intent();
mIntent.setAction("com.package.service");
bindService(mIntent, mServiceConnection, BIND_AUTO_CREATE);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName arg0) {
mIsBinded=false;
mServiceConnection=null;
}
#Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
mIsBinded=true;
mMessenger = new Messenger(arg1);
}
};
And I send a message to Close the app2.
In app2 I have a service like this:
public class RemoteServiceClient extends Service
{
static final int STOP = 0;
static final int CONTINUE = 1;
private static final String TAG ="service" ;
class MyHandler extends Handler
{
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch(msg.what)
{
case STOP:
sendBroadcast(new Intent("stop"));
Log.d(TAG,"stopapp");
break;
case CONTINUE:
break;
}
}
}
Messenger mMessenger = new Messenger(new MyHandler());
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return mMessenger.getBinder();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
return Service.START_STICKY;
}
}
and I also put in manifest inside application:
<service android:name="com.package.app.service"
android:process=":exported">
<intent-filter>
<action android:name="com.package.service" />
</intent-filter>
</service>
In activity of app2 I put a braodcast receiver that when the message STOP is delivered the app calls finish() .
The problem I have is that the first time the messanger delivers the message and reboot the app2. Once app2 is reboot the app1 cannot be able to stop app2 again. I get this error:
05-04 15:47:28.168 16741-16755/com.package.app1 W/System.err: android.os.DeadObjectException
05-04 15:47:28.178 16741-16755/com.package.app1 W/System.err: at android.os.BinderProxy.transact(Native Method)
Related
Hi in project I'm using service for chat communication using SignalR. Chat communication is working fine but when the app goes to background the service got stopped I need to run the services fully till my app get deleted
Here is me service code
public class SignalRService extends Service {
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler; // to display Toast message
private final IBinder mBinder = new LocalBinder(); // Binder given to clients
public SignalRService() {
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
startSignalR();
return result;
}
#Override
public void onDestroy() {
Log.i("onDestroy","onDestroy");
mHubConnection.stop();
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// Return the communication channel to the service.
startSignalR();
return mBinder;
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
public SignalRService getService() {
// Return this instance of SignalRService so clients can call public methods
return SignalRService.this;
}
}
/**
* method for clients (activities)
*/
public void sendMessage(String message) {
String SERVER_METHOD_SEND = "Send";
mHubProxy.invoke(SERVER_METHOD_SEND, message);
}
/**
* method for clients (activities)
*/
public void sendMessage_To(String receiverName, String message) {
String SERVER_METHOD_SEND_TO = "SendChatMessage";
mHubProxy.invoke(SERVER_METHOD_SEND_TO, receiverName, message);
}
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
Credentials credentials = new Credentials() {
#Override
public void prepareRequest(Request request) {
request.addHeader("User-Name", "BNK");
}
};
String serverUrl = "http://10.10.10.180/signalr/hubs";
mHubConnection = new HubConnection(serverUrl);
mHubConnection.setCredentials(credentials);
String SERVER_HUB_CHAT = "ChatHub";
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
Log.e("SimpleSignalR", e.toString());
return;
}
sendMessage("Hello from BNK!");
String CLIENT_METHOD_BROADAST_MESSAGE = "broadcastMessage";
mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler1<CustomMessage>() {
#Override
public void run(final CustomMessage msg) {
final String finalMsg = msg.UserName + " says " + msg.Message;
// display Toast message
mHandler.post(new Runnable() {
#Override
public void run() {
Log.i("message","message: "+finalMsg);
Toast.makeText(getApplicationContext(), finalMsg, Toast.LENGTH_SHORT).show();
}
});
}
}
, CustomMessage.class);
}}
And here is the activity code
public class MainActivity extends AppCompatActivity {
private final Context mContext = this;
private SignalRService mService;
private boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(mContext, SignalRService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
// Unbind from the service
Log.i("onStop","onStop");
if (mBound) {
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
public void sendMessage(View view) {
if (mBound) {
// Call a method from the SignalRService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
EditText editText = (EditText) findViewById(R.id.edit_message);
EditText editText_Receiver = (EditText) findViewById(R.id.edit_receiver);
if (editText != null && editText.getText().length() > 0) {
String receiver = editText_Receiver.getText().toString();
String message = editText.getText().toString();
mService.sendMessage_To(receiver, message);
mService.sendMessage(message);
}
}
}
/**
* Defines callbacks for service binding, passed to bindService()
*/
private final ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to SignalRService, cast the IBinder and get SignalRService instance
SignalRService.LocalBinder binder = (SignalRService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.i("onServiceDisconnected","onServiceDisconnected");
mBound = false;
}
};}
My manifest code for service
<service
android:name=".SignalRService"
android:enabled="true"
android:exported="true" >
</service>
Plese help me on this
If you bind the service with any component the system will automatically destroy the service if no other client is bound with it.
If you want to run a service independently then you have to start a service rather than bind. But you can't communicate with a service if you start it with startService()
For more details you can see the documentation here
You can BOTH start AND bind the service.
In this way, even if multiple components bind to the service at once, then ALL of them unbind, the service will NOT be destroyed. Refer to A service can essentially take two forms: Bound
your service can work both ways: it can be started (to run indefinitely) and also allow binding. It's simply a matter of whether you implement a couple callback methods: onStartCommand() to allow components to start it and onBind() to allow binding.
// onBind method just return the IBinder, to allow clients to get service.
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// onStartCommand just return START_STICKY to let system to
// try to re-create the service if the servcie's process is killed.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
// and make startSignalR public to allow client to call this method.
public void startSignalR() {
}
In your clients, no need to keep a boolean mBound.
Just bind service when onCreate, unbind service when onDestroy. DO NOT unbind when onStop. Since onStop may called many times, for example dialog popup will invoke onStop, but your activity is still on foreground, this will cause your service destroyed.
Refer to my answer for question: Pass Service From one Activity to Another for sample code.
Issues
Service is NOT running always even after I have used START_STICKY.
Sometimes I dont get any Toast Action for Outgoing call, is that mean service stops after some time ?
My Requirment
Application shows a Toast whenever user makes a outgoing call from the phone. For this I am using a BroadcastReceiver to tap the call action and a service (to run Receiver always). once I start this activity, it starts showing toast when a outgoing call get initiated ..but not Always.
Below is the complete code -
MainActivity.class
public class MainActivity extends Activity
{
CallNotifierService m_service;
boolean isBound = false;
private ServiceConnection m_serviceConnection = new ServiceConnection()
{
#Override
public void onServiceConnected(ComponentName className, IBinder service)
{
m_service = ((CallNotifierService.MyBinder)service).getService();
Toast.makeText(MainActivity.this, "Service Connected", Toast.LENGTH_LONG).show();
isBound = true;
Intent intent = new Intent(MainActivity.this, CallNotifierService.class);
startService(intent);
}
#Override
public void onServiceDisconnected(ComponentName className)
{
m_service = null;
isBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, CallNotifierService.class);
bindService(intent, m_serviceConnection, Context.BIND_AUTO_CREATE);
}
.
.
.
}
CallNotifierService.class
public class CallNotifierService extends Service
{
private final IBinder myBinder = new MyBinder();
private static final String ACTION_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
private CallBr br_call;
#Override
public IBinder onBind(Intent arg0)
{
return myBinder;
}
#Override
public void onDestroy()
{
Log.d("service", "destroy");
this.unregisterReceiver(this.br_call);
Toast.makeText(CallNotifierService.this, "Receiver Un-Registered", Toast.LENGTH_LONG).show();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_OUTGOING_CALL);
this.br_call = new CallBr();
this.registerReceiver(this.br_call, filter);
Toast.makeText(CallNotifierService.this, "onStartCommand Called", Toast.LENGTH_LONG).show();
return START_STICKY;
}
public class MyBinder extends Binder
{
CallNotifierService getService()
{
return CallNotifierService.this;
}
}
public class CallBr extends BroadcastReceiver
{
public CallBr() {}
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Action:"+intent.getAction(), Toast.LENGTH_LONG).show();
}
}
}
You are getting the wrong approach here, by mixing a simple idea (that would work if done correctly) with more complicated ideas (that cannot work).
Keep in mind: services are not "always running" components, even when using START_STICKY.
The Android system will not hesitate to kill your service if it needs memory somewhere else. START_STICKY only means that the Android system will re-start your service when it can, calling onStartCommand as specified in the documentation.
If you need a service to really stick around, then you must use a foreground service. But it will have consequences on the UI (annoying notification icon always showing), and battery life, and you do not need this here.
Now here is the magic trick: your app does not need to be running for your BroadcastReceiver to work. All you need to do is to register it in your AndroidManifest.xml with the correct intent-filter:
<receiver android:name=".broadcastreceivers.CallBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
(also make sure your app has the required permissions, namely PROCESS_OUTGOING_CALLS).
Then all you need in code is:
public class CallBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Action: " + intent.getAction(), Toast.LENGTH_LONG).show();
}
}
No activity (except to ask for the PROCESS_OUTGOING_CALLS permission on Android 6+), no service, nothing. Simple and battery-efficient !
The service does get re-created, not not re-started.
If you override the onCreate and do a Log.d or a Toast, you will see that it gets called after your app is destroyed.
So the trick to keep it running after it is recreated is to do your code on the onCreate method and use the onStartCommand just to return START_STICKY.
i am looking for a fast way to get the data from the listeners, which are in my service, to an activity.
I tried it with variables where i store the current value and read it in the activity, but this is to slow!
I start my service from an activity. I read that it's possible to start a service independently of an activity and bound from an activity to this service too. Could this be a slution? How would it look like?
Here is a part of my service:
public class DataService extends Service {
private VehicleManager mVehicleManager;
public int onStartCommand(Intent intent, int flags, int startId) {
context = getApplicationContext();
Intent intent1 = new Intent(this, VehicleManager.class);
bindService(intent1, mConnection, Context.BIND_AUTO_CREATE);
startThreadUpdatingDatabase();
return Service.START_NOT_STICKY;
}
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mVehicleManager = ((VehicleBinder) service).getService();
mVehicleManager.addListener(EngineSpeed.class, engineSpeedListener);
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
};
EngineSpeed.Listener engineSpeedListener = new EngineSpeed.Listener() {
public void receive(Measurement measurement) {
final EngineSpeed data = (EngineSpeed) measurement;
new Thread(new Runnable() {
public void run() {
Double engineSpeedValue = data.getValue().doubleValue();//i want this value using in an activity!!
}
}).start();
}
};
}
It's not the best way to do it, but try this one :
Add an update(double value) method in your activity.
Pass the context to your service when starting it and add this after :
Double engineSpeedValue = data.getValue().doubleValue(); // I want this value used in an activity!!
(YourAcitvityName) context).update(engineSpeedValue);
I have a service Class in android. Is it be possible for a Service to run as a separate process than an application just for receiving SMS and enqueue them in a queue after that an application reads SMS from this Queue.
Is it possible to launch a separate service?
I have tag the source code of SmsService class below
public class SmsService extends Service {
private SMSReceiver mSMSreceiver;
private IntentFilter mIntentFilter;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public SmsService(){
/*dba = new DataBaseAdapter(this);*/
mSMSreceiver = new SMSReceiver();
}
#Override
public void onCreate(){
super.onCreate();
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(ConstantClass.SMS_RECEIVED);
registerReceiver(mSMSreceiver,mIntentFilter);
}
#Override
public int onStartCommand(Intent intent , int flags, int type){
return START_STICKY;
}
#Override
public void onDestroy(){
super.onDestroy();
//unregisterReceiver(mSMSreceiver);
}
To enroll your service in a different process, you need to define android:process attribute when defining your service in AndroidManifest.xml
For example:
<service android:process=":kaushik" />
This will run your service in a new process called kaushik.
Hy i have a problem to set the ServiceUpdateUIListener in the service to update the UI. It's wrong to make a new Service object and set there the listener and put it in an intent.
Code source is at http://developerlife.com/tutorials/?p=356 there i can't find how the set the listener and start the service right.
Calling:
TimerService service = new TimerService();
TimerService.setUpdateListener(new ServiceUpdateUIListener() {
#Override
public void updateUI(String time) {
clock.setText(time);
}
});
Intent i = new Intent(Timer.this,service.class); //service cannot be resolved to a type
i.putExtra("ms", ms);
startService(i);
Service:
public class TimerService extends Service{
CountDownTimer timer;
Chronometer clock;
public static ServiceUpdateUIListener UI_UPDATE_LISTENER;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
int ms = intent.getIntExtra("ms", 0);
timer = new CountDownTimer(ms,1000){
#Override
public void onTick(long millisUntilFinished) {
int seconds = (int) (millisUntilFinished / 1000) % 60 ;
int minutes = (int) ((millisUntilFinished / (1000*60)) % 60);
int hours = (int) ((millisUntilFinished / (1000*60*60)) % 24);
clock.setText( String.format("%02d:%02d:%02d", hours,minutes,seconds));
Log.e("Timer", String.valueOf(millisUntilFinished));
}
#Override
public void onFinish() {
// TODO Auto-generated method stub
}
}.start();
super.onStart(intent, startId);
}
public static void setUpdateListener(ServiceUpdateUIListener l) {
UI_UPDATE_LISTENER = l;
}
The Service documentation has fairly complete sample code for implementing a service in your app that another part of your app can bind to and make calls on:
http://developer.android.com/reference/android/app/Service.html#LocalServiceSample
Just put your setUpdateListener() method on the Service, and call it once you get onServiceConnected() with the service.
So your code would be something like this:
public interface UpdateListener {
public void onUpdate(long value);
}
class LocalService {
// Like in the Service sample code, plus:
public static String ACTION_START = "com.mypackage.START";
private final ArrayList<UpdateListener> mListeners
= new ArrayList<UpdateListener>();
private final Handler mHandler = new Handler();
private long mTick = 0;
private final Runnable mTickRunnable = new Runnable() {
public void run() {
mTick++;
sendUpdate(mTick);
mHandler.postDelayed(mTickRunnable, 1000);
}
}
public void registerListener(UpdateListener listener) {
mListeners.add(listener);
}
public void unregisterListener(UpdateListener listener) {
mListeners.remove(listener);
}
private void sendUpdate(long value) {
for (int i=mListeners.size()-1; i>=0; i--) {
mListeners.get(i).onUpdate(value);
}
}
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_START.equals(intent.getAction()) {
mTick = 0;
mHandler.removeCallbacks(mTickRunnable);
mHandler.post(mTickRunnable);
}
return START_STICKY;
}
public void onDestroy() {
mHandler.removeCallbacks(mTickRunnable);
}
Now you can start the service to get it to start counting, and anyone can bind to it to register a listener to receive callbacks as it counts.
It is really hard though to answer your question very well because you aren't really saying what you actually want to accomplish. There are a lot of ways to use services, either starting or binding or mixing the two together, depending on exactly what you want to accomplish.
Now you can implement your client code again based on the sample:
public class SomeActivity extends Activity implements UpdateListener {
private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mBoundService = ((LocalService.LocalBinder)service).getService();
mBoundService.registerListener(this);
}
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
}
};
void doBindService() {
bindService(new Intent(Binding.this,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
if (mBoundService != null) {
mBoundService.unregisterListener(this);
}
unbindService(mConnection);
mIsBound = false;
}
}
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
I don't know exactly what you want, but this is not the way to do it. It seems you're mixing up a lot of things.
The tutorial itself is a bad example to my opinion, keeping a static reference to an activity in a service seems to me bad practice; you would use binding to bind your service to an activity, or if you don't want to you can pass Intents around.
As far as I know instantiating a service like you do and setting a listener on it like that doesn't work. You get an error in the startService() call because the service instance isn't a class obviously; you should use TimerService.class instead. In your service you have an onStart(); onStart() is a deprecated function, you should use onStartCommand() instead.
Now, if you have an activity in which you want to show a clock you don't need nor want the service to update its UI directly of course, but if you'd want the service to calculate a new clock tick for you, just call startService(); As long as your service is alive, sending a new start service intent will just call the onStartCommand() with the intent you're sending along.
If your clock is in an activity, setup a broadcast receiver inside your activity that and let your service broadcast an intent that can be received by the broadcast receiver you setup, with your new clock value passed along.
MrJre is correct that onStart is depreciated and that you should be using onStartCommand().
If you want to get this to work, there is a better way.
I am doing something similar, as in wanting to update a UI from results happening in a service. This was not particularly easy. (In my opinion)
Here's how to do it: (First off scrap your existing code)
In UI class add:
public Intent service;
service = new Intent(thisContext, TimerService.class);
service.putExtra("ms", ms);
startService(service);
//bind service to the UI **Important**
bindService();
IntentFilter timerFilter = new IntentFilter("TimerIntent"); // Filter that gets stuff from the service
registerReceiver(myReceiver, timerFilter);
void bindService() {
Intent newIntent = new Intent(this, TimerService.class);
bindService(newIntent, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder binder) {
s = ((TimerService.MyBinder) binder).getService();
}
#Override
public void onServiceDisconnected(ComponentName className) {
s = null;
}
};
public void releaseBind() {
if (mIsBound) {
unbindService(mConnection);
mIsBound = false;
}
}
// Now in this class we need to add in the listener that will update the UI (the receiver registered above)
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
//Get Bundles
Bundle extras = intent.getExtras();
/* DO ANY UI UPDATING YOU WANT HERE (set text boxes, etc.) TAKING INFO FROM THE "extras" Bundle ie: setting the clock*/
//ie: int timerTest = extras.getInt("0");
// Now update screen with value from timerTest
}
};
Service File:
public class TimerService extends Service {
public TimerService () {
super();
}
private final IBinder mBinder = new MyBinder();
public Timer clockTimer = new Timer();
public int timer = 0;
// We return the binder class upon a call of bindService
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// After service starts this executes
Bundle extras;
extras = intent.getExtras();
/* Call a function to do stuff here. Like if you are a clock call a timer function updates every second */
// Here's an example, modify to fit your needs.
clock();
return START_STICKY;
}
public class MyBinder extends Binder {
TimerService getService() {
return TimerService.this;
}
}
public void clock() {
clockTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
try {
// Some function ie: Time = Time + 1 //
/* MAKE SURE YOU BROADCAST THE RECEIVER HERE. This is what you send back to the UI. IE:*/
timer = timer+ 1; // increment counter
Intent intent = new
//Bundle the timervalue with Intent
intent.putExtra("0", timer);
intent.setAction("TimerIntent");
sendBroadcast(intent); // finally broadcast to the UI
} catch(Exception ie) {
}
}
},
0, // Delay to start timer
1000); // how often this loop iterates in ms (so look runs every second)
}
There might be some syntax errors in this code as I've just modified my existing and working code to try and fit your needs. There will obviously need to also be some modifications depending on what you want to do. But follow this framework and you will be able to do what you are trying to do.
This works for me, so hopefully you can modify this to work for you. (Only thing I've left out are the imports, but you should be able to easily figure that out)
Key points:
Bind service to UI
Register listener in UI file to respond to the broadcast from inside the service.
Cheers.