stopService and stop get message - java

I Want to stop my service and stop get data to ma handler which I have in activity. And service I connect to USB and get data from this port.
I try did this:
usbService.stopSelf();
Intent intent = new Intent(MainMenu.this, UsbService.class);
usbService.stopService(intent);
but all the time I have a data from service.
I start my service just like this:
private void startService(Class<?> service, ServiceConnection serviceConnection, Bundle extras) {
if (!UsbService.SERVICE_CONNECTED) {
Intent startService = new Intent(this, service);
if (extras != null && !extras.isEmpty()) {
Set<String> keys = extras.keySet();
for (String key : keys) {
String extra = extras.getString(key);
startService.putExtra(key, extra);
}
}
startService(startService);
}
Intent bindingIntent = new Intent(this, service);
bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}

You need to unbind your service first, by calling unBindService.
As you can see in the Service documentation:
Note that if a stopped service still has ServiceConnection objects
bound to it with the BIND_AUTO_CREATE set, it will not be destroyed
until all of these bindings are removed. See the Service documentation
for more details on a service's lifecycle.
you need to unbind all objects bound to the service before stopping it in order to destroy the service.
EDIT: Answer to your question. Add a boolean variable mBound. Override these methods.
public void onServiceConnected(ComponentName className, IBinder service) {
mBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
In your activity's onStop method, add this:
#Override
public void onStop()
{
super.onStop();
if (mBound) {
try {
unbindService(mConnection);
} catch (java.lang.IllegalArgumentException e)
{
//handle exception here
}
}
mBound = false;
}

Related

Android Request to server before application compeletly closed

I have just one Activity , when user close the application (from os clear list of recent apps) I want to send a request to my server api and change user status.
so I make IntentService and call it in my onDestroy() method of activity, but it dosn't work. how do it? is there any way else to do this(send request to server before application killed compeletly)?
my code :
Activity:
#Override
protected void onDestroy() {
Intent intent = new Intent(this, MakeOfflineIntentService.class);
intent.putExtra(Variables.INTENT_TOKEN, Token);
intent.setAction("ACTION_MAKE_OFFLINE");
startService(intent);
super.onDestroy();
}
and in my IntentService:
public class MakeOfflineIntentService extends IntentService {
private static final String ACTION_MAKE_OFFLINE = "ACTION_MAKE_OFFLINE";
private static final String EXTRA_TOKEN = Variables.INTENT_TOKEN;
public MakeOfflineIntentService() {
super("MakeOfflineIntentService");
}
public static void startActionFoo(Context context, String param1) {
Intent intent = new Intent(context, MakeOfflineIntentService.class);
intent.setAction(ACTION_MAKE_OFFLINE);
intent.putExtra(EXTRA_TOKEN, param1);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_MAKE_OFFLINE.equals(action)) {
final String param1 = intent.getStringExtra(EXTRA_TOKEN);
retrofitBaseInformationChange(param1,Variables.OFFLINE,1);
}
}
}
private void retrofitBaseInformationChange(final String Token, final int online, int vehicle){
RetrofitCallServer retrofitCallServer = new RetrofitCallServer(WebServiceUrls.RETROFIT_INFORMATION_CHEETAH_MAN);
OnCallBackRetrofit onCallBackRetrofit = retrofitCallServer.getResponse();
Call<OBRbaseInfromationChange> call = onCallBackRetrofit.askBaseInformationChange(Token,online,vehicle);
call.enqueue(new Callback<OBRbaseInfromationChange>() {
#Override
public void onResponse(Call<OBRbaseInfromationChange> call, Response<OBRbaseInfromationChange> response) {
/*response gotten maybe success or not*/
if (response.isSuccessful()){
OBRbaseInfromationChange obr = response.body();
if(obr.code == 200){
Log.i(Variables.APP_TAG,"BaseInformationChange successful");
}
else{
Log.i(Variables.APP_TAG,"BaseInformationChange error code: "+obr.code);
}
}// end if response successful
else {
Log.i(Variables.APP_TAG,"BaseInformationChange not Successful: "+response.code());
}
}
#Override
public void onFailure(Call<OBRbaseInfromationChange> call, Throwable t) {
/*our request not sent or conversion problem*/
Log.i(Variables.APP_TAG,"onFailure BaseInformationChange: "+t.getMessage());
}
});
}
// end retrofitBaseInformationChange()
}
and finally here is in my manifest:
<service
android:name=".Services.MakeOfflineIntentService"
android:exported="false"
android:stopWithTask="false"/>
Have you tried to return START_STICKY in the onStartCommand override?
After you sent your request you can then call stopService to stop yourself.
As far as I know, even sticky services might be "recreated" when you kill the app. So maybe, an Intent is not the best way to use here.
I'd go with SharedPreferences here:
The onCreate of your app sets the key "app_offline" to "false"
The onDestroy sets this key to "true" and starts the service
The service is START_STICKY and when it finds the "app_offline" as true, sends its request, updates "app_offline" to false (resets it) and then performs a self-shutdown.
Something like that.
Hope this helps, cheers, Gris
thanks for Grisgram answer, I solve the issue and paste my code here for more complete answer :
I make a variable in SharedPreferences name IS_APP_CLOSED.
when application open in onCreate :
saveL.saveInLocalStorage(Variables.IS_APP_CLOSED,false);
startServiceToMakeOffline();
method startServiceToMakeOffline() is :
private void startServiceToMakeOffline(){
Intent intent= new Intent(this, MakeOfflineService.class);
startService(intent);
}
in onDestroy of this activity :
#Override
protected void onDestroy() {
saveL.saveInLocalStorage(Variables.IS_APP_CLOSED,true);
super.onDestroy();
}
and here is my service class :
public class MakeOfflineService extends Service {
private boolean isAppClosed = false;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
loadInfoFromLocalStorage();
if(isAppClosed){
askServer();
}
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void loadInfoFromLocalStorage() {
SharedPreferences prefs = getApplicationContext().getSharedPreferences(Variables.CHEETAH_NORMAL, 0);
isAppClosed = prefs.getBoolean(Variables.IS_APP_CLOSED, false);
prefs = null;
}
// end loadInfoFromLocalStorage()
private void askServer() {
//TODO: request server than when result gotten:
stopSelf();
}
}
and here is my manifest :
<service
android:name=".Services.MakeOfflineService"
android:stopWithTask="false"/>

