NullPointerException - Handler.removeCallbacks(java.lang.Runnable) - android

I got some crash reports from my app on console. I tried to fix it but I stucked. I'm using custom progress dialog, my problem is about that. What should I do? Should I use removeCallBack?
FlipProgressDialog fpd; // this is my custom progress dialog
#Override
public void onPause() {
super.onPause();
fpd.dismissAllowingStateLoss();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_top_feeds, container, false);
this.mView = view;
fpd = new FlipProgressDialog(); //and initialized here for escape the nullpointer exception but not worked
fpd.setImageList(imageList);
fpd.setCanceledOnTouchOutside(false);
// Handler handler = new Handler();
Runnable myRunnable = new Runnable() {
#Override
public void run() {
new Listeleme().execute();
}
};
myRunnable.run();
//handler.removeCallbacks(myRunnable);
//I guess I need call the above but I couldn't apply properly
return view;
}
private class Listeleme extends AsyncTask<Void,Void,Void>
{
String URL="...";
#Override
protected void onPreExecute()
{
super.onPreExecute();
fpd.show(getActivity().getFragmentManager(),"");
}
#Override
protected Void doInBackground(Void... params) {
//...
return null;
}
#Override
protected void onPostExecute(Void avoid)
{
if (getActivity()!= null) {
}
if (fpd.isVisible()) {
fpd.dismissAllowingStateLoss();
}
}
}
And this is the line 245 - FlipProgressDialog. java
#Override
public void onDestroyView() {
Dialog dialog = getDialog();
if (dialog != null && getRetainInstance()) {
dialog.setDismissMessage(null);
}
handler.removeCallbacks(r); // line 245
super.onDestroyView();
}

Apparently, some resources of your FlipProgressDialog are destroyed when you enter onPause(), so calling anything after everything gets destroyed causes that exception. Just try to call fpd.dismissAllowingStateLoss() before super.onPause()

Related

Toast in OnPostExecute() once the fragment changes

