My app needs to access a shared preference file in the background. Ever since I started using the v21 support library's actionbaractivity to hold my fragment, my app force closes. It force closes whenever the fragment goes off screen, but the async task is still running and trying to access that sharedpreferences file. Why is it trowing this error and how do I fix it?
Here's the stack trace:
12-22 23:49:49.469: E/AndroidRuntime(23016): FATAL EXCEPTION: AsyncTask #4
12-22 23:49:49.469: E/AndroidRuntime(23016): Process: com.bernard.beaconportal.activities, PID: 23016
12-22 23:49:49.469: E/AndroidRuntime(23016): java.lang.RuntimeException: An error occured while executing doInBackground()
12-22 23:49:49.469: E/AndroidRuntime(23016): at android.os.AsyncTask$3.done(AsyncTask.java:300)
12-22 23:49:49.469: E/AndroidRuntime(23016): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
12-22 23:49:49.469: E/AndroidRuntime(23016): at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
12-22 23:49:49.469: E/AndroidRuntime(23016): at java.util.concurrent.FutureTask.run(FutureTask.java:242)
12-22 23:49:49.469: E/AndroidRuntime(23016): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
12-22 23:49:49.469: E/AndroidRuntime(23016): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
12-22 23:49:49.469: E/AndroidRuntime(23016): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
12-22 23:49:49.469: E/AndroidRuntime(23016): at java.lang.Thread.run(Thread.java:818)
12-22 23:49:49.469: E/AndroidRuntime(23016): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.SharedPreferences android.support.v4.app.FragmentActivity.getSharedPreferences(java.lang.String, int)' on a null object reference
12-22 23:49:49.469: E/AndroidRuntime(23016): at com.bernard.beaconportal.activities.Due_Tommorow_Fragment$Update.doInBackground(Due_Tommorow_Fragment.java:815)
12-22 23:49:49.469: E/AndroidRuntime(23016): at com.bernard.beaconportal.activities.Due_Tommorow_Fragment$Update.doInBackground(Due_Tommorow_Fragment.java:1)
12-22 23:49:49.469: E/AndroidRuntime(23016): at android.os.AsyncTask$2.call(AsyncTask.java:288)
12-22 23:49:49.469: E/AndroidRuntime(23016): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
12-22 23:49:49.469: E/AndroidRuntime(23016): ... 4 more
Here's the specific line of code where the error happens:
SharedPreferences userName = getActivity().getSharedPreferences(
"Login_Info", Context.MODE_PRIVATE);
Here's the async task where the error happens:
public class Update extends AsyncTask<String, Void, Void> {
private final HttpClient Client = new DefaultHttpClient();
@Override
protected Void doInBackground(String... urls) {
SharedPreferences bDay = getActivity().getSharedPreferences(
"Login_Info", Context.MODE_PRIVATE);
String day1 = Integer.toString(bDay.getInt("Day", 0));
String year1 = Integer.toString(bDay.getInt("Year", 0));
String month1 = Integer.toString(1 + bDay.getInt("Month", 0));
SharedPreferences userName = getActivity().getSharedPreferences(
"Login_Info", Context.MODE_PRIVATE);
String day = day1.replaceFirst("^0+(?!$)", "");
String month = month1.replaceFirst("^0+(?!$)", "");
String year = year1.replaceFirst("^0+(?!$)", "");
String birthday = month + "/" + day + "/" + year;
System.out.println("Birthday = " + birthday);
String user = userName.getString("username", "");
// String user = (username).split("@")[0];
System.out.println("Username = " + user);
try {
// HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
// HttpGet httpGet = new HttpGet(
// "http://www.beaconschool.org/~markovic/lincoln.php");
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(
"http://www.beaconschool.org/~markovic/lincoln.php");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
2);
nameValuePairs
.add(new BasicNameValuePair("username", user));
nameValuePairs.add(new BasicNameValuePair("birthday",
birthday));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
response = httpclient.execute(httppost);
Log.d("Http Response:", response.toString());
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
try {
Log.d("receiver", "animation stopped and downloaded file");
String homework = new Scanner(response.getEntity()
.getContent(), "UTF-8").useDelimiter("\\A").next();
// String homework =
// Html.fromHtml(duetommorow_html).toString();
SharedPreferences.Editor localEditor = getActivity()
.getSharedPreferences("homework",
Context.MODE_PRIVATE).edit();
SimpleDateFormat dateFormat = new SimpleDateFormat(
"MM/dd hh:mm a");
Calendar cal = Calendar.getInstance();
String downloaded = dateFormat.format(cal.getTime());
localEditor.putString("homework_content", homework);
localEditor.putString("download_date", downloaded);
localEditor.apply();
localEditor.putString("homework_content", homework);
localEditor.apply();
Log.d("receiver", "information given to shared preferences");
due_tommorow_list.clear();
parse_due_tommorow_string();
parse_due_tommorow_content();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
due_tommorow_list.clear();
parse_due_tommorow_string();
parse_due_tommorow_content();
SharedPreferences.Editor localEditor = getActivity()
.getSharedPreferences("homework",
Context.MODE_PRIVATE).edit();
localEditor.putString("download_error", "yes");
localEditor.apply();
e.printStackTrace();
}
catch (NoSuchElementException e) {
due_tommorow_list.clear();
parse_due_tommorow_string();
parse_due_tommorow_content();
SharedPreferences.Editor localEditor = getActivity()
.getSharedPreferences("homework",
Context.MODE_PRIVATE).edit();
localEditor.putString("download_error", "yes");
localEditor.apply();
e.printStackTrace();
}
catch (RuntimeException e) {
due_tommorow_list.clear();
parse_due_tommorow_string();
parse_due_tommorow_content();
SharedPreferences.Editor localEditor = getActivity()
.getSharedPreferences("homework",
Context.MODE_PRIVATE).edit();
localEditor.putString("download_error", "yes");
localEditor.apply();
e.printStackTrace();
}
} finally {
}
return null;
}
@Override
protected void onPostExecute(Void result) {
swipeLayout.setRefreshing(false);
Log.d("sender", "Broadcasting message");
Intent intent = new Intent("up_navigation");
intent.putExtra("message", "This is my message!");
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(
intent);
Toast.makeText(getActivity(), "Refresh Finished", 4000).show();
SharedPreferences download_error = getActivity()
.getSharedPreferences("homework", Context.MODE_PRIVATE);
String error = download_error.getString("download_error", "no");
String download_date = "Download error, refreshed homework using homework downloaded at "
+ download_error.getString("download_date", "");
if (error.equals("yes")) {
SharedPreferences.Editor localEditor = getActivity()
.getSharedPreferences("homework", Context.MODE_PRIVATE)
.edit();
Toast.makeText(getActivity(), download_date, Toast.LENGTH_LONG)
.show();
localEditor.putString("download_error", "no");
localEditor.commit();
}
adapter.notifyDataSetChanged();
swipeLayout.setRefreshing(false);
}
}
You do something time-consuming in an AsyncTask
, when the getActivity()
part is executed, the Activity has been destroyed. So the reference getActivity()
return null, which is quite correct.
Which you should do is in your Thread
or AsyncTask
, you should always check if getActivity()
is null, in case of the Activity
which host your Fragment
has been destroyed.
I don't think @I'm_With_Stupid 's answer is a good pratice, coz it's bad to hold an Activity
reference in your Fragment
and Fragment has already done that for you.