Android service does not work independently [duplicate] - android

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

Related

What is the advantage of binding to a Service to get its variables, as opposed to using SharedPrefs, or getting the variables directly?

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

Android best use AsyncTask, Service or other

I'm a student writing some app to understand and study Android Development.
I'm trying to write an app the should work like this:
MapActivity:
Show a map with user position and open Access point in a range.
User and AP position should be received by the "MainClass".
MainClass:
This should do the main work. It should get user position, get open access point from db and insert into the db new open AP found with WifiManager scans.
Now, the MainClass should work in background, on user agree, even if the app is closed.
My questions are:
Should I do MainClass stuff on a new thread or on the UI thread?
Should MainClass be an AsyncTask, Service or other? please tell me why too.
the scan operation return a scan that get executed in a registered receiver. Does it run on UI thread or in a new one?
Thanks in advance.
UPDATE;
So, if i'm not messing what are you saying, the service should look like this:
public class MainService extends Service {
Thread mainThread;
#Override
public void onCreate() {
mainThread = new Thread(new Runnable() {
#Override
public void run() {
....
mainOperation();
....
}
});
mainThread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
mainThread.run();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
does START_STICKY on kill call onStartCommand or onCreate?
Should I do MainClass stuff on a new thread or on the UI thread?
Answer:
You should do on the background thread (new thread) because android does not allow network tasks on UI thread also if you do time taking operation on UI thread UI will freeze
Should MainClass be an AsyncTask, Service or other? please tell me why too.
Answer:
As you clearly said your requirement (MainClass should work in background) you need to use Service because service runs in background even when your app is killed
You should use MainClass.java stuff into a background thread. i.e., Service
Service will trigger data through Broadcast receiver.
Broadcast receiver will send data to MapActivity.java. Registered receiver's onReceive() method always run in the UI thread.
If you want to run MainClass.java stuff in foreground you can use MVP pattern. You should do your stuff into presentation layer.
Background Service will be the best and only solution for your requirements I guess. Because you want your operation to keep running even when your app is closed.

Designing a Service for a two-step task

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.

How to make Handler accessible around the app

There are a few threads running in a service.
The threads need to post messages to UI / Activity
How would I pass over the Handler reference to the threads ? so that they can post their state changes to Activity ?
Or Better yet is there a way to globally expose handler ref like this ?
Handler getUIHandler();
Thank you in advance ;)
Create a Handler object in your UI thread. You can just create it at instantiation time if you like. Any thread launched from your activity can post messages or runnables to that handler. Threads launched from other activities, services, or whatnot will not work because there's no guarantee that your Activity is even running. (Actually, it might be a fun experiment to see if it works when the Activity is running, but you could never base a real app on this technique.)
In fact, you don't even need to create a Handler. Every View object contains its own Handler, so you can simply post your runnables to a view.
Or you could just call runOnUiThread()
From my notes on Handlers:
Usage patterns:
Pattern 1, handler plus runnables:
// Main thread
private Handler handler = new Handler()
...
// Some other thread
handler.post(new Runnable() {
public void run() {
Log.d(TAG, "this is being run in the main thread");
}
});
Pattern 2, handler plus messages:
// Main thread
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
Log.d(TAG, "dealing with message: " + msg.what);
}
};
...
// Some other thread
Message msg = handler.obtainMessage(what);
handler.sendMessage(msg);
Pattern 3, call runOnUiThread():
// Some other thread
runOnUiThread(new Runnable() { // Only available in Activity
public void run() {
// perform action in ui thread
}
});
Pattern 4, use the built-in handler of a View:
// Some other thread
myView.post(new Runnable() {
public void run() {
// perform action in ui thread, presumably involving this view
}
});
I've answered a similar question on how to report back to activity an error in the service.
Check Best practice for error handling in an Android Service, that will give you the aproach as well as a code example that you can use.
Regards.
OK, maybe we should get back to the base issue. Are you trying to make UI updates in your activity from the service? I see two approaches to this.
First, your service could send special Intents back up to the activity. Declare the activity with a launch mode of "singleTask" and implement onNewIntent() to receive intents from the service. Then, pack any relevant information into the intent and send it to the activity to be handled.
The better way, but somewhat more complicated, would be to bind the service from the activity, and then they can easily communicate with each other over the binder. If the service and activity are both part of the same application, and both running in the same process, this becomes much simpler.
Again, from my notes:
Declare an inner class named e.g. "LocalBinder" which extends Binder and contains a method named e.g. getService() which returns the instance of the service:
public class MyService extends Service
{
public class LocalBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
private final IBinder binder = new LocalBinder();
public IBinder onBind(Intent intent) {
return binder;
}
}
Your activity contains code that looks like:
// Subclass of ServiceConnection used to manage connect/disconnect
class MyConnection extends ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder svc) {
myService = ((MyService.LocalBinder)svc).getService();
// we are now connected
}
public void onServiceDisconnected(ComponentName name) {
// we are now disconnected
myService = null;
}
}
private MyService myService;
private MyConnection connection = new MyConnection();
/**
* Bind to the service
*/
void doBind() {
bindService(new Intent(MyClient.this, MyService.class),
connection, Context.BIND_AUTO_CREATE);
}
/**
* Unbind from the service
*/
void doUnbind() {
if (connection != null) {
unbindService(connection);
}
}

Can bindService() be made to block?

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.

Categories

Resources