I have two fragments in my Activity : Fragment_A and Fragment_B.
In Fragment A, I created an AsyncTask (when the user "swipeRefreshes" the screen). In the onPostExecute() of this task, I want to display a Toast :
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
private Exception mLastError = null;
MakeRequestTask() {
//Some stuff
}
#Override
protected List<String> doInBackground(Void... params) {
//Some stuff
}
#Override
protected void onPreExecute() {
//Some stuff
}
#Override
protected void onPostExecute(List<String> output) {
swipeRefreshLayout.setRefreshing(false);
Toast.makeText(getActivity(), "TO_DISPLAY", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onCancelled() {
swipeRefreshLayout.setRefreshing(false);
//Some stuff
}
}
If the user changes from Fragment_A to Fragment_B before the AsyncTask finishes, I get a crash:
java.lang.IllegalStateException: Fragment Fragment_A not attached to a context.
I know how to avoid the crash (by adding the condition isAdded()), but I want my Toast to be displayed no matter which Fragment is displayed/alive on top of my Activity.
1stly I would like to suggest you, please make your MakeRequestTask inner class as static as this can be a memory leak.
For your question, You need to pass the context to the class like below:
private static class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
private Exception mLastError = null;
private WeakReference<Context> weakReference;
MakeRequestTask(Context context) {
//Some stuff
weakReference = new WeakReference<>(context);
}
#Override
protected List<String> doInBackground(Void... params) {
//Some stuff
}
#Override
protected void onPreExecute() {
//Some stuff
}
#Override
protected void onPostExecute(List<String> output) {
// swipe layout will not be shown if fragment is not visible or destroyed
if (isFragmentVisible) {
swipeRefreshLayout.setRefreshing(false);
}
// toast will be shown no matter what fragment is visible
if (weakReference != null) {
Context context = weakReference.get();
if (context != null) {
Toast.makeText(context, "TO_DISPLAY", Toast.LENGTH_SHORT).show();
}
}
}
#Override
protected void onCancelled() {
if (isFragmentVisible) {
swipeRefreshLayout.setRefreshing(false);
}
//Some stuff
}
}
Try this way
Declare a boolean in Fragment_A
private boolean isFragmentVisible=false;
In Fragment_A class
Make this boolean true in onCreateView() of this Fragment_A
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.lyourlayout, container, false);
isFragmentVisible = true;
return view;
}
And make this boolean false in onDestroyView() of this fragment A
#Override
public void onDestroyView() {
super.onDestroyView();
isFragmentVisible = false;
}
Finally use it in Asyntask of Fragment_A like this
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
private Exception mLastError = null;
MakeRequestTask() {
//Some stuff
}
#Override
protected List<String> doInBackground(Void... params) {
//Some stuff
}
#Override
protected void onPreExecute() {
//Some stuff
}
#Override
protected void onPostExecute(List<String> output) {
// swipe layout will not be shown if fragment is not visible or destroyed
if(isFragmentVisible){
swipeRefreshLayout.setRefreshing(false);
}
// toast will be shown no matter what fragment is visible
Toast.makeText(getActivity(), "TO_DISPLAY", Toast.LENGTH_SHORT).show();
}
#Override
protected void onCancelled() {
if(isFragmentVisible){
swipeRefreshLayout.setRefreshing(false);
}
//Some stuff
}
}
Or you can just use and interface or an EventBus in the onPostExecute method, and show the Toast inside the activity.
#Override
protected void onPostExecute(List<String> output) {
swipeRefreshLayout.setRefreshing(false);
activityContractInterface.showToast()
}
}
And in your Activity:
#Override
public void showToast(){
Toast.makeText(getActivity(), "TO_DISPLAY", Toast.LENGTH_SHORT).show();
}
Or the EventBus approach:
#Override
protected void onPostExecute(List<String> output) {
swipeRefreshLayout.setRefreshing(false);
EventBus.getDefault().post(new ShowToastEvent())
//just create an empty class, hope you know what EventBus is
}
And in your activity:
#Subscribe(threadMode = ThreadMode.Main){
Toast.makeText(getActivity(), "TO_DISPLAY", Toast.LENGTH_SHORT).show();
}
EventBusLibrary

What causes a fragment to get detached from an Activity?

I have a SignupActivity which will go through several fragments as users go through a signup process. On the last fragment, I'm calling
getActivity().setResult(Activity.RESULT_OK)
since SingupActivity intent was started for result. Some users are crashing at this point, because getActivity() is producing a NPE. I'm not able to figure out what is causing this. Screen rotation is disabled, so there is no reason that I know of for the fragment to detach from the Activity.
Any insight as to what may be causing this, and how I can resolve it?
public class SignupConfirmationFragment extends Fragment {
public static final String TAG = SignupConfirmationFragment.class.getSimpleName();
private User mNewUser;
private myAppClient mmyAppClient;
private Animation rotateAnimation;
private ImageView avatar;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNewUser = ((SignUpActivity) getActivity()).getNewUser();
mmyAppClient = ((SignUpActivity) getActivity()).getmyAppClient();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_signup_confirmation, null);
((TextView) v.findViewById(R.id.username_textView)).setText(((SignUpActivity) getActivity()).getNewUser().getName());
avatar = (ImageView) v.findViewById(R.id.avatar);
if (mNewUser.getAvatarImage() != null) {
avatar.setImageBitmap(mNewUser.getAvatarImage());
}
rotateAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.progress_rotate);
v.findViewById(R.id.progress_loading).startAnimation(rotateAnimation);
if (mNewUser.getAvatarImage() != null) {
startAvatarUpload();
} else if (mNewUser.getNewsletter()) {
setNewsletterStatus();
} else {
pauseForOneSecond();
}
return v;
}
private void startAvatarUpload() {
mmyAppClient.uploadUserAvatar(mNewUser.getAvatarImage(), new FutureCallback<JsonObject>() {
#Override
public void onCompleted(Exception e, JsonObject result) {
if (mNewUser.getNewsletter()) {
setNewsletterStatus();
} else {
updateFragment();
}
}
},
null,
null);
}
private void setNewsletterStatus() {
mmyAppClient.setNewsletter(mNewUser.getEmail(), mNewUser.getFirstName(), mNewUser.getLastName(), new FutureCallback<String>() {
#Override
public void onCompleted(Exception e, String result) {
//Log.d(TAG, "Result: " + result);
updateFragment();
}
});
}
private void pauseForOneSecond() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
updateFragment();
}
}, 1000);
}
private void updateFragment() {
rotateAnimation.cancel();
if (isAdded()) {
getActivity().setResult(Activity.RESULT_OK);
AnalyticsManager.logUIEvent("sign up completed");
getActivity().finish();
} else {
AnalyticsManager.logUIEvent("sign up failed");
}
}
}
According to Fragment lifecycle in Android OS, you cannot get the Activity associated with the fragment in the onCreateView, because the Activity with which the Fragment is associated will not be created at that stage.
See the figure below:
Also, refer to this link, http://developer.android.com/guide/components/fragments.html
As you can see the Activity is created in onActivityCreated which is after onCreateView, hence you'll get null if you try to call the Activity in the onCreateView. Try to call it in onActivityCreated or in onStart that should solve your problem.
I hope this helps.

