3

I have a question on using AsyncTask class provided by Android sdk. I am starting a task in my code from the activity whose work is to send emails periodically (as per the specified time). I restart the task in onPostExecute(). It does send email periodically but after some time emails stop going. Does pressing the back button have any impact on it ?

I was going through the following link on AsyncTask and found that AsyncTask needs to be refreshed after the activities' orientation changes or is out of focus. Do I need to handle this separately ? Do i need to refresh the context everytime the activity is out of focus or its orientation changes ? There are certain DB operations I am doing based on context.

Here is my AsyncTask code :

public class SendEmailTask extends AsyncTask<String, Void, String> {
    private static final String LOG_TAG = "EmailTask";
    private static final int MESSAGE_SENT = StringConstants.CONSTANT_YES_FLAG;
    private Context context;

    public SendEmailTask(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(String... time) {
        // String message = "Message sent at ";
        try{
            //DB operations
            Validator validator = new Validator(context);
            int emailInterval = validator.validForSendingEmail(settingsMap);

            String emailId = settingsMap.get(DBSetting.COLUMN_EMAILID);
            String emailPwd = settingsMap.get(DBSetting.COLUMN_EMAIL_PWD);

            if (emailId != null && emailPwd != null && emailInterval > 0) {
                Thread.sleep((Integer.valueOf(emailInterval) * 60000));

                // TODO: formatting of email body
                DALLog dalLog = DALLog.getDALLogInstance();
                dalLog.init(context);

                GMailSender sender = new GMailSender(emailId, emailPwd);
                sender.sendMail("Mail From Auto responder",
                        result, emailId,
                        emailId);

                dalLog.close();
            }
            return null;
        }
        catch (NumberFormatException e) {
            e.printStackTrace();
            Log.d(LOG_TAG, e.getMessage());
        }
        catch (InterruptedException e) {
            e.printStackTrace();
            Log.d(LOG_TAG, e.getMessage());
        }
        catch (Exception e) {
            Log.d(LOG_TAG, e.getMessage());
        }
        return null;
    }

    @Override
    protected void onPostExecute(String result) {
        //DB operations
        Validator validator = new Validator(context);
        int emailInterval = validator.validForSendingEmail(settingsMap);

        // Start EmailTask thread if not started already
        SendEmailTask emailTask = new SendEmailTask(context);
        if (emailTask.getStatus() != AsyncTask.Status.RUNNING) {
            emailTask.execute(new String[]{});
        }
    }
}
Community
  • 1
  • 1
Adithya
  • 2,923
  • 5
  • 33
  • 47
  • 1
    yes. the asynctask exists only in the context that starts it. an activity, most likely. Use a service for background tasks. – njzk2 Jan 03 '13 at 08:19
  • 3
    also, you should know there is a limited amount of thread (by default) used for asynctask (a pool). blocking one is not a good idea. I would recommend using the alarmmanager for this. – njzk2 Jan 03 '13 at 08:20
  • agree with njzk2. Another remark, the condition "if (emailTask.getStatus() != AsyncTask.Status.RUNNING)" is totally useless – gezdy Jan 03 '13 at 08:35
  • @gezdy Also is the String parameter in `doInBackground(String... time)` and `onPostExecute(String result)` since he's not using it, so the call `emailTask.execute(new String[]{});` could be more simple: `emailTask.execute();` by changing the asynctask parameters to `SendEmailTask extends AsyncTask` – Aballano Jan 03 '13 at 08:43
  • Yes. I am going to remove those unwanted params. Secondly, i was thinking of sticking to Thread class provided by Java. Should that be helpful as i don't want to interact with the activity. A question still arises though. I need some way to access the application context. – Adithya Jan 03 '13 at 09:01

1 Answers1

1

When you start up a task that uses the context of an Activity, that task is being run in the same life cycle as the Activity. When the Activity is destroyed, its context is going to be lost with it, without a valid context the task will fail.

If you want a context that is available for the lifetime of the application, you should use getApplicationContext() which does not require an active Activity (and shouldn't be used to modify an Activity as a result).

Incorrect usage can also cause issues with garbage collection - objects being left floating around.

As has been mentioned in the comments section of your question, the best way to go forward, if you want to be able to run an AsyncTask whilst the application is not in the foreground (that is, in the background without the user's input required), is to create a Service which the AsyncTask can run within.

A Service will have its own context you can use, and you can bind the Service to your Activity if you want direct communication between the two.

For more info on Services see this Android Developer Article which provides an overview of their use

biddulph.r
  • 5,226
  • 3
  • 32
  • 47
  • Do you mean that when the activity is killed (which can happen when the activity is pushed behind) ,android automatically kills the asynctask and its context ? or simply removes i.e. nullifies the context present in the task ? – Adithya Jan 04 '13 at 06:57