Android stop specified IntentService - android

I've have develop an android application with an IntentService.
This IntentService does nothing more like a fileupload.
I just want to implement the functionality to upload multiple "file-upload-threads".
The problem is to stop one specified "file-upload-thread".
For example:
User choose ten files from the device and upload these.
A notification is created to gives the user "transfer-feedback".
While the thread is working the user can choose other files to upload.
Another notification is created but does not start until the first thread is done.
Is it possible to implement a "cancel-functionality" for the user to cancel the first thread and the second thread start automatically?!
Maybe is it better to user an Service instead of an IntentService?

IntentServices are designed to run-one-at-a-time. Of course you could cancel your IntentService since in inherits from Service.

class MyService extends IntentService {
public static volatile boolean shouldStop = false;
public MyService() {
super("My Service");
}
#Override
protected void onHandleIntent(Intent intent) {
doStuff();
}
private void doStuff() {
// do something
// continue doing something
// put those checks wherever you need
// check the condition
if (shouldStop) {
stopSelf();
return;
}
}
}
And from your activity code you can change the state of the boolean flag to true if you want to stop the service. Hope this will help you.

An IntentService is designed to stop itself only when all the requests present in the work queue have been handled.As per docs,IntentService class "Stops the service after all of the start requests are handled, so you never have to call stopSelf()
In case you want to cancel requests,you can probably use volley and cancel previous requests
https://developer.android.com/training/volley/simple.html#cancel

Related

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.

self destructing an android app after certain amount of time

i currently work on an app that needs a lot of battery in order to support background gps tracking. my experience shows that people just forget about the app runnning in the background when they dont really need the tracking anymore. therefore i setup some code that should close the application after 4 hours.
public class SelfDestructor {
private static SelfDestructor instance;
private final long IDLE_TIME_UNTIL_AUTO_DESTRUCT = 4 * 60 * 60 * 1000; // 4 hours
private Handler handler;
private Runnable closeApp = new Runnable() {
#Override
public void run() {
System.exit(0);
}
};
public static SelfDestructor getInstance() {
if (SelfDestructor.instance == null) {
SelfDestructor.instance = new SelfDestructor();
}
return SelfDestructor.instance;
}
public void keepAlive() {
if (handler == null) {
handler = new Handler();
}
handler.removeCallbacks(closeApp);
handler.postDelayed(closeApp, IDLE_TIME_UNTIL_AUTO_DESTRUCT);
}
}
now in my main activity i call keepAlive().
#Override
protected void onResume() {
super.onResume();
SelfDestructor.getInstance().keepAlive();
}
#Override
protected void onStart() {
super.onStart();
SelfDestructor.getInstance().keepAlive();
}
now if i set the time to an hours or so and debug the that functionality everything works fine. if i set the time to 4 hours the System.exit(0); is never called. i am assuming the app thread with the close callback is just put on hold by the android system after a while and therefore will not be executed anymore while gps will continue to run. any ideas how to properly get this to work?
handler and postDelayed are not suited for long timers. At most they should be used within a few seconds and personally I think I never used one for anything more than 2 seconds.
Said all that, Android have an appropriate class for "stuff that should happen after a long time", it's called AlarmManager: http://developer.android.com/reference/android/app/AlarmManager.html
you can get the references to the system service AlarmManager by calling Context.getSystemService(Context.ALARM_SERVICE)
and then set it by calling am.set(AlarmManager.ELAPSED_REALTIME, IDLE_TIME_UNTIL_AUTO_DESTRUCT, operation)
the operation is a PendingIntent to a BroadcastReceiver that you register in the AndroidManifest.xml via the <receiver> tag. Then you do the close application code inside this broadcast receiver.
Also I should add that it's NEVER good to call System.exit(0);, as this just destroy the VM without much of a warning. It's a better, more organised/structured shut down if you pass a command to the Service that is holding the GPS (I believe you're running a service), then this service will cancel the GPS request, and call stopSelf();

What happens to Threads started in Android Service when Android restarts the Service?

I have a Service like this (this is not the actual Service, it's just for describing my problem).
public class UploadService {
private BlockingQueue<UploadData> queue = null;
private UploadInfoReceiver receiver = null;
public void onStart(...) {
queue = new LinkedBlockingQueue<UploadData>();
(new Processor()).start();
// creating and reigtering receiver
}
public void onDestroy() {
queue.add(new ServiceDestroyedData());
// unregistering the receiver
}
private class Processor extends Thread() {
public void run() {
while (true) {
UploadData data = queue.take();
if (data instanceof ServiceDestroyedData) {
return;
}
// processing data
}
}
}
private class UploadInfoReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
queue.add(new UploadData(/* getting data from intent */));
}
}
}
And my problem is that if I do something like this in my App:
if (!isUploadServiceRunning()) {
// start the Service
}
Then it starts the Service, but when I move my App to the background and open task manager (android 4.2.2), and kill the app, Android restart my Service, and I can see that it creates a whole new instance of it, and I can see that onDestroy never gets called for the previous Service instance. And I also can see that the instance of the previous Processor Thread is no longer running. How can this be? If onDestroy never gets called how does Android know that it should stop my Thread?
Thanks for your answers.
Android will kill off anything that it finds that is attached to your apps classloader when you select force stop from the menu. Think kill -9 on Linux. There will be no nice callbacks to any onDestroy methods, the system will just end everything.
Now for your service:
while(true) should really NEVER be used. It will instantly kill the battery and will not do any work 99% of the time anyway.
You area already using a receiver, you can just put your while logic into there and once the upload is done call the next upload and so on. There is absolutely no need for the loop.

