Android: AsyncTask more priority than Service - android

I have a Service and AsyncTask running at the same time, Inside the service, storing the data in the server takes place, In AsyncTask, getting data from a different source and updating UI takes place.
UI doesn't get updated until the the task inside the Service gets completed, after that UI gets displayed
protected List<AppItem> doInBackground(MyTaskParams... integers) {
android.os.Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE);
I used the above code for asynctask , but its not working, how can I give more preference to AsyncTask than Service

use this piece of code instead
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);

By default, Service runs on the Main thread.
Remember that if you do use a service, it still runs in your
application's main thread by default, so you should still create a new
thread within the service if it performs intensive or blocking
operations.
https://developer.android.com/guide/components/services?hl=en#should-you-use-a-service-or-a-thread
It looks like you start your Service first, then you run your AsyncTask. Because the service runs in the Main thread, your AsyncTask is not started until it finishes.
Update
There are many solutions and the choice depends on requirements. It looks like in your case the simplest way to achieve concurrency is to use the IntentService. So, you can start both the IntentService and AsyncTask from your Activity.
public class MyIntentService extends IntentService
{
private static final String TAG = this.getClass().getSimpleName();
public MyIntentService() {
super("MyIntentService");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "MyIntentService Started");
// This thing still happens on ui thread
return START_NOT_STICKY;
}
#Override
protected void onHandleIntent(Intent intent)
{
Log.d(TAG, "MyIntentService Handling Intent");
// Your work should be here, it happens on non-ui thread
}
}
https://developer.android.com/reference/android/app/IntentService

Related

Same Intent Service running multiple background tasks parallely (ISSUE)