How does a service notify an activity class by sending an object and calling a method from that activity with the sent object?

I am aware of the BroadCastReceiver, but how can I use it to call a method in my activity. So if I get a notification from my service, a button in my UI turns red, and red being the object that has been sent from the service and turning red the method that has been called by the activity.
sorry for bad english :)
Register a BroadcastReceiver in your activity
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
if (message.equals("eventOne"))
{
//do something
}
else if (message.equals("eventTwo"))
{
//do something else
}
}
};
Override onResume and onDestroy of your activity
#Override
protected void onResume()
{
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
}
#Override
protected void onDestroy()
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
To check if your service is running add the following on your activity
private static boolean isServiceRunning(String serviceName, Context context)
{
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
{
if (serviceName.equals(service.service.getClassName()))
{
return true;
}
}
return false;
}
Call it like this
boolean isServiceRunning = isServiceRunning(MyService.class.getName(), this.getApplicationContext());
if (!isServiceRunning)
{
Intent startMyServiceIntent = new Intent(this.getApplicationContext(), MyService.class);
startService(startMyServiceIntent);
}
Finally on your service add a method like that and call it whenever you want
private void sendMessage(String event)
{
Intent intent = new Intent("my-event");
intent.putExtra("message", event);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
sendMessage("eventOne");
return START_STICKY;
}
And don't forget to add your service to manifest
<application
...
...
<service android:name=".MyService"/>
</application>
You can use a BroadcastReceiver, an event bus or an observable. In your activity, listen for the event and call a method that updates your UI how you want.
I do something similarly for GCM intent service. I use an rxBus that posts when the service is triggered. My activity subscribes to the bus and reacts when it sees the post.