Android best way to update UI thread from AsyncTask

I released an app today and I am getting some crash reports that indicate the following:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.app.Activity.findViewById(int)' on a null object reference
I have on Activity and a couple of Fragments. This error happens in one my Fragments where I have an AsyncTask:
private ProgressDialog dialog;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_dial, container, false);
dialog = new ProgressDialog(getActivity());
new CountryCodeTask().execute();
return view;
}
private class CountryCodeTask extends AsyncTask<Void, Void, ArrayList<String>>
{
#Override
protected void onPreExecute()
{
if (!dialog.isShowing()) {
dialog.show();
}
}
#Override
protected void onPostExecute(ArrayList<String> result)
{
if (dialog.isShowing()) {
dialog.dismiss();
}
if (result != null) {
Spinner countryCodeSpinner = (Spinner) getActivity().findViewById(R.id.country_code_spinner);
countryCodeSpinner.setAdapter(new CountryCodeAdapter(getActivity(), result));
countryCodeSpinner.setSelection(countryCodeSpinnerValue);
countryCodes = result;
}
}
#Override
protected ArrayList<String> doInBackground(Void... params)
{
return MainActivity.apiService.getCountryCodes();
}
}
I am guessing this is not the best way to update the UI thread from a ASyncTask. This error happens when I use the back/home button and then restart the app (but not all the time). What am I doing wrong here?
The error happens on this line: Spinner countryCodeSpinner = (Spinner) getActivity().findViewById(R.id.country_code_spinner);
You're not doing anything wrong really - it's to be expected that when you navigate away from an Activity via back/home, the AsyncTask will no longer have a reference to the Activity. I would modify your code to handle this common scenario:
#Override
protected void onPostExecute(ArrayList<String> result)
{
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
Activity activity = getActivity();
if (activity != null) {
if (result != null) {
Spinner countryCodeSpinner = (Spinner) activity.findViewById(R.id.country_code_spinner);
countryCodeSpinner.setAdapter(new CountryCodeAdapter(activity, result));
countryCodeSpinner.setSelection(countryCodeSpinnerValue);
countryCodes = result;
} else {
cancelTaskAndShowDialog();
}
}
}
When your AsyncTask finishes, after you pressed back and left the activity, getActivityreturns null.
You need to add a null check in onPostExecute
final Activity activity = getActivity()
if (dialog =! null && dialog.isShowing()) {
dialog.dismiss();
}
if (activity != null) {
if (result != null) {
Spinner countryCodeSpinner = (Spinner) activity.findViewById(R.id.country_code_spinner);
countryCodeSpinner.setAdapter(new CountryCodeAdapter(activity, result));
countryCodeSpinner.setSelection(countryCodeSpinnerValue);
countryCodes = result;
}
}
Try this:
private ProgressDialog dialog;
private Spinner countryCodeSpinner;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_dial, container, false);
dialog = new ProgressDialog(getActivity());
new CountryCodeTask().execute();
countryCodeSpinner = (Spinner) view.findViewById(R.id.country_code_spinner);
return view;
}
private class CountryCodeTask extends AsyncTask<Void, Void, ArrayList<String>>
{
#Override
protected void onPreExecute()
{
if (!dialog.isShowing()) {
dialog.show();
}
}
#Override
protected void onPostExecute(ArrayList<String> result)
{
if (dialog.isShowing()) {
dialog.dismiss();
}
if (result != null) {
countryCodeSpinner.setAdapter(new CountryCodeAdapter(getActivity(), result));
countryCodeSpinner.setSelection(countryCodeSpinnerValue);
countryCodes = result;
}
}
#Override
protected ArrayList<String> doInBackground(Void... params)
{
return MainActivity.apiService.getCountryCodes();
}
}

