Should I Use Getapplicationcontext or Activity.This in a Long Running Asynctask

Should I use getApplicationContext or Activity.this in a long running AsyncTask

There is a reason to use each of the options.

When you are using the context in order to modify the UI, you should use the Activity context, since in some cases using the application context might cause an exception (as described here and here). Such as in the following case:

TextView senderNameTextView = new TextView(getApplicationContext());

When you are using the context in cross-activity usage, you should not bind the Activity context to the action, since then even if the activity is destroyed, it will not be garbage-collected, as it is still referenced from the running task. In those cases, you should use the Application context. See the article in Android Developer's site (written by Romain Guy) for even more details.

If you are only using the context to call getContentResolver, you should use the Application context.

getting context in AsyncTask

You need to do following things.

  • when you want to use AsyncTask, extend that in other class say MyCustomTask.
  • in constructor of new class, pass Context

Example

public class MyCustomTask extends AsyncTask<Void, Void, Long> {

private Context mContext;

public MyCustomTask (Context context){
mContext = context;
}

//other methods like onPreExecute etc.
protected void onPostExecute(Long result) {
Toast.makeText(mContext,"Subiendo la foto. ¡Tras ser moderada empezara a ser votada!: ", Toast.LENGTH_LONG).show();
}
}

And instantiate class by following.

MyCustomTask task = new MyCustomTask(context);
task.execute(..);

Starting Activity in AsyncTask passing context from activity

Since one of the argument of your AsyncTask is the activity you can directly use

Intent s = new Intent(activity, userLandingPage.class);
activity.startActivity(s);

How do i pass a context to an AsyncTask?

Pass a Context object into the AsyncTask's constructor.

Sample code:

public class MyTask extends AsyncTask<?, ? ,?> {
private Context mContext;

public MyTask(Context context) {
mContext = context;
}
}

and then, when you are constructing your AsyncTask:

MyTask task = new MyTask(this);
task.execute(...);

AlertDialog - Activity vs Application Context

There are two types of Context:

Application context is associated with the application and will always be same throughout the life of application -- it does not change. So if you are using Toast, you can use application context or even activity context (both) because toast can be displayed from anywhere with in your application and is not attached to a specific window. But there are many exceptions, one exception is when you need to use or pass the activity context.

Activity context is associated with to the activity and can be destroyed if the activity is destroyed -- there may be multiple activities (more than likely) with a single application. And sometimes you absolutely need the activity context handle. For example, should you launch a new activity, you need to use activity context in its Intent so that the new launching activity is connected to the current activity in terms of activity stack. However, you may use application's context too to launch a new activity but then you need to set flag Intent.FLAG_ACTIVITY_NEW_TASK in intent to treat it as a new task.

For more details

What's the difference between the various methods to get an Android Context?

I agree that documentation is sparse when it comes to Contexts in Android, but you can piece together a few facts from various sources.

This blog post on the official Google Android developers blog was written mostly to help address memory leaks, but provides some good information about contexts as well:

In a regular Android application, you
usually have two kinds of Context,
Activity and Application.

Reading the article a little bit further tells about the difference between the two and when you might want to consider using the application Context (Activity.getApplicationContext()) rather than using the Activity context this). Basically the Application context is associated with the Application and will always be the same throughout the life cycle of your app, where as the Activity context is associated with the activity and could possibly be destroyed many times as the activity is destroyed during screen orientation changes and such.

I couldn't find really anything about when to use getBaseContext() other than a post from Dianne Hackborn, one of the Google engineers working on the Android SDK:

Don't use getBaseContext(), just use
the Context you have.

That was from a post on the android-developers newsgroup, you may want to consider asking your question there as well, because a handful of the people working on Android actual monitor that newsgroup and answer questions.

So overall it seems preferable to use the global application context when possible.

Sending intent to MainActivity through (From) AsyncTask

You are getting an error because your activity is null. This happends because you have two constructors.

// this is the constructor that is called
public JSONTask(MainActivity mainActivity) {
dataSendToActivity = (OnDataSendToActivity)mainActivity;
}

// this is not called
public JSONTask(Activity activity){
this.activity = activity;
}

So your activity variable is never initialized.

See my changes,

public class JSONTask extends AsyncTask<String,String, String>{
OnDataSendToActivity dataSendToActivity;
Context context;

// single constructor to initialize both the context and dataSendToActivity
public JSONTask(Context context){
this.context = context;
dataSendToActivity = (OnDataSendToActivity) ((Activity) context);
}

@Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
StringBuffer buffer = new StringBuffer();

try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return buffer.toString();
}

@Override
protected void onPostExecute(String result) {
try {
JSONObject parentObject = new JSONObject(result);
JSONObject query = parentObject.getJSONObject("query").optJSONObject("results").optJSONObject("channel").optJSONObject("item");
String temperature = query.getJSONObject("condition").optString("temp");
String text = query.getJSONObject("condition").optString("text");
int code = query.getJSONObject("condition").optInt("code");
temperature += " °C " +" and "+ text;

if(dataSendToActivity != null){
dataSendToActivity.sendData(temperature, code);
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

In your MainActivity,

public class MainActivity extends AppCompatActivity implements OnDataSendToActivity {

public TextView temperatureTextView,textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

temperatureTextView = (TextView) findViewById(R.id.temperatureTextView);
textView = (TextView) findViewById(R.id.textView);

new JSONTask(this).execute("https://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20woeid%3D906057%20and%20u%3D%27c%27&format=json");
}

@Override
public void sendData(String str, String code) {
temperatureTextView.setText(str);
textView.setText(code);
}
}

Your OnDataSendToActivity interface will become,

public interface OnDataSendToActivity {
void sendData(String str, String code);
}

Using context reference after activity be finished

  1. First of all, in this situation you better go for service instead of asynctask. In your case, Service should stop itself once task is finished.
  2. Even if you go for asynctask, try to use application context that you can get from activity context as below:

    activity_context.getApplicationContext();

    The application context will be there even if activity is finished and also it will avoid memory leak.

  3. And if you want to make the asynctask run safely even if activity is finished, then try not to update any UI in postExecute(..) method as it will run on the UI of the activity which is already finished leading to exception. Try to do only any background task inside doInBackground(...) which runs on different thread.

Hope this answers your question.

Is Android Context thread safe?

You can always access the context from different Thread as long as you are not changing something and you only retrieve resources through the context I don't see a problem with Thread-safety.

The problem is that the context will stay in memory and active as long as the Thread runs. This is a good thing for you because you can rely on having a valid context all the time.
The bad thing is that if you pass an Activity as a context all the views and member variables from this activity will also stay in memory and this can lead to a very late garbage collection for a lot of memory, like Waqas suggested.

On thing I would not do from a different Thread is accessing methods from Context subclasses like setTheme() that will affect the currently displayed views.



Related Topics



Leave a reply



Submit