using Xamarin and Mqtt and my mqtt client m2mqtt is unable to maintain a connection throughout the android lifecycle.
Activity life cycle will cause problems if your process needs to stay alive after the activity has paused or stopped (phone sleeps, user switches apps then comes back)
The idea of using a service is that it will remain intact regardless of where the activity is in the life cycle.
Can anyone show me how to implement a service.
OK,
It's very easy and really kind of cool.
I got the info I needed to figure this out here c# corner
a lot of times when I need a layman's description csharp corner isn't bad I used their example pretty close to how they portrayed it I just want to help you to understand how to use it
You need 3 classes
1. the service itself (we'll call it service)
2. service binder (serviceBinder)
3. service connection (serviceConnection)
I'll show you mine next (this is working), I was designing a bound service hence you will see in the names instead of service it's called boundService. However, after doing this I found out that a start service works exactly the same way you just start it different the classes are the same.
You need android.app.
So first we need the service it extends :Service (important)
using Android.App
[Service]
class MqttBoundService : Service
{
private MqttBoundServiceBinder binder;
public override void OnCreate()
{
base.OnCreate();
}
public override IBinder OnBind(Intent intent)
{
binder = new MqttBoundServiceBinder(this);
Toast.MakeText(this, "OnBind() method start from BoundService", ToastLength.Long).Show();
Toast.MakeText(this, "Bound Service is started", ToastLength.Long).Show();
return binder;
}
public override bool OnUnbind(Intent intent)
{
Toast.MakeText(this, "OnUnBind() Method Called from BoundService.cs", ToastLength.Long).Show();
return base.OnUnbind(intent);
}
public override void OnDestroy()
{
Toast.MakeText(this, "Bound Service Destroyed", ToastLength.Long).Show();
base.OnDestroy();
}
The toast is there just so you know whats happening in case your service is getting destroyed when you didn't want it too.
Ok now we need the service binder (Extends Binder important)
class MqttBoundServiceBinder : Binder
{
MqttBoundService service;
public MqttBoundServiceBinder(MqttBoundService service)
{
this.service = service;
}
}
now we need the connection and this is where the heavy lifting takes place. I am still new to this but it looks like you want to put the methods here that need to outlive the activity life cycle.
class MqttBoundServiceConnection : Java.Lang.Object, IServiceConnection
{
public Connection connect { get; private set; }
public void OnServiceConnected(ComponentName name, IBinder service)
{
Console.WriteLine("OnServiceConnected() Method called");
}
public void OnServiceDisconnected(ComponentName name)
{
Console.WriteLine("OnServiceDisConnected() Method called");
}
public Connection Connect()
{
connect = new Connection(Utility.data, Utility.cdata);
return connect;
}
}
in the method Connect I instantiate my Connection object the parameters here are security certs but that's not important. I also have a property with get; set; that I set to my object so I can access the mqtt connection in my OnRestart() and OnResume() functions of my activity.
I was having problems with resources being diverted by android before I did this and that doesn't happen now.
Not sure if it matters but this is my OnRestart()
if (serviceConnection.connect == null)
{
DoBindService();
connect = serviceConnection.Connect();
}
else
{
connect = serviceConnection.connect;
}
Oh I forgot how to tell you how to start it OK for me I am doing a bound service this means that after all the activities (or clients) that are using it are destroyed the service is destroyed.
So to start a bound service first create a class level variable for the connection (in the activity -- it is referenced in my OnStart() above). Also once you do this you can call the methods from this class (really cool)
MqttBoundServiceConnection serviceConnection = new mqttBoundServiceConnection();
Then we need a method in the activity called DoBindService
private void DoBindService()
{
var BoundServiceIntent = new Intent(this, typeof(MqttBoundService));
BindService(BoundServiceIntent, serviceConnection, Bind.AutoCreate);
}
in the OnCreate() for the activity add
DoBindService();
I hope this help someone it helped me once I figured it out :)
Related
I've got a service meant to sometimes run in the background - started with startService().
What is the advantage of binding to this service so as to get/set its variables, instead of - controversial, I know, but still - just accessing its public variables directly (e.g. myVar = mainService.itsVar), or using SharedPrefs to set and get the values?
Especially, what is the fastest, in terms of performance, based on the fact that the get interval would be roughly 3 seconds?
Advantage - You can access variables and run methods directly.
Disadvantage - allot of cross thread headache, not to mention unresolved crashes on google developer console.
How to do it correctly, I will give example of a foreground service, if it can be background then change only how to start it:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mContext.startForegroundService(startIntent)
} else {
mContext.startService(startIntent);
}
In the service you need to implement all binding methods:
private IBinder mBinder = new MyBinder();
public MainService() {
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
#Override
public boolean onUnbind(Intent intent) {
return true;
}
public class MyBinder extends Binder {
public MainService getService() {
return com.xxx.xxx.MainService.this;
}
}
In the activity you need to listen to connection:
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mBoundService = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "connecting");
MainService.MyBinder myBinder = (MainService.MyBinder) service;
mBoundService = myBinder.getService();
mShouldUnbind.set(true);
}
};
If other activity or alarm can start your service you will need to check every second or so if the service was started by other and bind to it.
Important - service run on the same thread like the main/GUI thread - so if you have time consumption actions like camera or uploading - you will need to start a background thread. back communication can be made by calling the GUI/main thread.
on foreground service like mine - you need also to manage notifications otherwise the o.s. will kill the service after 5 seconds.
Code example:
if (mShouldUnbind.get() && mBoundService != null)
val = mBoundService.getTimestamp();
Edit I:
advantage:
I have a camera foreground service - I can set zoom values directly from the GUI thread since I have a handle to the service. the camera is running on the background thread in the service, but, since the preview is being drawn 30 times pro seconds - the zoom is set without any lag. you will never manage to do it in any other way.
there is a difference between bounded service and Unbound service, bounded services are bounded to an activity which binds it and will work only till bounded activity is alive. while a unbounded service will work till the completion even after activity is destroyed, see the below link
Can anybody explain what is difference between unbound and bound service in android
I am currently resuming a project I had been working on, and starting from scratch to recreate it.
However, upon creating a Service class, I noticed something - in my old project, a method inside the Service called onStartCommand contains all of the code that needs to be fired, whereas in my new project when I create a Service class, this method is nowhere to be found.
- Do I need to manually ADD this "onStartCommand" method to contain my service code?
- If not, where exactly would my code go? It seems in my "old" project's code, I completely comment-block public TimerService, and pass null into IBinder, and create onStartCommand etc instead.. and I can't quite figure out why.
- While i'm here, can someone please double-check my CountdownTimer code below? and if it's correct, should I be putting it inside of a Thread?
When I create a new Service Class, it looks like this:
public class TimerService extends Service {
public TimerService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
However in my old Project, my Service class looks like this:
public class TimerService extends Service {
/*
public TimerService() {
}
*/
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
intent.getStringExtra("TIMER_VALUE");
String string_timerValue;
string_timerValue = intent.getStringExtra("TIMER_VALUE");
long long_timerValue;
long_timerValue = Long.parseLong(String.valueOf(string_timerValue));
// I DO NOT WANT ANY TICK VALUE, SO GIVE IT FULL TIMER VALUE
long long_tickValue;
long_tickValue = Long.parseLong(String.valueOf(string_timerValue));
new CountDownTimer(long_timerValue, long_tickValue) {
public void onTick(long millisUntilFinished) {
// DO NOTHING
}
public void onFinish() {
Toast.makeText(TimerService.this, "TIMES UP", Toast.LENGTH_LONG).show();
stopService(intent);
}
}.start();
return START_STICKY;
// END OF onStartCommand
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
// END OF ENTIRE SERVICE CLASS
}
THANK YOU!!
Do I need to manually ADD this "onStartCommand" method to contain my service code?
Yes.
can someone please double-check my CountdownTimer code below?
Only create a service when one is absolutely necessary. It is unclear why this service is necessary.
Beyond that:
Use stopSelf(), not stopService(), to stop a service from inside that service.
Examining Intent extras and using START_STICKY is not a good combination. START_STICKY says "if you terminate my process to free up system RAM, please restart my service when possible, but pass null for the Intent". That will cause your service to crash with a NullPointerException.
I have a DialogFragment that can be launched from anywhere, let’s call it UploadDialogFragment. This fragment allows the user to accomplish two related tasks:
Upload an image (can take up to 1min)
Upload a JSON object with some text and a reference to the saved image
This two tasks need to be accomplished in sequence - you can’t do 2. without having completed 1.. So what really happens is:
I start uploading the image (1.)
Meanwhile, the user writes the text and adds other info
When all is ready, dismiss the dialog and start the second task (2.).
I used to do this with background tasks, but now I’d like to switch to a Service: the whole operation should be completed even if, after dismissing, I force quit the app.
Current design
In my experience I have always used IntentService, so I am a complete newbie. The current flawed design I am moving forward is something like:
public class UploadService extends Service {
private final Binder binder = new Binder();
public class Binder extends android.os.Binder {
UploadService getService() {
return UploadService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public void completeFirstTask() {
...
}
public void completeSecondTask() {
// wait for first task to complete if necessary...
...
stopSelf();
}
}
And here’s my UploadDialogFragment:
public class UploadDialogFragment extends AppCompatDialogFragment implements
ServiceConnection {
private UploadService uploadService;
private boolean boundService;
#Override
public void onServiceDisconnected(ComponentName name) {
uploadService = null;
boundService = false;
}
private void bindService() {
Intent i = new Intent(getActivity().getApplicationContext(), UploadService.class);
getActivity().getApplicationContext().bindService(i, this, Context.BIND_AUTO_CREATE);
boundService = true;
}
private void unbindService() {
if (boundService) {
getActivity().unbindService(this);
boundService = false;
}
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
uploadService = ((UploadService.Binder) service).getService();
uploadService.completeFirstTask();
}
// THEN, LATER:
// OnClick of a button, I call uploadService.completeSecondTask();
// and this.dismiss();
}
This is deeply flawed right now.
I need to reliably unbind() when the dialog fragment is closed/dismissed/recreating itself, otherwise I am going to leak it because of the ServiceConnection (right?). I don’t know when to do it?. onDismiss, onDestroyView, onSaveInstanceState ... I have tried many options but I often end up with a IllegalArgumentException saying that the service connection is not registered.
The service might never reach the completeSecondTask() part, and so no one is going to stop it, leaking it for no reason. I should probably call stopService() somewhere, but where? These are different scenarios:
I force-quit the app / recreate the fragment after a completeSecondTask() call: the Service should keep going until it ends.
I recreate the fragment without having called completeSecondTask() : the Service should keep going until it ends. (There’s proper logic inside my fragment to handle this)
I force-quit the app without having called completeSecondTask() : the Service should stop.
Questions
Now, you might see this as two questions: how to handle unbind(), and how to handle stopService().
However, because I am finding so hard to set up this little task, I am thinking that this is deeply flawed and I should use a totally different approach. I hope you can shed some light on this for me.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Android Service makes Activity not responding
I use service to synchronize data between database and view. But the service does not work properly, whenever I use service to work long task, the view stop response (I can't do any event in UI) and I have to wait the service has done. Here is my service:
public class SyncService extends Service{
private static final String TAG = "SyncService";
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onDestroy()
{
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, "call onBind");
return new DataManagerBinder();
}
private class DataManagerBinder extends Binder implements IUserDataManager
{
#Override
public void doProcess(Activity mView)
{
//do some long task (not touch UI thread)
// this will cause the view not response
syncDB();
// update view after process completed
mView.updateViewOnComplete();
}
}
I try to bind this service in client activity
//the interface to handle binder
IUserDataManager viewManager = null;
ServiceConnection serviceConnection = new ServiceConnection()
{
#Override
public void onServiceDisconnected(ComponentName name)
{
Log.i(TAG, "connection closed unexpectedly");
viewManager = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder)
{
Log.d(TAG, "serviceConnection onServiceConnected");
viewManager = (IUserDataManager) binder;
viewManager.doProcess(MyActivity.this);
}
};
Intent intent = new Intent(MyActivity.this, SyncService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Please give me the solution for that. Thanks in advance!
While others have given some responses, I don't know if the main point has been emphasized:
While a Service sounds like something that would automatically run in the background, it does not. It's merely a piece of code that can react to intents without maintaining a UI. However, the UI thread still does the processing for the Service.
By contrast, it looks like what you want, is a Service that sits in the background and does some work in a background thread. You will use the Service class to spawn a new thread, this is typically done on response to some intent, which you can define (usually in your onStart() or something similar). You will probably start a new thread which actually does the work updating the database, etc..., and use your main Service to coordinate to that thread.
As it looks like you also want to communicate with the service, you will have to implement an appropriate Messenger and Handler pair to keep track of messages you pass between the UI and the Service (coordinating a background thread), and also (possibly) some way (also perhaps a messenger) of coordinating between the Service and the background thread.
As others have noted, you can also use AsyncTask to do things on the UI thread and use a background thread "seamlessly."
Read up on the docs regarding services, specifically the "What is a Service?" paragraph. The service runs on the main UI thread. Take a look at AsyncTask, should solve your issue. The work here is done in a background thread, and the results are sent back to the UI thread.
Android closes service after sometime to save resources.
However you can prevent this from happening using something like
int onStartCommand(Intent, int, int){
return START_STICKY;
}
ref this
I have an Android application that uses a Remote Service and I bind to it with bindService(), which is asynchronous.
The app is useless until the service is bound, so I would like to simply wait until the binding is finished before any Activity is started. Is there a way to have the service bound before onCreate() or onResume() is called? I think there might be a way to do the binding in Application. Any ideas?
Edit:
if in onCreate() I do this.
bindService(service, mWebServiceConnection, BIND_AUTO_CREATE);
synchronized (mLock) { mLock.wait(40000); }
The ServiceConnection.onServiceConnected doesn't get called for 40 seconds. It's clear that I have to let onCreate() return if I want the service to bind.
So it appears there's no way to do what I want.
Edit 2:
Android how do I wait until a service is actually connected? has some good commentary about what is going on in Android when binding a service.
You cannot have bindService() block. However, your ServiceConnection (2nd parameter to bindService) has callbacks to tell you when the service is connected and disconnected, so you can have other code block until your onServiceConnected() method unblocks it.
When I need to wait a service to be bound before doing something else I play with locks. Precisely, the ServiceConnection owns a lock object and exposes a waitUntilConnected method that block on the lock until a wake up signal. That notification is located in the onServiceConnected callback.
public class MyServiceConnection implements ServiceConnection {
private volatile boolean connected = false;
private Object lock = new Object();
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
connected = true;
synchronized (lock) {
lock.notifyAll();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
connected = false;
}
public void waitUntilConnected() throws InterruptedException {
if (!connected) {
synchronized (lock) {
lock.wait();
}
}
}
}
So, for example, if an activity has to wait a service to be bound, it calls simply the waitUntilConnected method.
protected void onStart() {
super.onStart();
bindService(myServiceIntent, myServiceConnection, Context.BIND_AUTO_CREATE);
try {
myServiceConnection.waitUntilConnected();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I placed the waitUntilConnected method in onStart just as an example, but it has to be called in a different thread. I'd like to hear a more elegant way! :)
It seems that there is a way to do this. KeyChain.java and several Google-written classes uses a LinkedBlockingQueue to allow synchronously bind to a service.
For example, see the method called bind on this: https://github.com/android/platform_frameworks_base/blob/master/keystore/java/android/security/KeyChain.java
It seems to return the service object synchronously due to the use of blocking queue.
Unfortunately, as stated on the Android docs https://developer.android.com/reference/android/security/KeyChain.html, some methods throws InterruptedException, due to the taking of element from the queue that may be interrupted when waiting.
Android 10 has introduced a new bindService method signature when binding to a service to provide an Executor (which can be created from the Executors).
/**
* Same as {#link #bindService(Intent, ServiceConnection, int)} with executor to control
* ServiceConnection callbacks.
* #param executor Callbacks on ServiceConnection will be called on executor. Must use same
* instance for the same instance of ServiceConnection.
*/
public boolean bindService(#RequiresPermission #NonNull Intent service,
#BindServiceFlags int flags, #NonNull #CallbackExecutor Executor executor,
#NonNull ServiceConnection conn) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
See this Answer
bindService() cannot be made to block. That kind of defeats the whole purpose of a Service. You said that you whole UI consists of results from the service. I think you need to rethink your UI and populate it with some kind of intermediate representation that shows the user that the app is gathering data.