Show ProgressDialog from thread inside the Service

I have a Service with registered ContentObserver. When my ContentObserver detects changes it sets Service's boolean variable to true. I also have a Thread running in the service which sleeps for some time and wakes up to check that variable.
When it detects change it needs some time to process some other code and I need to show ProgressDialog during the delay. How can I do this?
You should use AsyncTask instead.
Here is the link to the library. It is fairly simple:
1) onPreExecute() = show ProgressDialog
2) doInBackground() = execute your code
3) onPostExecute() = dismiss ProgressDialog
DONE :-)
The essence of your question is that you want your service to send a message of some kind to your UI (to show a loading dialog).
There are four (or more) ways of going about this:
Intents: have your service send an intent to your activity
AIDL
Using the service object itself (as singleton)
Having your activity be a broadcast receiver
These options may seem familiar: How to have Android Service communicate with Activity
You'll have to read up on those options and take your pick.
AsyncTask is a good alternative, but still if you decided to go with threads, then in order to show the ProgressDialog on UI you will need to call runOnUiThread() method of the activity.
Let suppose you want to display the ProgressDialog in the MainActivity. Inside your Thread from Service you should have something like this:
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// Display ProgressDialog here
}
});
Thanks everyone for answers.
I solve the problem using these steps
- broadcast Intent when my variable was changed
- create BroadcastReceiver for the intent( in Activity )
- inside BroadcastReceiver's method onReceive call runOnUiThread for my activity
I know this is an old thread but I have exactly what you needed because I just implemented this from a thread here. Please read Rachit Mishra's answer further down the page talking about a ProgressBar:
Communication between Activity and Service
I have this in my service:
public void sendMessage(int state) {
Message message = Message.obtain();
switch (state) {
case 1://SHOW:
message.arg1 = 1;
break;
case 0:
message.arg1 = 0;
break;
}
try {
messageHandler.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
Call sendMessage() with 1 or 0 to show or dismiss the ProgressDialog within your service.
And this is in my Main Activity:
private ProgressDialog progress;
public class MessageHandler extends Handler {
#Override
public void handleMessage(Message message) {
int state = message.arg1;
switch (state) {
case 0://HIDE
progress.dismiss();
break;
case 1://SHOW
progress = ProgressDialog.show(MainActivity.this, (getResources().getString(R.string.CONNECTING) + "..."), (getResources().getString(R.string.PLEASE_WAIT) + "!")); //show a progress dialog
break;
}
}
}
The ProgressDialog cannot be shown from the service, it must be called from the activity or fragment. I hope I added all the code you need and that it works well for your needs. To be honest I'm not sure how the message handler works but it works for me! The naming is probably not the best either lol. Sorry.

synchronous messages from service to UI layer

is the order of a broadcast intent guaranteed? that is, if i do,
sendBroadcast(intent1);
sendBroadcast(intent2);
are the receivers guaranteed to get intent1 before intent2? i suspect the answer to this is no, but in that case, i'm not quite sure how to solve my problem.
i'm trying to create a "busy" indicator for my app that shows busy when the device is talking on the network, and then goes away when the network communication is done. all network communication happens in an intent service.
my attempt at this was to send a BUSY_START intent when i begin network communication in the service, and a BUSY_STOP when network communication ends. this seems to mostly work, but i'm finding occasionally that i get the stop and start messages out of order.
is there a better way to solve this problem?
i'm thinking of adding an ID to each busy intent, so they can be paired. that way if i receive a start for which i've already received a stop, i can ignore it. or, perhaps more simply, add an integer sequence number into each broadcast. if i ever receive a broadcast for which the sequence of the current intent is less than the sequence of the last received intent, ignore it.
Have you considered using a Handler object to communicate from the background thread in the IntentService? The advantage of a Handler over the BroadcastReciver approach is that the Handler uses a message queue to sequence the Message objects.
(I'm assuming your Service is in the same process as the app's main thread).
At least one viable alternative to intents is to execute messaging through the application class, i.e.,
create a listener interface
Manager a collection of listener objects in the application / provide methods to add / remove listener
Interested entities call the application methods to add / remove themselves as listeners
Add "notify" methods in the application, that call the appropriate listener interface method on each of the registered listeners
Services call the application's notification methods to
For example,
public class MyApplication extends Application {
public interface MyListener {
void onEvent();
}
private Set<MyListener> listeners = new HashSet<Listener>();
public void addListener(MyListener l) {
listeners.add(l);
}
public void removeListener(MyListener l) {
listeners.remove(l);
}
public void sendEvent() {
for (MyListener l: listeners) { l.onEvent(); }
}
}
Now, from your activity (or fragment),
public class MyActivity extends Activity implements MyListener {
...
...
...
#Override
public void onEvent() {
// do something
}
#Override
protected void onResume() {
super.onResume();
((MyApplication)getApplication()).addListener(this);
}
#Override
protected void onPause() {
super.onPause();
((MyApplication)getApplication()).removeListener(this);
}
}
And in your service,
((MyApplication)getApplication()).sendEvent();
This provides synchronous messaging without using intents or static variables.

Categories

Resources