Android: How to add AsyncTaskLoader to this RecyclerView

534 views Asked by At

[Update] Added repository link to download the project

I'm having this activity which connects to a URL to fetch data and display it using RecyclerView with a custom adapter. How can I edit this code to use AsyncTaskLoader instead of AsyncTask? here's the repository to download the very simple project Soonami tutorial app

public class MainActivity extends AppCompatActivity {

  private RecyclerView recyclerView;
  public static QuakesAdapter quakesAdapter;
  public static ArrayList<Event> eventsList = new ArrayList<>();
  public static final String USGS_REQUEST_URL =
        "https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2018-01-01&endtime=2018-12-01&minmagnitude=6&limit=50";

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

    recyclerView = findViewById(R.id.recycler_view);
    quakesAdapter = new QuakesAdapter(this, eventsList);

    //defining recyclerView and setting the adapter

    quakesAdapter.notifyDataSetChanged();

    FetchData fetchData= new FetchData();
    fetchData.execute();
}


private class FetchData extends AsyncTask<String, Void, ArrayList<Event>> {

    String myDdata = "";
    String line = "";

    @Override
    protected ArrayList<Event> doInBackground(String... params) {

        try {

            //opening the connection

            if (httpURLConnection.getResponseCode() == 200) {
                InputStream inputStream = httpURLConnection.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

                while(line != null){
                    line = bufferedReader.readLine();
                    myDdata = myDdata + line;
                }

                JSONObject jsonObject = new JSONObject(myDdata);
                eventsList.clear();

                JSONArray jsonArray = jsonObject.getJSONArray("features");

                for(int i = 0; i < jsonArray.length(); i++){

                    //getting values of the 3 attributes

                    eventsList.add(new Event(title, time, tsunamiAlert));
                }

                if (inputStream != null) {
                    inputStream.close();
                }

            } else {
                Log.e("Connection Error: ", "Error response code: " + httpURLConnection.getResponseCode());
            }

            if (httpURLConnection != null) {
                httpURLConnection.disconnect();
            }

        }
        catch (MalformedURLException e) {
            e.printStackTrace();
        }

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

        return null;
    }

    @Override
    protected void onPostExecute(ArrayList<Event> result) {
        super.onPostExecute(result);
        quakesAdapter.notifyDataSetChanged();
    }
  }
}

I have tested multiple examples but they have different codes and triggers multiple errors with my code like this one and still looking for a solution which makes my code works fine.

2

There are 2 answers

1
Sultan Mahmud On BEST ANSWER

Set adpter in your recyclerview and then call the loader like this way:

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Event>> {
        {

            private RecyclerView recyclerView;
            public static QuakesAdapter quakesAdapter;
            public static ArrayList<Event> eventsList = new ArrayList<>();
            public static final String USGS_REQUEST_URL =
                    "https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2018-01-01&endtime=2018-12-01&minmagnitude=6&limit=50";

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

            recyclerView = findViewById(R.id.recycler_view);
            quakesAdapter = new QuakesAdapter(this, eventsList);

            //defining recyclerView and setting the adapter

            recyclerView.setAdapter(quakesAdapter);

            getSupportLoaderManager().initLoader(1, null, this).forceLoad();

        }

            @Override
            public Loader<List<Event>> onCreateLoader ( int id, Bundle args){
            return new FetchData(MainActivity.this);
        }
            @Override
            public void onLoadFinished (Loader < List < Event >> loader, List < Event > data){
            quakesAdapter.setData(data);
        }
            @Override
            public void onLoaderReset (Loader < List < Event >> loader) {
            quakesAdapter.setData(new ArrayList<Event>());

}

Performs actual task in background and returns the result.

private static class FetchData extends AsyncTaskLoader<List<Event>>{

        String myDdata = "";
        String line = "";
           public FetchData(Context context) {
            super(context);
        }
        @Override
        public List<Event> loadInBackground () {

            try {
                List<Event> list = new ArrayList<Event>();

                //opening the connection

                if (httpURLConnection.getResponseCode() == 200) {
                    InputStream inputStream = httpURLConnection.getInputStream();
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

                    while (line != null) {
                        line = bufferedReader.readLine();
                        myDdata = myDdata + line;
                    }

                    JSONObject jsonObject = new JSONObject(myDdata);

                    JSONArray jsonArray = jsonObject.getJSONArray("features");

                    for (int i = 0; i < jsonArray.length(); i++) {

                        //getting values of the 3 attributes

                        eventsList.add(new Event(title, time, tsunamiAlert));
                    }

                    if (inputStream != null) {
                        inputStream.close();
                    }

                } else {
                    Log.e("Connection Error: ", "Error response code: " + httpURLConnection.getResponseCode());
                }

                if (httpURLConnection != null) {
                    httpURLConnection.disconnect();
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
            }

            return eventsList;
        }
    }

Add a method in your adapter like this:

public void setData(List<Event> data) {
        this.data=data;
        notifyDataSetChanged();
    }
2
Shayan Khaksar On

Which kind of error do you encounter?

I suggest using Java Interface and CallBack method for your AsynkTask, in this scenario, whenever your AsynkTask task is done, it notify the Activity with that callback method and you can execute notifyDataSetChange method of the adapter.