Stop/Pause/Sleep Service if connection unavailable and resume if available

I have an application in which I have created a service MyService.class
Now MyService.class is tied to my activity using bindService() but I want my service to run in the background even if activity destroys itself.
So I started the service and then bind it like below:
private void doBindService() {
if (!isServiceBound){
Log.d(LOG_TAG, "Binding Service...");
if (mBtAdapter != null && mBtAdapter.isEnabled()){
Intent intent = new Intent(MyActivity.this, MyService.class);
startService(intent);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
}
}
In MyActivity's onDestroy method I am unbinding the service
Now my service is running smoothly until the connection with the remote device breaks. I want to pause/sleep/stop this service if connection breaks, then after every 60 seconds it tries to start the service/connection.
I have tried this but doesn't work.
private void stopService() {
doUnbindService();
stopService(new Intent(MyActivity.this, MyService.class));
startService(new Intent(MyActivity.this, MyService.class));
}
Please any help will be much appreciated. Thanks in advance!!!
Try this
create a method that perform the Operation you want
create a Thread or Runnable class
Call the Helper method you created in the run() of the Thread or Runnable
Inside the Service onStartCommand start the Thread if connection is available
thread.wait/sleep if no connection
I'm not sure I have understanding your request.
With this solution you can play, pause and stop service.
And the service do some work every 60seconds
public class MyService extends Service {
public static boolean testConnexion;
private Timer timer;
#Override
public void onCreate() {
super.onCreate();
timer = null;
testConnexion = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (timer != null) {
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (testConnexion) {
//StartConnexion
}
}
}, 1000, 60000);
}
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
}
}
In Any activity
To start or stop service.
(Your can call startService many times as you want, there will be just one who will run.)
if (v.getId() == R.id.startService) {
Intent intent = new Intent(this, MyService.class);
startService(intent);
} else if (v.getId() == R.id.stopService) {
Intent intent = new Intent(this, MyService.class);
stopService(intent);
}
To pause action (but not kill the service)
MyService.testConnexion = false;
And for restarting
MyService.testConnexion = true;
Your service is not related to your activity.
If your killing your activity, your service continues to run.
I hope this can help you

Send data to activity from already running sticky service

I created sticky background service, that should be started on boot:
public class AutostartReceiver extends BroadcastReceiver
{
public AutostartReceiver()
{
}
#Override
public void onReceive(Context context, Intent intent)
{
context.startService(new Intent(context, MyService.class));
}
}
My service is intended to do some work in background, it's implemented by creating thread for this. Also there is Messenger class used for sending work status to my main activity:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.i(TAG, "Service onStartCommand " + startId);
final int currentId = startId;
Messenger callback = null;
if(intent!=null)
{
callback = intent.getParcelableExtra("messenger");
}
final Messenger finalCallback = callback;
Runnable r = new Runnable()
{
public void run()
{
... do something, then stop
stopSelf();
}
};
if(t == null)
{
t = new Thread(r);
t.start();
}
return Service.START_STICKY;
}
Main activity receives messages sent from background thread running inside my service (some commands, that service is sending periodically:
Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case 0:
Toast.makeText(MainActivity.this,"Service runing", Toast.LENGTH_LONG).show();
break;
}
}
};
This works only if I start my service from activity, with activity's context. Obviously, if service is started on boot, or my app was closed (removed from last app list) and opened again, my activity is unable to get any messages from service any more.
If I invoke start service while service is already running, it will simply run OnStartCommand again, so either new thread will be created (I don't want it) or I need to destroy running thread and run thread again.
Is there any way to get my activity receiving messages from service, without actually touching already running thread inside it? I know about bound services, but it's not clear for me how to use them in my specific case.
As Alternate way You can use LocalBroadcastManager to send Data from Service to Activity.
Broadcast Your message from Service:
private void broadcastMessage(Context context){
Intent intent = new Intent("UI_UPDATE_BROADCAST");
intent.putExtra("MESSAGE", "MyMessage");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
Register Broadcast Receiver in your activity to receive messages:
#Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(mContext).registerReceiver(mMessageReceiver, new IntentFilter("UI_UPDATE_BROADCAST"));
}
#Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mMessageReceiver);
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Do Something With Received Data
String msg = intent.getStringExtra("MESSAGE");
}
};
I would use a broadcast receiver for Service-to-Activity communication.
Code:
public class MyActivity extends Activity {
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Toast here
}
#Override
protected void onCreate(Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter("message-name"));
}
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
super.onDestroy();
}
}
Then in your service you would broadcast the message like this:
Intent intent = new Intent("message-name");
intent.putExtra("data", 1);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

