RecyclerView, адаптер, прослушиватель кликов и AsyncTask - PullRequest
0 голосов
/ 30 апреля 2018

Я столкнулся с проблемой при попытке реализовать AsyncTask (для получения данных с сайта USGS). Я создал адаптер для работы с данными и представлением моего переработчика.

До реализации AsyncTask у меня уже был заполненный массив данных ArrayList, и он работал нормально. Теперь я хочу сделать запрос динамическим, выбирая данные из интернета. Итак, я реализовал AsyncTask, но я думаю, что я делаю это неправильно, и, кстати, у меня пустая страница, когда я запускаю приложение.

EarthQuakeActivity.java

public class EarthquakeActivity extends AppCompatActivity {
private List<EarthQuake> mEarthQuakes = new ArrayList<>();
private static final String USGS_URL =
        "https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&eventtype=" +
                "earthquake&orderby=time&minmag=5&limit=10";

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

    RecyclerView mEarthQuakeRecyclerView;
    RecyclerView.Adapter earthQuakeAdapter;

    // Lookup the recyclerview in activity layout
    mEarthQuakeRecyclerView = (RecyclerView) findViewById(R.id.list_recycler_view);

    // Use this setting to improve performance if you know that changes
    // in content do not change the layout size of the RecyclerView
    mEarthQuakeRecyclerView.setHasFixedSize(true);

    // Set layout manager to position the items
    mEarthQuakeRecyclerView.setLayoutManager(new LinearLayoutManager(this));

    // Start the AsyncTask to fetch the earthquake data
    EarthQuakeAsyncTask earthQuakeAsyncTask = new EarthQuakeAsyncTask();
    earthQuakeAsyncTask.execute(USGS_URL);

    // Create adapter passing in the sample user data
    // Third argument is a new OnItemClickListener defining the onItemClick() method behavior
    earthQuakeAdapter = new EarthQuakeAdapter(
            mEarthQuakes,
            this,
            new OnItemClickListener() {
                @Override
                public void onItemClick(View v, int position) {
                    // Get the url string of the earthquake item at position position
                    String url = mEarthQuakes.get(position).getmURL();
                    // Define a new intent to browse the url of the specific item
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    // Start the intent
                    startActivity(intent);
                }
            });

    // Attach the adapter to the recyclerview to populate items
    mEarthQuakeRecyclerView.setAdapter(earthQuakeAdapter);
}

/**
 * AsyncTask to perform the network request on a background thread, and then
 * update the UI with the list of earthquakes in the response.
 * AsyncTask has three generic parameters: the input type, a type used for progress updates, and
 * an output type. Our task will take a String URL, and return an Earthquake List. We won't do
 * progress updates, so the second generic is just Void.

 * We'll only override two of the methods of AsyncTask: doInBackground() and onPostExecute().
 * The doInBackground() method runs on a background thread, so it can run long-running code
 * (like network activity), without interfering with the responsiveness of the app.
 * Then onPostExecute() is passed the result of doInBackground() method, but runs on the
 * UI thread, so it can use the produced data to update the UI.
 */
public class EarthQuakeAsyncTask extends AsyncTask<String, Void, List<EarthQuake>> {
    /**
     * This method runs on a background thread and performs the network request.
     * We should not update the UI from a background thread, so we return a list of
     * EarthQuake(s) as the result.
     */
    @Override
    protected List<EarthQuake> doInBackground(String... urls) {
        // Don't perform the request if there are no URLs, or the first URL is null
        if (urls.length < 1 || urls[0] == null) return null;

        return QueryUtils.fetchEarthquakeData(urls[0]);
    }

    /**
     * This method runs on the main UI thread after the background work has been
     * completed. This method receives as input, the return value from the doInBackground()
     * method.
     */
    @Override
    protected void onPostExecute(final List<EarthQuake> list) {
        mEarthQuakes.clear();
        mEarthQuakes.addAll(list);
    }
}

EarthQuakeAdapter.java

public class EarthQuakeAdapter extends RecyclerView.Adapter<EarthQuakeAdapter.ViewHolder> {
    /** Privates attributes */
// Define a member variable to store the context
private Context mContext;
// Define a member variable to store the earth quakes
private List<EarthQuake> mEarthQuakes;
// Define a member variable to set up the listener
private OnItemClickListener mListener;

/** Public constructors */
// Default constructor with no parameters
public EarthQuakeAdapter() {}

// Default constructor with parameters (we pass in the earthQuakes array into the constructor)
public EarthQuakeAdapter(List<EarthQuake> earthQuakes,
                         Context context,
                         OnItemClickListener listener) {
    this.mEarthQuakes = earthQuakes;
    this.mContext = context;
    this.mListener = listener;
}

/** Inner class */
// Provide a direct reference to each of the view within a data item
// Used to cache the views within the item layout for fast access
public static class ViewHolder extends RecyclerView.ViewHolder {
    // Your holder should contain a member variable for any view that will be set as you
    // render a row
    private TextView magnitudeTextView;
    private TextView distanceOfLocationTextView;
    private TextView locationTextView;
    private TextView dateTextView;
    private TextView timeTextView;

