简体   繁体   English

RecyclerView,适配器,单击侦听器和AsyncTask

[英]RecyclerView, adapter, click listener and AsyncTask

I'm facing a issue while trying to implement AsyncTask (to fetch datas from USGS site). 我在尝试实现AsyncTask(从USGS站点获取数据)时遇到问题。 I've created an adapter to deal with datas and my recycler view. 我创建了一个适配器来处理数据和回收者视图。

Before implementing the AsyncTask I had an ArrayList of datas already populated and that worked fine. 在实现AsyncTask之前,我已经有一个已填充数据的ArrayList,并且工作正常。 Now I want to make the request dynamic by fetching datas from internet. 现在,我想通过从Internet提取数据来使请求动态化。 So I've implemented an AsyncTask but I think I'm not doing it right and, by the way, I've a blank page when I launch the app. 因此,我实现了一个AsyncTask,但我认为我做的不正确,顺便说一句,启动应用程序时,我的页面空白。

EarthQuakeActivity.java 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 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);
}...

Any idea of how to implement this would be very helpful. 关于如何实现这一点的任何想法都将非常有帮助。 If needed I can upload the full code on GitHub. 如果需要,我可以将完整的代码上传到GitHub。

PS : I'm using an interface to specify the behavior of the standard onClick method from View.OnClickListener PS:我正在使用一个接口来指定View.OnClickListener中的标准onClick方法的行为

OnItemClickListener OnItemClickListener

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

Change this 改变这个

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

into this 进入这个

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

I'd add two functions to your adapter: 我要为您的适配器添加两个功能:

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
}

Then inside your onPostExecute() call these functions: 然后在您的onPostExecute()内部调用以下函数:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM