Question

My intention is to have download service created when the app first runs and checks for update every 24 hours. I originally had everything running my main activity but it seems to much to run everything on one thread and one class. So this is my attempt to move it to another class and into service. It suppose to run and check for an update ever 24 hours and if there is no internet try again in 4 hours. I specifically want to involve any recursive problems, having two or three same services checking update, just one every 24 hours. But having problem with integrating my code into service, what am I doing wrong?

public class DownloadService extends IntentService {

// TODO 0 - Define your Download Service as Android component in
// AndroidManifest.xml
private int result = Activity.RESULT_CANCELED;

public DownloadService() {
    super("DownloadService");
}

// Will be called asynchronously be Android
@Override
protected void onHandleIntent(Intent intent) {

    private final Runnable mUpdateUi = new Runnable(){
        public void run(){
            check();
        }

    };

    private void start(){
       new Thread(
            new Runnable(){
                public void run(){
                    Log.d(TAG, "inside start");
                    Looper.prepare();
                    mHandler = new Handler();
                    check();
                    Looper.loop();
                }
            }
        ).run();
    }


    private void check(){
        if (isNetworkAvailable()== true){
            try {
                new checkupdate().execute();
                delayTime = 86400000;
                Toast.makeText(DownloadService.this, "Daily update check!", Toast.LENGTH_SHORT).show();
            } 
            catch (IOException e) {
                e.printStackTrace();
                delayTime = 21600000;
            }
        }else{
            delayTime = 21600000;
            Toast.makeText(DownloadService.this, "No internet for Daily update check, try again in little!", Toast.LENGTH_SHORT).show();
        }
        reCheck();
    }

    private void reCheck(){
        mHandler.postDelayed(mUpdateUi, delayTime);
    }

}
Was it helpful?

Solution

IntentService already handles setting up a worker thread and queue, and termination when the queue is empty. Which makes it a very good candidate for something like a download service to manage the actual work of downloading data, but not really a great candidate for a time scheduler.

I'd suggest using an AlarmManager to schedule your work instead. What you want is to trigger an Intent to start your DownloadService, by sending it intent with an Action indicating what to do.

Note also that if you want to cancel an IntentService with an Action, you will need to implement onStartCommand in addition to the usual onHandleIntent, so that you can respond to the action immediately -- you cannot do this from onHandleIntent, since the intent won't be sent to that until the current task in the queue is completed. Here's a quick example:

public class DownloadService extends IntentService {

    private static final String TAG = "DownloadService";

    ////////////////////////////////////////////////////////////////////////
    // Actions

    public static final String ACTION_CANCEL   = "package.name.DownloadService.action.CANCEL";
    public static final String ACTION_DOWNLOAD = "package.name.DownloadService.action.DOWNLOAD";

    ////////////////////////////////////////////////////////////////////////
    // Broadcasts

    public static final String BROADCAST_DOWNLOADED = "package.name.DownloadService.broadcast.DOWNLOADED";
    public static final String BROADCAST_ERROR      = "package.name.DownloadService.broadcast.ERROR";

    ////////////////////////////////////////////////////////////////////////
    // Extras

    public static final String MESSAGE = "package.name.DownloadService.extra.MESSAGE";
    // etc.

    private boolean isCancelled;

    // usual stuff omitted

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if(intent != null) {
            String action = intent.getAction();
            Log.v(TAG, "onStartCommand() - action: "+action);
            if(ACTION_CANCEL.equals(action)) {

                isCancelled = true;

                // insert code here to signal any objects to cancel
                // their work, etc.

                stopSelf();
            }
        }

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        if(intent != null) {
            final String action = intent.getAction();
            Log.v(TAG, "onHandleIntent() - action: "+action);
            if(ACTION_DOWNLOAD.equals(action)) {
                handleDownloading(intent);
            }
            else if(ACTION_CANCEL.equals(action)) {
                // nothing to do here, handled in onStartCommand
            }
        }
    }

    ////////////////////////////////////////////////////////////////////

    private void handleDownloading(Intent intent) {

        // get stuff you need from the intent using intent.getStringExtra(), etc.

        if(!isCancelled) {
            // do downloading, call broadcastDownloaded() when done
        }
        else {
            // stop work, send broadcast to report cancellation, etc.
        }
    }

    // send a broadcast to a BroadcastReceiver (e.g. in your activity)
    // to report that the download completed
    private void broadcastDownloaded() {
        Log.v(TAG, "broadcastDownloaded()");
        Intent broadcastIntent = new Intent();
        if (broadcastIntent != null) {
            broadcastIntent.setAction(BROADCAST_DOWNLOADED);
            broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
            sendBroadcast(broadcastIntent);
        }
    }

    private void broadcastError(String message) {
        Log.v(TAG, "broadcastError(), message: "+message);
        Intent broadcastIntent = new Intent();
        if (broadcastIntent != null) {
            broadcastIntent.setAction(BROADCAST_ERROR);
            broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
            if(message != null) {
                broadcastIntent.putExtra(MESSAGE, message);
            }
            sendBroadcast(broadcastIntent);
        }
    }
}

OTHER TIPS

This is not how IntentService is meant to be used. As per the documentation, IntentService already creates its own worker threads. You should not be creating your own:

Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

Apart from the fact that your code as shown here won't compile (your start method is inside the onHandleIntent method), your general approach seems to be to start your own worker thread. What would happen in this approach is that you would start the thread, onHandleIntent would complete and then the service would be stopped. In addition to not actually working, this approach is also a bad idea because (at best if you're lucky) the service would be running continually 24/7.

What you should do instead is actually do your main work in onHandleIntent which IntentService will queue on a worker thread for you. Then instead of using postDelayed use AlarmManager to set an alarm to send an Intent to start the service again in 24 hours or 4 hours.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top