I'm developing an android application which creates an android service which refresh the location of the mobile device using gps. It works with a timer that in 'x' time, it refresh the position.
The problem is that I would like to comunicate with that local android service from one activity of the application, because I would like to change the refresh time ('x') when I want. So, How do I can do it?
One possible solution is to stop the service and then start again every time the time refresh is changed, but I think it is not the optimal solution.
Any suggerence, help, pls?
If you are within the same Process-Space (Same Application/.apk) you can just establish a simple Service Connection
In your activity, include something like the following:
private ServiceConnection _svcConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName arg0) {
_myService = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
_myService = ((MyService.LocalBinder) service).getService();
if(!_myService.IsRunning())
_myService.Start();
}
};
#Override
protected void onResume() {
bindService(new Intent(Main.this, MyService.class), _svcConnection
BIND_AUTO_CREATE);
startService(new Intent(Main.this, MyService.class));
super.onResume();
}
#Override
protected void onPause() {
unbindService(_svcConnection);
super.onPause();
}
Your Service needs a binder:
private final IBinder _Binder = new LocalBinder();
#Override
public IBinder onBind(Intent arg0) {
return _Binder;
}
/**
* Class for clients to access. 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 MyService getService() {
return MyService.this;
}
}
Then you can work with the _MyService object and call any Method on it. (E. g. Registering a Callback or request Location Updates), but be aware that if the service connection fails, the _MyService variable will be null!
_MyService.SetInterval(4);
If you need to access this service from another Application (Another Process), you have to deal with IPC.
It will help you, You do this in service, it will refresh your location in this method
Timer timer = new Timer("Refresh Time");
timer.schedule(RefreshTask, 1000L, 60 * 1000L);
private TimerTask refreshTask = new TimerTask() {
#Override
public void run() {
Log.i(TAG, "Update time here");
}
};
Related
I would like to know if I am doing the right thing. I am clearly getting memory leaks, but I can not pin down where - I have submitted a simplified version of where I think the problem lies . . . is there a potential for leak in the following code?
public class MainActivity extends Activity {
filterService mServer;
private void startService() {
Intent mIntent = new Intent(getApplicationContext(), filterService.class);
startService(mIntent);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
}
private void stopService() {
stopService(new Intent(getApplicationContext(), filterService.class));
unbindService(mConnection);
mConnection = null;
}
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
mServer = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder mLocalBinder = (LocalBinder)service;
mServer = mLocalBinder.getServerInstance();
}
};
public void onDestroy() {
super.onDestroy();
stopService();
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService();
}
}
Any comments would be most valuable - thank you.
Better unbind from your service in 'onStop()', because 'onDestroy()' may not be called.
If you use 'startService()' to make your service do whatever it is supposed to do and return with 'START_STICKY' from the 'onStartCommand()' method of the service, then it will not be destroyed.
See the documentation about bound services (The Basics):
When the last client unbinds from the service, the system destroys the service (unless the service was also started by startService()).
This way, you can keep your service alive even though the activity is stopped/ destroyed. As soon as it is finished, it can call 'stopSelf()'.
Another source for memory leaks could be a Handler used for communication with the bound service, but I can't judge that from your code.
In my application I am using an IntentService to download a file from a cloud. And showing the progress in NotificationManager. I need to show the status (Downloading/Completed or Failed) in the Activity which stared the IntentService too.
My problem is once I closed the app and open it back, I want to get the status of downloading from IntentService.
Which is the best way to do this?
You can let your Activity bind to your Service, by calling bindService() in your Activity. As per the documentation:
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. Multiple components can
bind to the service at once, but when all of them unbind, the service
is destroyed.
Also:
You should create a bound service when you want to interact with the
service from activities and other components in your application or to
expose some of your application's functionality to other applications,
through interprocess communication (IPC).
The documentation provides a fully functional example of this. Below is taken from the provided link.
Service class:
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);
}
}
Activity class:
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;
}
};
}
In your Service, you can define public methods that your Activity can call, such as polling for your download progress. Please refer to the documentation for explanation in detail.
There are couple of ways to have communication connection between Service and Activity. I would suggest these 2
First, you can use the great library Otto. With Otto, you can also have #Produce annotated method. With this method you will return the latest information about the download. When you #Subscribe in your Activity you will get the latest info immediately. https://github.com/square/otto
If you are using Android built-in DownloadManager it returns the updates and results with a Broadcast, you can register to that Broadcast both in your Service and Activity. This way you will be able to update both of them. I suggest you to use DownloadManager, it is awesome.
http://developer.android.com/reference/android/app/DownloadManager.html
I'm designing my first Android app.
This app consist in several Runnable that do some stuff. Initially I made this Runnable to be execute by a Thread (a Thread for each Runnable). Each Runnable is also Observable, so it can notify changes to Activity. User click on a start button, one or more Runnable starts, them do their job notifying gui during execution and then stops. All works fine.
First question: Is that approach the right one? In order to answer this question please keep reading.
I need two other things in my app:
to be sure that execution of my jobs doesn't stops, even if user goes away from my app to do something else;
to plan the execution of my Runnable that has to start and execute in background. Example: user decides that wants a "job" to be execute everyday at 16:00.
I've seen that I can do that with an AlarmManager and Service.
Second question: I need a Service that can manage several Runnable asynchronously, so when AlarmManager starts I ask this Service to do the requested job; I'll also modify the first part of application: instead of Thread I'll use this Service, so I can be sure that execution doesn't stop.
What kind of Service I need? IntentService can do this job?
It's right to proceed in this way? There is a better solution?
Can you give me some example of how I can implement all that?
I hope that I explained clearly my situation, otherwise I'll try to do it better.
Regards
First question: Is that approach the right one?
No, you should implement and run your Runnables in Threads in a Service.
An IntentService would be your best option if you don't require your Service to handle multiple requests simultaneously. If you start a Service it will keep running in the background even if the Activity that started it goes to the background or stops.
A Runnables can send a broadcast indicating a UI update is needed. The Activity should register a BroadcastReceiver to listen to the broadcast message and update the UI accordingly.
You can use an AlarmManager to schedule the execution of your jobs as you indicated. One way to do it is to schedule the AlarmManager to send a broadcast to be received by your IntentService which acts upon it by running the appropriate job.
Here is an example that combines all that:
Here is the IntentService
public class MyIntentService extends IntentService {
public static final String ACTION_START_JOB = "com.mycompany.myapplication.START_JOB";
public static final String ACTION_UPDATE_UI = "com.mycompany.myapplication.UPDATE_UI";
private final IBinder mBinder = new MyBinder();
// You can have as many Runnables as you want.
Runnable run = new Runnable() {
#Override
public void run() {
// Code to run in this Runnable.
// If the code needs to notify an Activity
// for a UI update, it will send a broadcast.
Intent intent = new Intent(ACTION_UPDATE_UI);
sendBroadcast(intent);
}
};
public MyIntentService() {
super("MyIntentService");
}
#Override
public void onCreate() {
// You need to register your BroadcastReceiver to listen
// to broadcasts made by the AlarmManager.
// The BroadcastReceiver will fire up your jobs when these
// broadcasts are received.
IntentFilter filter = new IntentFilter(ACTION_START_JOB);
registerReceiver(jobBroadcastReceiver, filter);
}
#Override
public void onDestroy() {
// You should unregister the BroadcastReceiver when
// the Service is destroyed because it's not needed
// any more.
unregisterReceiver(jobBroadcastReceiver);
}
/**
* This method is called every time you start this service from your
* Activity. You can Spawn as many threads with Runnables as you want here.
* Keep in mind that your system have limited resources though.
*/
#Override
protected void onHandleIntent(Intent intent) {
Intent intentFireUp = new Intent();
intentFireUp.setAction(ACTION_START_JOB);
PendingIntent pendingIntentFireUpRecording = PendingIntent
.getBroadcast(MyIntentService.this, 0, intentFireUp, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
int year = 2013, month = 5, day = 10, hourOfDay = 7, minute = 13, second = 0;
cal.set(year, month, day, hourOfDay, minute, second);
long startTime = cal.getTimeInMillis() + 5 * 60 * 1000; // starts 5
// minutes from
// now
long intervalMillis = 24 * 60 * 60 * 1000; // Repeat interval is 24
// hours (in milliseconds)
// This alarm will send a broadcast with the ACTION_START_JOB action
// daily
// starting at the given date above.
alarm.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalMillis,
pendingIntentFireUpRecording);
// Here we spawn one Thread with a Runnable.
// You can spawn as many threads as you want.
// Don't overload your system though.
new Thread(run).run();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// Depending on your implementation, you may need to bind
// to this Service to run one of its methods or access
// some of its fields. In that case, you will need a Binder
// like this one.
public class MyBinder extends Binder {
MyIntentService getService() {
return MyIntentService.this;
}
}
// Spawns a Thread with Runnable run when a broadcast message is received.
// You may need different BroadcastReceivers that fire up different jobs.
BroadcastReceiver jobBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
new Thread(run).run();
}
};
}
And here is the Activity
public class MyActivity extends Activity {
Service mService;
boolean mBound = false;
ToggleButton mButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (ToggleButton) findViewById(R.id.recordStartStop);
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (mButton.isChecked()) {
Intent intent = new Intent(MyActivity.this,
MyIntentService.class);
startService(intent);
}
}
});
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(MyIntentService.ACTION_UPDATE_UI);
registerReceiver(uiUpdateBroadcastReceiver, filter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(uiUpdateBroadcastReceiver);
}
BroadcastReceiver uiUpdateBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Here goes the code to update your User Interface
}
};
ServiceConnection myServiceConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
// If you need
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyIntentService mService = ((MyBinder) service).getService();
mBound = true;
}
};
}
And don't forget to add the Service definition in your AndroidManifest.xml file:
<manifest ... >
...
<application ... >
<service android:name=".MyIntentService" />
...
</application>
</manifest>
I am using intent service to periodically send queries to my server to check if there are any updates. In the intent service there is a timer task, which queries the server every 3 seconds, This starts running when the application is closed.
Now when the user again comes back in to the application I want to stop the service.
How should I do this? how can an intent service which is doing timertask be stopped form another activity?
Please give suggestions for Intent Service because that is what I am using.
Maybe it will be better to use just service instead of IntentService.
public class UpdateService extends Service {
public class LocalBinder extends Binder {
public void startUpdates() {
// start updateThread if it not started, or
// notify about resuming probes
}
public void stopUpdates() {
// make updateThread to wait, until startUpdates
// called again.
//
// REMEMBER this method can be called when startUpdates didnt called.
}
}
// For simplicity we will use local binder.
private final IBinder binder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return binder;
}
private Thread updateThread = new Thread() {
#Override
public void run() {
while (true) {
// Do updates. Sleep/awake managment.
}
}
};
}
Just bind to service (with AUTO_CREATE_FLAG) and start updates when you are need.
When your activity shows just bind again to service and make it stop updates.
First of all,IntentService cannot be stopped.It will stop itself only after it has completed all the tasks present in its queue.Hence,IntentService should not be used here.
I am currently using 2 services in my app:
1: LocationService, basically trying to localize the user, and aims to stay alive only when the app is on foreground.
2: XmppService, which init the connection with the xmpp server, receive messages, send it, logout ... and aims to stay alive until the user logout.
I've been reading quite a lot of documentation, but I just can't make it clear.
I'm having Leaks when I try to store reference of LocationServiceBinder, which is used to call my service functions (using AIDL interfaces). Same for Xmpp. When I unbind, I get sometimes ANR (which look like to be linked with the fact that my bind/unbind are weirdly done, onResume, onRestart ...).
All the system is working, but I'm sure it is not the right way to do it, and please I would love to follow experienced people to come back in the right side of the force ! :)
Cheers
UPDATE
My Location Service is bind at the app launch to get as fast as possible the user's position :
if(callConnectService == null) {
callConnectService = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder binder) {
locationServiceBinder = LocationServiceBinder.Stub.asInterface(binder);
try {
global.setLocationBinder(locationServiceBinder);
global.getLocationBinder().startLocationListener();
} catch (Exception e){
Log.e(TAG, "Service binder ERROR");
}
}
public void onServiceDisconnected(ComponentName name) {
locationServiceBinder = null;
}
};
}
/* Launch Service */
aimConServ = new Intent(this, LocationService.class);
boolean bound = bindService(aimConServ,callConnectService,BIND_AUTO_CREATE);
My Xmpp Service is launched when the user log in :
callConnectService = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder binder) {
try {
Log.d(TAG, "[XMPP_INIT] Complete.");
global.setServiceBinder(ConnectionServiceBinder.Stub.asInterface(binder));
//Connect to XMPP chat
global.getServiceBinder().connect();
} catch (Exception e){
Log.e(TAG, "Service binder ERROR ");
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "Service binder disconnection ");
}
};
/* Launch Service */
Intent aimConServ = new Intent(MMWelcomeProfile.this, XmppService.class);
bound = bindService(aimConServ,callConnectService,Context.BIND_AUTO_CREATE);
and unbind on each Activity :
if (callConnectService != null){
unbindService(callConnectService);
callConnectService = null;
}
It hasn't been well-documented in Google's official dev guide, Context.bindService() is actually an asynchronous call. This is the reason why ServiceConnection.onServiceConnected() is used as a callback method, means not happened immediately.
public class MyActivity extends Activity {
private MyServiceBinder myServiceBinder;
protected ServiceConnection myServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
myServiceBinder = (MyServiceBinderImpl) service;
}
... ...
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// bindService() is an asynchronous call. myServiceBinder is resoloved in onServiceConnected()
bindService(new Intent(this, MyService.class),myServiceConnection, Context.BIND_AUTO_CREATE);
// You will get a null point reference here, if you try to use MyServiceBinder immediately.
MyServiceBinder.doSomething(); // <-- not yet resolved so Null point reference here
}
}
A workaround is call MyServiceBinder.doSomething() in myServiceConnection.onServiceConnected(), or perform MyServiceBinder.doSomething() by some user interaction (e.g. button click), as the lag after you call bindService() and before system get a reference of myServiceBinder is quite soon. as long as you are not using it immediately, you should be just fine.
Check out this SO question CommonsWare's answer for more details.
this thread is quite old, but I just discovered it.
Actually there is only one way for your service to go on living if it is bound : it has to be also started. The documentation is not quite clear about that but a service can be both started and bound.
In that case, the service will not get destroyed when you unbind from it, it will get destroyed when :
you stop it and there is no one bound to it
you unbind from it and it has been stopped before.
I made a small Service Lifecycle demo app on GitHub and it's also available on Google Play.
Hope that helps ;)
if you bind to a service in an Activity, you need to unbind it too:
#Override
protected void onResume() {
Log.d("activity", "onResume");
if (locationServiceBinder == null) {
doBindLocationService();
}
super.onResume();
}
#Override
protected void onPause() {
Log.d("activity", "onPause");
if (locationServiceBinder != null) {
unbindService(callConnectService);
locationServiceBinder = null;
}
super.onPause();
}
where doBindLocationService():
public void doBindLocationService() {
Log.d("doBindService","called");
aimConServ = new Intent(this, LocationService.class);
// Create a new Messenger for the communication back
// From the Service to the Activity
bindService(aimConServ, callConnectService, Context.BIND_AUTO_CREATE);
}
You need to do this practise for your XmppService as well