public class DataManager extends IntentService {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
public DataManager() {
super("DataManager");
setIntentRedelivery(true);
}
#Override
protected void onHandleIntent(final Intent intent) {
// download and parsing task done here
}
}
This is my intent service which i am using to download file and parse it. Now if i get a new request for a file download, i have to clear the ongoing task and start the download for new request cancelling the older one. so i use the below code for doing it :.
private void refreshSync() {
context.stopService(new Intent(context, DataManager.class));
final Intent mServiceIntent = new Intent(context, DataManager.class);
mServiceIntent.putExtras(bundle);
context.startService(mServiceIntent);
}
So the service gets killed and the next request to start service is intented. But the previous tasks starts again running two parallel tasks performing download. Basically the previous task doesnt get killed which i intended to.
Is there any work around to kill the ongoing task of the service and start another fresh task ?
Don't use IntentService. This doesn't match your requirements. IntentService is a simple Service that accepts a queue of work and processes the queue and then shuts itself down when the queue is empty.
You need more intelligence, and you are better off implementing that yourself. Just extend Service instead of IntentService. In onStartCommand() start a background Thread that downloads the data. Keep track of that background Thread in a member variable in the Service. If startService() gets called again, check if you already have a download in progress. If so, stop it and start a new background Thread to download the new file. To stop a background thread, you should provide a boolean variable in the Thread that gets examined every now and then inside the download loop. If that variable's state changes, it means the Thread should stop. This is a standard mechanism for stopping background threads in Java.
You are setting setIntentRedelivery(true);, that force the intents to survive calls of the service if they are not handled completely (if onHandleIntent doesn't manage to return). Taking into account the fact that IntentService has only one working thread (can execute only one task at a time) the behavior of the service completely depends on the onHandleIntent implementation. So you need either analyze implementation and change it according to you goals, or set setIntentRedelivery(false);

Best approach to execute service in Android

I have a service that have an variable life time. It may execute from 5 minutes to 2 hours (for example). So I'm looking for the best approach to do that, and my service must achieve the following features:
Send (to my server) lat-long every 5 seconds and some extra information (string's, boolean's and int's)
I have tried a "normal" service and tried to do something like this to achieve this:
public class MyFiveSecondsService extends Service {
private Handler handler;
Runnable r = new Runnable() {
#Override
public void run() {
//here send my new data
}
};
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(handler == null){
handler = new Handler();
}
handler.post(r);
return super.onStartCommand(intent, flags, startId);
}
}
Actually that code works, but I got some performance problems with that approach, so I tried to do something like this:
public class SendUniquePositionIntentService extends IntentService {
public SendUniquePositionIntentService() {
super("co.bomboapp.Service.IntentService.SendUniquePositionIntentService");
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
protected void onHandleIntent(Intent intent) {
//do the logic here
}
}
public class MyFiveSecondsService extends Service {
private Handler handler;
Runnable r = new Runnable() {
#Override
public void run() {
//call my SendUniquePositionIntentService here
}
};
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(handler == null){
handler = new Handler();
}
handler.post(r);
return super.onStartCommand(intent, flags, startId);
}
}
And that approach haven't worked, when I had closed the app any service kept running. So before start any other attempt to achieve this, I want some direction, what's the best approach to do this "infinite loop service" and keep the performance?
I'm using Android 4.1 as min API, and targeting 5.0 API.
My test device is a Nexus 5 running Android 6.
Right now I'm using parse.com as database.
"I have tried a "normal" service...but I got some performance problems"
By default, a service runs on the application's main thread, so when you create a handler with
public int onStartCommand(Intent intent, int flags, int startId) {
if(handler == null){
handler = new Handler();
}
...
}
the handler is associated with the main thread's Looper and all messages and runnables are delivered and later executed on the thread. That's the reason of the "performance problems". From the documentation:
Remember that if you do use a service, it still runs in your application's main thread by default...
Regarding the second approach and the part
"...when I had closed the app any service kept running"
you haven't mentioned how exactly you "close" the app, but what I can see is
public int onStartCommand(Intent intent, int flags, int startId) {
...
return super.onStartCommand(intent, flags, startId);
}
which means that if the system kills the service it, by default, will be recreated. So if "closing" your app means killing it, the following chain of actions takes place:
The system recreates MyFiveSecondsService,
onStartCommand() is called and the handler posts the runnable
within the run() method SendUniquePositionIntentService is started
From the documentation of onStartCommand():
the default implementation calls onStart(Intent, int) and returns either START_STICKY or START_STICKY_COMPATIBILITY.
Note that starting a service from another one (like starting SendUniquePositionIntentService from MyFiveSecondsService in your case) is redundant unless you intended to.
The final part of your question is confusing to me. On one hand it doesn't work for you because "...any service kept running" but, on the other hand, you'd like "do this "infinite loop service""...?
If you only need to send such information as "strings, booleans and ints" to a server (without any feedback to the component that started the service), I suppose it's simply enough for you to use IntentService. This is a "out-of-box" framework that does its work on a background thread (letting you avoid freezing the main thread) and stops itself once it's done. As an example you can use the documentation on IntentService - it's well written.
Also note that the behaviour of a service after killing it by the system depends on the flag returned by onStartCommand(). E.g. use START_NOT_STICKY to not recreate the service after killing the app or START_REDELIVER_INTENT to recreate it with the last Intent redelivered.

Start service once and forever untill it gets killed

A simple question, how to make a Service repeat at log cat console msg "hello", as long as the Service is living/is active? I've tried:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("LocalService", "Received start id " + startId + ": " + intent);
Mano lopas = new Mano(this);
lopas.Lopas();
while(true) {
Log.v("HAHA", "hello");
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
But it never returns START_STICKY, actually it doesnt even build the project. I think im missing something about services? I start my service, in MainActivity in my application, like:
startService(new Intent(getApplicationContext(),Myclass.class));
And it runs only once without my while loop in my service. It says me something in Logcat and this is it. Morever, my service starts so many times as many times I re-open my application. How to make service start run once and "forever", I mean untill it gets killed by the system or user kills it.
Services don't have their own thread, they run on the UI thread. If you want it to run in parallel, you need to create a Thread. So here you should create a Thread in your onStartCommand, and that thread should do whatever it is you want.
Same way you'd log something at intervals in your activity: use a Handler. Post a task that logs a message and re-posts itself to the same Handler using postDelayed(...). Cancel any pending execution in your activity's onPause() or your service's onDestroy().
Note that there is almost never a good reason to explicitly create a Thread or use J2SE constructs like TimerTask in Android. For heavyweight tasks, use AsyncTask. For lightweight tasks, use Handlers. In your case, creating a new Thread would be a ridiculously heavyweight solution for what you want to do.
First of all, do not forget to register the Service in your Manifest.
This can be done by using
<service android:enabled="true" android:name=".services.Paycan" />
Next is, that your Service (if its not an intentservice) run in the MainUI. If you create an endless loop make sure it's in a background thread, otherwise it will freeze the app.
You can do it using an Asynctask, a Thread which get created with onStartCommand and stopped in onDestroy or use an IntentService instead of a Service.
example:
public class yourTestClass extends Service {
Thread testThread;
boolean threadRunning = false;
#Override
public void onCreate() {
super.onCreate();
testThread = new Thread() {
#Override
public void run() {
try {
while(threadRunning) {
Thread.sleep(1000);
Log.i("test", "....");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
threadRunning = true;
testThread.start();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
threadRunning = false;
}

IntentService and Threadpool

i have an IntentService that should act like a manager and create Tasks in a queue (Runnable) that are submitted to a ThreadPool.
Im a little bit confused of the lifecycle of an IntentService:
The method protected abstract void onHandleIntent (Intent intent) runs already on a separated Thread. In the onHandleIntent I would create a new Runnable instance and submit it to the ThreadPool. My Service looks like this:
public class SyncService extends IntentService {
private final ThreadPoolExecutor threadPool;
public SyncService() {
super("SyncService");
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
threadPool = new ThreadPoolExecutor(1, 1, 20, TimeUnit.SECONDS, queue);
}
#Override
public void onCreate() {
super.onCreate();
EventBus.getInstance().register(this);
}
#Override
public void onDestroy() {
super.onDestroy();
EventBus.getInstance().unregister(this);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent.getAction().equals("sync")){
threadPool.submit(new SyncRunnable());
}else
if(intent.getAction().equals("delete")){
threadPool.submit(new DeleteRunnable());
} else
if(intent.getAction().equals("register")){
threadPool.submit(new RegisterRunnable())
}
}
}
My questions:
Is it a good idea to use a ThreadPool in a IntentService?
If I use a ThreadPool, than the IntentService will be destroyed if the Threadpool has no more Runnables to execute or queued, right?
Is IntentService already something that I want to achieve and should I simply execute my (long running) Runnable code in the
onHandleIntent() because this method alread runs on the
IntentService worker Thread? If yes, is there a queue limit for
intent, since onHandleIntent() could run up to 30 seconds before
finishing and handling the next Intent.
Is it a good idea to use a ThreadPool in a IntentService?
Not really. IntentService is already a single threaded (serial) variant of what you try to achieve. I would derive directly from Service.
If I use a ThreadPool, than the IntentService will be destroyed if the Threadpool has no more Runnables to execute or queued, right?
No. IntentService can go into the destroyed state once you return from onHandleIntent - i.e. immediately because threadPool.submit is non-blocking. Within the source it calls stopSelf(int) with the startId it got when the service was started.
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
A Service will go into destroyed state if you call stopSelf with the latest (highest) startId. It will keep running if a newer start is in the queue.
If the service goes into destroyed state it will not kill your thread pool because it has no knowledge about it. The problem is that Android now thinks that your service is dead and it will no longer count as a reason to keep your app process. The service running vs destroyed state is essentially just a way to tell Android that there is something going on and you don't want to get destroyed.
If you want to do it the right way you have to keep the service state in sync with what is actually going on.
Is IntentService already something that I want to achieve and should I simply execute my (long running) Runnable code in the onHandleIntent() because this method alread runs on the IntentService worker Thread?
If you are happy with single threaded serial execution yes. That's what onHandleIntent does for you.
If yes, is there a queue limit for intent, since onHandleIntent() could run up to 30 seconds before finishing and handling the next Intent.
There is no limit (it's a linked list as far as I can tell). But there is also nothing that stops you from producing more tasks than it can handle which will ultimately lead to some kind of overflow.

Stopping an Android Service from within a thread

I have a Service which starts a thread during onCreate(). The thread is monitoring hardware (IOIO) and will end once it is disconnected so essesentially is an infinite loop. Stopping the service from an Activity works fine and the thread also stops (ended in onDestory()).
My problem is that if the thread dies (say because of an exception) is it possible to stop the service that spawned it.
I've tried using stopSelf() from within the thread code but the service does not stop.
Thank you
ps my first post so please excuse any missing conventions I should have followed.
I think what you want here might be to use a Handler. Eseentially, create a handler for your Sevrice (make sure it's final so you can use across all threads). Then in your other thread, call:
myServiceHandler.post(new Runnable(){
public void run(){
stopSelf();
}
}
How about storing the Intent of the service and stopping it directly?
In the service:
private Intent thisIntent;
public int onStartCommand (Intent intent, int flags, int startId) {
thisIntent = intent;
In the thread inside the service:
stopService(thisIntent);

Categories

Resources