Custom progressbar dialog with dialogFragment

I'm new to android programming. I want to create a custom progress dialog with some textview and button and showing the progress with two progressBar and updating them while sending the files from Asynctask, Also I want it works with minimum API 10. google doc recommend me to use DialogFragment and i do not have any idea how to update the progress bars and textviews that are in that custom layout of my fragmentDialog, when I try to reference a textview or progress bar it throw null exeption
Here is my code
public static class FireMissilesDialogFragment extends DialogFragment {
public FireMissilesDialogFragment(){
}
public static FireMissilesDialogFragment newInstance(String title) {
FireMissilesDialogFragment frag = new FireMissilesDialogFragment();
Bundle args = new Bundle();
args.putString("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = this.getActivity().getLayoutInflater();
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View view = inflater.inflate(R.layout.custom_progress, null);
ProgressBar pbCurrent = (ProgressBar) view.findViewById(R.id.current);
builder.setView(view);
builder.setMessage("Fire Missiles")
.setPositiveButton("Fire", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// FIRE ZE MISSILES!
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
I got a nullExeption here in my main activity when try to reference a view
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button frag = (Button) findViewById(R.id.frag);
frag.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FireMissilesDialogFragment fragment = FireMissilesDialogFragment.newInstance("hi") ;
fragment.getActivity().findViewById(R.id.current);// nullExeption here
// downloadAsync as = new downloadAsync();
// as.execute();
}
});
I didn't see much question and example about that, did I go all the way wrong and should pick another way to achieve my point??!!
Edit :
I'm trying to create something like this
thanks in advance
I can not do a full explanation but I can leave an example and then hopefully you can figure out a way to incorporate the things you need.
The DialogFragment with an AsyncTask and a Progress bar:
public class LoadHydrantsToMapTaskFragment extends DialogFragment {
public static final String TAG = LoadHydrantsToMapTaskFragment.class
.getSimpleName();
public interface LoadHydrantsToMapTaskCallback {
void onPreExecute(int maxProgress);
void onProgressUpdate(int progress);
void onCancelled();
void onPostExecute();
}
private LoadHydrantsToMapTask mTask;
// private ProgressBar mProgressBar;
private List<HydrantHolder> mHydrants;
private GoogleMap map;
public static LoadHydrantsToMapTaskFragment newInstance(
List<HydrantHolder> hydrants, GoogleMap map) {
LoadHydrantsToMapTaskFragment taskFragment = new LoadHydrantsToMapTaskFragment();
taskFragment.mHydrants = hydrants;
taskFragment.map = map;
return taskFragment;
}
#Override public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_progress_task, container);
mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar);
mProgressBar.setProgress(0);
mProgressBar.setMax(mHydrants.size());
getDialog().setTitle(getActivity().getString(R.string.adding_hydrants));
// This dialog can't be canceled by pressing the back key.
getDialog().setCancelable(false);
getDialog().setCanceledOnTouchOutside(false);
return view;
}
/**
* This method will only be called once when the retained Fragment is first
* created.
*/
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(SherlockDialogFragment.STYLE_NORMAL, R.style.TuriosDialog);
// Retain this fragment across configuration changes.
setRetainInstance(true);
mTask = new LoadHydrantsToMapTask(mHydrants);
mTask.setCallback(new LoadHydrantsToMapTaskCallback() {
#Override public void onPreExecute(int maxProgress) {
}
#Override public void onProgressUpdate(int progress) {
mProgressBar.setProgress(progress);
}
#Override public void onPostExecute() {
if (isResumed())
dismiss();
mTask = null;
}
#Override public void onCancelled() {
if (isResumed())
dismiss();
mTask = null;
}
});
mTask.execute();
}
#Override public void onResume() {
super.onResume();
// This is a little hacky, but we will see if the task has finished
// while we weren't
// in this activity, and then we can dismiss ourselves.
if (mTask == null)
dismiss();
}
#Override public void onDetach() {
super.onDetach();
}
// This is to work around what is apparently a bug. If you don't have it
// here the dialog will be dismissed on rotation, so tell it not to dismiss.
#Override public void onDestroyView() {
if (getDialog() != null && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
// Also when we are dismissed we need to cancel the task.
#Override public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
// If true, the thread is interrupted immediately, which may do bad
// things.
// If false, it guarantees a result is never returned (onPostExecute()
// isn't called)
// but you have to repeatedly call isCancelled() in your
// doInBackground()
// function to check if it should exit. For some tasks that might not be
// feasible.
if (mTask != null)
mTask.cancel(false);
}
private class LoadHydrantsToMapTask extends
AsyncTask<Void, Integer, List<MarkerOptions>> {
// Before running code in separate thread
List<HydrantHolder> mHydrants;
LoadHydrantsToMapTaskCallback mLoadHydrantsToMapTaskCallback;
public LoadHydrantsToMapTask(List<HydrantHolder> hydrants) {
this.mHydrants = hydrants;
}
public void setCallback(
LoadHydrantsToMapTaskCallback loadHydrantsToMapTaskCallback) {
this.mLoadHydrantsToMapTaskCallback = loadHydrantsToMapTaskCallback;
}
#Override protected void onPreExecute() {
if (mLoadHydrantsToMapTaskCallback != null) {
mLoadHydrantsToMapTaskCallback.onPreExecute(mHydrants.size());
}
}
// The code to be executed in a background thread.
#Override protected List<MarkerOptions> doInBackground(Void... arg) {
List<MarkerOptions> markers = new ArrayList<MarkerOptions>();
for (HydrantHolder hydrant : mHydrants) {
final String hydrant_type = hydrant.getHydrantType();
final String hydrant_icon_path = hydrant.getIconPath();
double latitude = hydrant.getLatitude();
double longitude = hydrant.getLongitude();
final LatLng position = new LatLng(latitude, longitude);
final String address = hydrant.getAddress();
final String addressNumber = hydrant.getAddressNumber();
final String addressremark = hydrant.getAddressRemark();
final String remark = hydrant.getRemark();
// Log.d(TAG, hydrant.toString());
BitmapDescriptor icon = BitmapDescriptorFactory
.defaultMarker(BitmapDescriptorFactory.HUE_RED);
if (!hydrant_icon_path.isEmpty()) {
File iconfile = new File(hydrant_icon_path);
if (iconfile.exists()) {
BitmapDescriptor loaded_icon = BitmapDescriptorFactory
.fromPath(hydrant_icon_path);
if (loaded_icon != null) {
icon = loaded_icon;
} else {
Log.e(TAG, "loaded_icon was null");
}
} else {
Log.e(TAG, "iconfile did not exist: "
+ hydrant_icon_path);
}
} else {
Log.e(TAG, "iconpath was empty on hydrant type: "
+ hydrant_type);
}
StringBuffer snippet = new StringBuffer();
if (!address.isEmpty())
snippet.append("\n" + address + " " + addressNumber);
if (addressremark.isEmpty())
snippet.append("\n" + addressremark);
if (!remark.isEmpty())
snippet.append("\n" + remark);
markers.add(new MarkerOptions().position(position)
.title(hydrant_type).snippet(snippet.toString())
.icon(icon));
publishProgress(markers.size());
}
return markers;
}
// Update the progress
#Override protected void onProgressUpdate(Integer... values) {
if (mLoadHydrantsToMapTaskCallback != null) {
mLoadHydrantsToMapTaskCallback.onProgressUpdate(values[0]);
}
}
#Override protected void onCancelled() {
if (mLoadHydrantsToMapTaskCallback != null) {
mLoadHydrantsToMapTaskCallback.onCancelled();
}
}
// after executing the code in the thread
#Override protected void onPostExecute(List<MarkerOptions> markers) {
for (MarkerOptions marker : markers) {
if (marker != null && map != null)
map.addMarker(marker);
}
if (mLoadHydrantsToMapTaskCallback != null) {
mLoadHydrantsToMapTaskCallback.onPostExecute();
}
}
}
}
My dialog_progress_task layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:maxHeight="10dip"
android:minHeight="10dip"
android:progress="0"
android:progressDrawable="#drawable/progress_orange" />
</LinearLayout>
And finally the code I use to add it:
#Override public void loadHydrantsToMap(List<HydrantHolder> hydrants,
GoogleMap map) {
LoadHydrantsToMapTaskFragment loadHydrantsFragment;
if (fm != null) {
FragmentTransaction ft = fm.beginTransaction();
loadHydrantsFragment = (LoadHydrantsToMapTaskFragment) fm
.findFragmentByTag(LoadHydrantsToMapTaskFragment.TAG);
if (loadHydrantsFragment != null) {
Log.i("Attatching LoadHydrantsToMapTaskFragment");
ft.attach(loadHydrantsFragment);
} else {
loadHydrantsFragment = LoadHydrantsToMapTaskFragment
.newInstance(hydrants, map);
Log.i("Adding new LoadHydrantsToMapTaskFragment");
ft.add(loadHydrantsFragment, LoadHydrantsToMapTaskFragment.TAG);
}
ft.commit();
}
}

