Search code examples
androidlistviewandroid-fragmentsloaderasynctaskloader

AsyncTaskLoader not calling onFinishedLoad after orientation change


Some background information: I am using a Activity>ParentFragment(Holds ViewPager)>Child fragments. Child Fragments are added dynamically with add, remove buttons. I am using MVP architecture

Actual Problem: In child fragment, we have listview that populates using an asynctaskloader via a presenter.

Child Fragment:

//Initialize Views
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    root = inflater.inflate(R.layout.fragment_search_view_child, container, false);

.......

     mSearchViewPresenter= new SearchViewPresenter(
            getActivity(),
             new GoogleSuggestLoader(getContext()),
            getActivity().getLoaderManager(),
            this, id
    );

    SearchList list=new SearchList();
    //requestList from presenter
    searchListAdapter =new SearchViewListAdapter(getActivity(), list, this);
    listView.setAdapter(searchListAdapter);

......

    return root;
}



@Override
public void onResume(){
super.onResume();
    mSearchViewPresenter.start();
    searchBar.addTextChangedListener(textWatcher);


}

In the presenter class we have:

public SearchViewPresenter(@NonNull Context context, @NonNull GoogleSuggestLoader googleloader,@NonNull LoaderManager loaderManager,
                               @NonNull SearchViewContract.View tasksView, @NonNull String id) {
        // mLoader = checkNotNull(loader, "loader cannot be null!");
        mLoaderManager = checkNotNull(loaderManager, "loader manager cannot be null");
        // mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");
        mSearchView = checkNotNull(tasksView, "tasksView cannot be null!");

        mSearchView.setPresenter(this);

        searchList=new SearchList();
        this.googleLoader=googleloader;
        this.context=context;
        this.id=loaderID;
      //  this.id=Integer.parseInt(id);
    }

    @Override
    public void start() {


        Log.d("start>initloader","log");
        mLoaderManager.restartLoader(1, null, this);
    }

    //TODO implement these when you are ready to use loader to cache local browsing history


    @Override
    public android.content.Loader<List<String>> onCreateLoader(int i, Bundle bundle) {

        int loaderid=googleLoader.getId();
        Log.d("Loader: ", "created");
        googleLoader=new GoogleSuggestLoader(context);
        googleLoader.setUrl("");
        googleLoader.setUrl(mSearchView.provideTextQuery());
        return googleLoader;
    }

    @Override
    public void onLoadFinished(android.content.Loader<List<String>> loader, List<String> data) {
        Log.d("Loader: ", "loadFinished");
        searchList.clear();
        for (int i = 0; i < data.size(); ++i) {

            searchList.addListItem(data.get(i), null, LIST_TYPE_SEARCH, android.R.drawable.btn_plus);
           Log.d("data Entry: ",i+ " is: "+searchList.getText(i));
        }
        mSearchView.updateSearchList(searchList);

    }

    @Override
    public void onLoaderReset(android.content.Loader<List<String>> loader) {

    }

Also we have this code in the presenter that is triggered by a edittext box on the fragment view being edited.

  @Override
        public void notifyTextEntry() {
            //DETERMINE HOW TO GIVE LIST HERE
           // Dummy List
            Log.d("notifyTextEntry","log");
            if(googleLoader==null)googleLoader=new GoogleSuggestLoader(context);
                googleLoader.setUrl(mSearchView.provideTextQuery());
           // mLoaderManager.getLoader(id).abandon();


            mLoaderManager.getLoader(1).forceLoad();
            mLoaderManager.getLoader(1).onContentChanged();
            Log.d("length ", searchList.length().toString());
        //    googleLoader.onContentChanged();
        }

Lastly we have the loader here:

public class GoogleSuggestLoader extends AsyncTaskLoader<List<String>>{

    /** Query URL */
    private String mUrl;
    private static final String BASE_URL="https://suggestqueries.google.com/complete/search?client=firefox&oe=utf-8&q=";
    private List<String> suggestions =new ArrayList<>();


    public GoogleSuggestLoader(Context context) {
        super(context);
        this.mUrl=BASE_URL;

    }

    public void setUrl(String mUrl){
        this.mUrl=BASE_URL+mUrl;
    };
    @Override
    protected void onStartLoading() {forceLoad(); }
    @Override
    public List<String> loadInBackground() {
        if (mUrl == null) {
            return null;
        }

        try {
            suggestions = new ArrayList<>();
            Log.d("notifyinsideLoader","log");
            String result=GoogleSuggestParser.parseTemp(mUrl);
            if(result!=null) {
                JSONArray json = new JSONArray(result);
                if (json != null) {
                JSONArray inner=new JSONArray((json.getString(1)));
                    if(inner!=null){
                        for (int i = 0; i < inner.length(); ++i) {
                            //only show 3 results
                            if(i==3)break;
                            Log.d("notifyinsideLoader",inner.getString(i));
                            suggestions.add(inner.getString(i));
                        }

                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return suggestions;
    }





}

So the problem:

The code loads the data fine to the listview on the fragment. When orientation changes loader is not calling onLoadFinished. I have tested the loader and it is processing the data fine. I have already tried forceload and onContentChanged in the presenter to no avail. If you need anymore info or if I should just use something else like RxJava let me know. But I would really like to get this working. Before you ask I have seen similar problems like: AsyncTaskLoader: onLoadFinished not called after orientation change however I am using the same id so this problem should not exist.


Solution

  • The answer was on this page AsyncTaskLoader doesn't call onLoadFinished but details were not given as to how to move to this. So let me explain here for anyone else with this problem in future.

    Support library is meant for fragments. So the class that is in charge of callbacks has to be importing AND implementing the correct methods from the support library. Same as if you are using MVP your presenter must extend from support loadermanager. i.e: import android.support.v4.app.LoaderManager; Then implement correct callbacks.

    Like

    @Override
        public android.support.v4.content.Loader<List<String>> onCreateLoader(int i, Bundle bundle) {
    ...
    return new loader
    }
    

    and

    @Override
        public void onLoadFinished(android.support.v4.content.Loader<List<String>> loader, List<String> data) {
    //do something here to your UI with data
    }
    

    Secondly: The loader itself must be extending from support asynctaskloader. i.e: import android.support.v4.content.AsyncTaskLoader;