    // We also create a constructor (by design) that accepts the entire item row
    // and does the view lookups to find each subview
    public ViewHolder(View itemView) {
        // Stores the itemView in a public final member variable that can be used
        // to access the context from any ViewHolder instance
        super(itemView);
        magnitudeTextView = (TextView) itemView.findViewById(R.id.magnitude_text_view);
        distanceOfLocationTextView =
                (TextView) itemView.findViewById(R.id.distanceOfLocation_text_view);
        locationTextView = (TextView) itemView.findViewById(R.id.location_text_view);
        dateTextView = (TextView) itemView.findViewById(R.id.date_text_view);
        timeTextView = (TextView) itemView.findViewById(R.id.time_text_view);
    }
}

/** Methods */
// Usually involves inflating a layout from XML and returning the holder
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(mContext);
    // Inflate the custom layout
    View earthQuakeView =
            inflater.inflate(R.layout.list_earthquake, parent, false);
    // Create a new view holder
    final ViewHolder earthQuakeViewHolder = new ViewHolder(earthQuakeView);
    // Attach a listener on the earthQuakeView view
    earthQuakeView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mListener.onItemClick(v, earthQuakeViewHolder.getAdapterPosition());
        }
    });
    // Return a new holder instance
    return earthQuakeViewHolder;
}

// Involve populating data into the item through holder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    // Get the data model based on position
    EarthQuake currentEarthQuake = mEarthQuakes.get(position);

    // Call to getFormattedMagnitude to get a properly formatted magnitude string value
    String magnitudeOutput = getFormattedMagnitude(currentEarthQuake.getmMagnitude());

    // Set the proper background color on the magnitude circle.
    // Fetch the background from the TextView, which is a GradientDrawable.
    GradientDrawable magnitudeCircle =
            (GradientDrawable) holder.magnitudeTextView.getBackground();

    // Get the appropriate background color based on the current earthquake magnitude
    int magnitudeColor = getMagnitudeColor(currentEarthQuake.getmMagnitude());

    // Set the color on the magnitude circle
    magnitudeCircle.setColor(magnitudeColor);

    // Array that will contain the splitted location
    String[] distanceOfLocation = getFormattedLocation(currentEarthQuake.getmLocation());

    // Create a an object based on the item date and calls to functions to format the output
    // ex formatDate : "jan 28, 2016"
    // ex formatTime : "10:40"
    Date dateObject = new Date(currentEarthQuake.getmDate());
    String dateToDisplay = formatDate(dateObject);
    String timeToDisplay = formatTime(dateObject);

    // Set item views based on the view and data model
    holder.magnitudeTextView.setText(magnitudeOutput);
    holder.distanceOfLocationTextView.setText(distanceOfLocation[0]);
    holder.locationTextView.setText(distanceOfLocation[1]);
    holder.dateTextView.setText(dateToDisplay);
    holder.timeTextView.setText(timeToDisplay);
}...

Любая идея о том, как реализовать это, была бы очень полезной. При необходимости я могу загрузить полный код на GitHub.

PS: я использую интерфейс для определения поведения стандартного метода onClick из View.OnClickListener

OnItemClickListener

public interface OnItemClickListener {
void onItemClick(View v, int position);
}

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Я бы добавил две функции к вашему адаптеру:

public void clear() {
    mEarthQuakes.clear();
    notifyDataSetChanged(); 
    // you can also call the other notify methods instead to provide animations
}

public void addAll(List<EarthQuake> newList) {
    mEarthQuakes.addAll(newList);
    notifyDataSetChanged(); 
    // you can also call the other notify methods instead to provide animations
}

Тогда внутри вашего onPostExecute() вызовите эти функции:

@Override
protected void onPostExecute(final List<EarthQuake> list) {
    earthQuakeAdapter.clear();
    earthQuakeAdapter.addAll(list);
}
0 голосов
/ 30 апреля 2018

Изменить это

@Override
protected void onPostExecute(final List<EarthQuake> list) {
    mEarthQuakes.clear();
    mEarthQuakes.addAll(list);
}

в это

@Override
protected void onPostExecute(final List<EarthQuake> list) {
    mEarthQuakes.clear();
    mEarthQuakes.addAll(list);
    EarthQuakeAdapter.notifyDataSetChanged();
}
...