Accessing context from another thread

I am starting to migrate some PC Java applications to Android environments being a complete newbie concerning Android platform.
I found a problem when I tried to use a Service reference as context for a Toast message.
This is the relevant part of my Service code:
public class ServicePFPE extends Service {
Timer messageSimulator;
TimerTask messagePoll;
private class MessageReceptionTask extends TimerTask
{
public MessageReceptionTask(Context c) {
context = c;
}
#Override
public void run() {
String shownText = "Message received!! on " + (new Date(System.currentTimeMillis())).toString();
//doToast(shownText, context); //THIS LINE MAKES THE APP CRASH!
System.out.println(shownText); //But I can do this
}
private Context context;
}
public ServicePFPE() {
super();
messageSimulator = new Timer();
messagePoll = new MessageReceptionTask(this);
}
#Override
public IBinder onBind(Intent intent)
{
doToast("Service: onBind");
return null;
}
...
...
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doToast("Service: onStartCommand");
messageSimulator.schedule(messagePoll, 5000, 5000);
return super.onStartCommand(intent, flags, startId);
}
...
...
...
private void doToast(String msg) { doToast(msg, this); }
private void doToast(String msg, Context con) {
Toast.makeText(con,msg,Toast.LENGTH_SHORT).show();
}
}
When the scheduled task runs reaching doToast call Android notifies that "Unfortunatelly, myAPP has stopped".
I think it has something to do with the fact I am using the service context in a different thread but I don't know for sure.
Could you confirm if that is the case? What is the right way to run a timer from a service and be able to use its context? If that is not possible, can I get a context for that thread so I can generate Toasts user messages.
It depends on what you really need, if you are planning to show simple notifications, maybe instead of toasts you can use Android notification bar (which is the standard way to show them). For example you can use:
/**
* Show a notification while this service is running.
*/
private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.local_service_started);
NotificationManager mNM;
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.stat_sample, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, LocalServiceActivities.Controller.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.local_service_label),
text, contentIntent);
// Send the notification.
mNM.notify(NOTIFICATION, notification);
}
however, if you just want toasts, you can show them from the service, your problem is that the timertask is being executed in a different thread that the UI thread (where the service is running). to "post" this code to the UI thread you can do it directly with something like this:
Handler handler;
#Override
public void onCreate() {
// Handler will get associated with the current thread,
// which is the main thread.
handler = new Handler();
super.onCreate();
}
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
Source
And finally if you want fully interaction between service and activities, you have several ways:
Use binders, for simple communications, this is moreless what you need.
Use a messenger, to more complicated communications.
If you only need dialogs you are always able to launch new activities in dialog mode.
AIDL...
Documentation about 1 & 2 here and here
Binders:
They let you bind different objects in your application letting them access directly to the object itself and its functions, example from android doc:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* 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 {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// 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.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
Messenger:
More advanced & complicated, in this way you can send messages from one object to another:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* 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 object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
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;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
In case you want to show activities as fancy dialogs to show the updates you can use a regular activity with this theme:
<activity android:theme="#android:style/Theme.Dialog" />
Any UI related code should be ran on the UI thread using RunOnUiThread method.
you should set a global context like this:
public static Activity currentActivity=null;
and after run your main activity or any activity that runs service set context like this:
MainActivity.currentActivity = this;
after that in toast use this context:
Toast.makeText(MainActivity.currentActivity," text", Toast.LENGTH_LONG);
hope use full

Categories