Phil
Phil

Reputation: 4069

Android - AsyncTask error when ListView empty?

I have an app which uses tabs and fragments. On one of my tabs, I have a ListView which contains an header view and footer view.

The items in the list are gathered from my database via an XML feed that I get using an AsyncTask. When I items in the list, everything works exactly as it should. However, I noticed that when I have no items, and my listview is empty I get the error below when I try to switch tabs.

java.lang.IllegalStateException: Fragment Pending{3223f5a4} not attached to Activity

I do call myList.setAdapter(null) if my data comes back empty so that I at least see my list header/footer, but I've commented it out to eliminate it as a possibility and it still bombs on me.

What would make this happen? Again, everything works totally fine when I have data returned in my asynctask.

I can add more code as necessary, but wanted to wait to see if anyone knew off-hand what would cause this.

AsyncTask causing the problem

private class GetMaintenanceRequestsPending extends AsyncTask<String, Integer, Integer>
    {
        @Override
        protected void onPreExecute() { 
            progressDialog = ProgressDialog.show(getActivity(), "", getResources().getString(R.string.general_msg_please_wait));
        }

        @Override
        protected Integer doInBackground(String... params) {
            //First check if network is connected, if not take user to network error activity.
            if(!NetworkStatus.getInstance(getActivity().getApplicationContext()).isOnline(getActivity().getApplicationContext())) {
                return AppConstants.STATUS_NETWORK;
            }
            try {       
                getMaintenancePending(params[0],params[1]);
                if (maintenancePendingData == null) {
                    return AppConstants.STATUS_ERROR;
                } else {
                    return AppConstants.STATUS_SUCCESS;
                }
            } catch (Exception e) {
                return AppConstants.STATUS_ERROR;
            } 
        }

        @Override
        protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); }

        @Override
        protected void onPostExecute(Integer result) {
            // NETWORK ERROR HAS OCCURRED - SHOW NETWORK ACTIVITY
            if (result == AppConstants.STATUS_NETWORK) {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        progressDialog.dismiss();
                        Intent networkError = new Intent(getActivity(), NetworkError.class);
                        networkError.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        startActivity(networkError);
                        getActivity().finish();
                    }
                }, 1000);
            }
            // ERROR OCCURRED
            else if (result == AppConstants.STATUS_ERROR ) {
                progressDialog.dismiss();
                alertDialog.showAlertDialog(getActivity(), getString(R.string.error), getString(R.string.error_connect), false, false);
            }
            else {
                // SUCCESS!
                layoutMaintenanceSwipeRefresh.setRefreshing(false);
                Globals.refreshMaintenanceRequestData = false;
                setupPendingRequests();
            }
        }
    }       

What I don't understand is why would something in my AsyncTask be triggered anyway? It's called when the tab loads, and I'm moving OFF the tab, so why would it get called again?

Also, the setupPendingRequests() method of the AsyncTask onPostExecute method does get called. Everything looks to work exactly like it should...until I try to switch tabs. Then it throws the error. I noticed it will sometimes say WindowLeaked as the error, and other times the not attached to activity.

UPDATE 8.24.16

So I went through my code and tried removing anything that I could think of that would cause this error. Here is what I have found. In my fragment, I use the code below to trigger my UI work (AsyncTask, and setting ui element values) AFTER the animation is complete. When my listview was empty, for WHATEVER reason, this method is what is causing my problems.

//@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        Animation animation = super.onCreateAnimation(transit, enter, nextAnim);
        final Boolean fragmentShown = enter;
        if (animation == null && nextAnim != 0) {
            animation = AnimationUtils.loadAnimation(getActivity(), nextAnim);
        }
        if (animation != null) {
            if (getView() != null) {
                getView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                    }

                    public void onAnimationEnd(Animation animation) {
                        getView().setLayerType(View.LAYER_TYPE_NONE, null);
                        if (fragmentShown) {
                            new Handler().postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    setupFragment();
                                }
                            }, 200);
                        }
                    }
                });
            }
        } else {
            setupFragment();

From my understanding of how this method works, when I call if (fragmentShown) { ...my Ui stuff } I am waiting for the animation of the fragment to be complete and then do my work. I'm also checking if the animation is null, then no animation was set for this fragment and call the ui stuff.

Why would this method cause the problem when my listview dataset was empty? I don't understand. I've fixed it by removing this method and instead putting my setupFragment() call in the onResume() method of the fragment. But I want to understand WHY this happened, and if I can fix it somehow to keep the animation method in there. } return animation; }

Upvotes: 0

Views: 109

Answers (2)

Hamza
Hamza

Reputation: 2045

i am not sure it work for you because you not show your whole code , but it work for me , i just add this method in Recyler view fragment

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

  if (isVisibleToUser && mDataset.isEmpty()) {

        Log.i(TAG, "start Asyc task ");

        new LoadRssFeedsItems(getActivity()).execute(Constants.DW_HOME_PAGE_URL);


    }

}

Upvotes: 0

Ahlem Jarrar
Ahlem Jarrar

Reputation: 1129

Since you are performing background task in your app. there is no guarantee that user will stay on same screen until task finishes so if user navigates to other screen or presses home button before task is completed; your fragment is detached from activity. So always make sure that you have fragment attached with the Activity. try checking with

if (isAdded) {
//Do your UI stuff here
}

for More details please visit this link :

Fragment MyFragment not attached to Activity

Upvotes: 1

Related Questions