jhnewkirk
jhnewkirk

Reputation: 87

Wait to call AsyncTask until a previous one finishes

I have an application on an android tablet that sends a log file back to me after the user does certain things. I have had it setup already, being able to send the log file that I am creating in an AsyncTask. As the log file gets bigger and bigger it takes longer to send, and I am starting to run into an issue where it starts sending another log file before the first one finishes.

The code is simply

private class SendLogFile extends AsyncTask<Void, Void, Void> {
    @Override
    protected Void doInBackground(Void... params) {
        //Send Log File From Tablet to Server
    }
}

being called with a simple

new SendLogFile().execute();

Is there a way for me to not run a new SendLogFile AsyncTask if there is one currently executing? I do NOT want to set it up as a recurring task with a timer, I still want it started off user actions.

Thanks.

Upvotes: 0

Views: 104

Answers (5)

Long Ranger
Long Ranger

Reputation: 6008

I suggested to use RxJava if it is possible, since the logic flow is more advanced and complicated in the future. And more separate thread is needed for the job. I think you should include some logic in Fragment/Activity for you work (They are in the zone between View and controller in MVC Pattern)

From Gabe Sechan's response, it would be great if you can just send the diff to the server. If it is not possible, you can to save the current checksum of the file in your device. At least it can save you the time to upload if there is no change in the log.

Tutorial is here for replacing asynctask. http://blog.stablekernel.com/replace-asynctask-asynctaskloader-rx-observable-rxjava-android-patterns/

Upvotes: 0

Juan Hurtado
Juan Hurtado

Reputation: 368

There is a simple solution for this problem, use Intent services. You can execute as many as you want and it will automatically create a qeue and execute it one after another until there are no commands left, that will solve your problem, use this class that i created.

public class FeedBackSyncCommand extends IntentService {

    public static final String ARG_LOG_FILE = "Log";

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public FeedBackSyncCommand(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String logFile = intent != null ?
                intent.getStringExtra(ARG_LOG_FILE) :
                "Log not available";

        // do stuff with your log file
    }
}

And you can use it this way (starting 10 instances of the service):

Intent feedBackCommand = 
                new Intent(getApplicationContext(), FeedBackSyncCommand.class);

    for (int i = 0; i < 11; i ++) {
        feedBackCommand.removeExtra(FeedBackSyncCommand.ARG_LOG_FILE);
        feedBackCommand.putExtra(FeedBackSyncCommand.ARG_LOG_FILE, 
                "This is an example log file" + 1);
        getApplicationContext().startService(feedBackCommand);
    }

Upvotes: 0

Buddy
Buddy

Reputation: 11028

Call newSingleThreadExecutor() and run your AsyncTask on the returned executor: https://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor()

Upvotes: 0

Hiemanshu Sharma
Hiemanshu Sharma

Reputation: 7862

You can use a ThreadPoolExecutor with a size of 1, and just submit tasks to it. It will only execute one after the other.

Upvotes: 0

Gabe Sechan
Gabe Sechan

Reputation: 93542

You realize that you're creating a bottleneck here, right? If you have trouble as the log file gets bigger, your approach is wrong. Don't send up the whole log, send up the diffs.

Ignoring that- I wouldn't use an AsyncTask. I'd use a Thread. The Thread sits around and waits for a send log message. When it gets one it sends it. Since its the only thread sending logs it can never be sending two at once.

Upvotes: 2

Related Questions