DialogFragment on Fragment with screen rotation

On my main activity I have a Fragment in which I apply setRetainInstance(true) so that the AsyncTask I use into it is not disturbed by orientation change.
A lot of work is processed by the AsyncTask. That's why I would like to display a dialog with a progressBar on top of my activity.
I made some researches and I succeed in doing with a DialogFragment:
public class DialogWait extends DialogFragment {
private ProgressBar progressBar;
public DialogWait() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_wait, container);
Dialog dialog = getDialog();
dialog.setTitle("Hello");
setCancelable(false);
progressBar = (ProgressBar) view.findViewById(R.id.progress);
return view;
}
public void updateProgress(int value) {
progressBar.setProgress(value);
}
And here is my AsyncTask:
public class InitAsyncTask extends AsyncTask<Void, Integer, Void> {
private Context activity;
private OnTaskDoneListener mCallback;
private DialogWait dialog;
public InitAsyncTask(Context context, OnTaskDoneListener callback, DialogWait dialogWait) {
activity = context;
mCallback = callback;
dialog = dialogWait;
}
#Override
protected Void doInBackground(Void... params) {
doStuff();
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
dialog.updateProgress(values[0]);
}
#Override
protected void onPostExecute(Void result) {
publishProgress(100);
if(dialog != null)
dialog.dismiss();
mCallback.onTaskDone();
}
private void doStuff() {
//...
}
}
If I don't change the screen rotation, it works fine. But if I do, the dialog is dismissed and a few seconds later, I got a NullPointerEsception which nonsense since I set the condition: if(dialog != null)
What am I doing wrong?
Solution found!
I was not doing the right thing with the Fragment containing my AsyncTask.
Because, I haven't really understood the concept of orientation in Fragment, I get it thanks to this link: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
Override onCreate, and onDestroyView methods in your DialogWait as follows:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onDestroyView() {
if (getDialog() != null && getRetainInstance()) {
getDialog().setDismissMessage(null);
}
super.onDestroyView();
}

Categories

Resources