首页 > 解决方案 > 我的 recyclerView 适用于调试但不适用于“运行应用程序”

问题描述

我的代码如下所示:

package com.example.humspots.fragments;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.amplifyframework.AmplifyException;
import com.amplifyframework.api.aws.AWSApiPlugin;
import com.amplifyframework.api.graphql.model.ModelMutation;
import com.amplifyframework.api.graphql.model.ModelQuery;
import com.amplifyframework.core.Amplify;
import com.amplifyframework.datastore.generated.model.Event;
import com.example.humspots.R;
import com.example.humspots.adapters.EventAdapter;

import java.util.ArrayList;
import java.util.List;

import static com.parse.Parse.getApplicationContext;

/**
 * A simple {@link Fragment} subclass.
 */
public class EventsFragment extends Fragment {

    public static final String EVENTBRITE_URL = "https://www.eventbriteapi.com/v3/users/me/?token=FXZ47VT64UDMVS6KNOP4";
    public static final String HSU_URL = "https://25livepub.collegenet.com/calendars/student-project-humboldt-app.json";
    public static final String ORGANIZATION_URL = "https://www.eventbriteapi.com/v3/organizations/436148186604/events/?token=FXZ47VT64UDMVS6KNOP4";
    public static final String TAG = "EventsFragment";

    EventAdapter eventAdapter;

    List<Event> events;
    RecyclerView rvEvents;

    public EventsFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_events, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        rvEvents = view.findViewById(R.id.rvEvents);
        //bottomNavigationView = findViewById(R.id.bottomNavigation);

        events = new ArrayList<>();

        amplifyAndSetAdapter();
        eventAdapter.notifyDataSetChanged();
    }

    private void addEventToAWS() {
        Event todo = Event.builder().eventTitle("My todo")
                .eventDate("11/21/20")
                .eventTime("11:30:00")
                .extraInfo("AHHHHHHHHHHHHHHHHH")
                .category("temp")
                .description("this is a description")
                .template("Lost Coast")
                .postUrl("https://docs.amplify.aws/lib/graphqlapi/mutate-data/q/platform/android")
                .venue("McDonalds")
                .build();

        Amplify.API.mutate(
                ModelMutation.create(todo),
                response -> Log.i(TAG, "Added Todo with id: " + response.getData().getId()),
                error -> Log.e(TAG, "Create failed", error)
        );
    }

    private void amplifyAndSetAdapter() {
        initializeAmplify();
        amplifyQuery();
    }

    private void initializeAmplify() {
        try {
            // Add these lines to add the AWSApiPlugin plugins
            Amplify.addPlugin(new AWSApiPlugin());
            Amplify.configure(getApplicationContext());

            Log.i(TAG, "Initialized Amplify");
        } catch (AmplifyException error) {
            Log.e(TAG, "Could not initialize Amplify", error);
        }
    }

    private void amplifyQuery() {

        //create the adapter
        eventAdapter = new EventAdapter(getContext(), events);

        //set a layout manager on RV
        rvEvents.setLayoutManager(new LinearLayoutManager(getContext()));

        //set the adapter on the recycler view
        rvEvents.setAdapter(eventAdapter);
        Amplify.API.query(
                ModelQuery.list(Event.class),
                response -> {
                    for (Event event : response.getData()) {
                        Log.i("Amplify", event.getEventTitle() + " " + event.getEventDate() + " " + event.getEventTime() + " " + event.getCategory()
                                + " " + event.getPostUrl() + " " + event.getExtraInfo() + " " + event.getVenue() + " " + event.getTemplate());
                        addEvents(event);
                    }

                },
                error -> Log.e("Amplify", "Query failure", error)
        );

    }

    private void addEvents(Event event) {
        try {
            events.add(event);
            Log.i(TAG, "Events: " + events.size());
        } catch (Exception e) {
            Log.e(TAG, "Events: ", e);
        }
    }
}

EventAdapter 看起来像这样:

package com.example.humspots.adapters;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.amplifyframework.datastore.generated.model.Event;
import com.bumptech.glide.Glide;
import com.example.humspots.DetailActivity;
import com.example.humspots.R;

import org.parceler.Parcels;

import java.util.List;

public class EventAdapter extends RecyclerView.Adapter<EventAdapter.ViewHolder> {

    Context context;

    List<Event> events;

    public EventAdapter(Context context, List<Event> events) {
        this.context = context;
        this.events = events;
    }

    //usually involves inflating a layout from XML and returning the viewholder
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View eventView = LayoutInflater.from(context).inflate(R.layout.item_event, parent, false);
        return new ViewHolder(eventView);
    }

    //involves populating data into the item through holder
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        //get the event at the given position
        Event event = events.get(position);
        //bind the event data into the view holder
        holder.bind(event);
    }

    //returns the total number of items in the list
    @Override
    public int getItemCount() {
        return events.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        RelativeLayout container;
        TextView tvDay;
        TextView tvMonth;
        TextView tvEventTitle;
        TextView tvSummary;
        ImageView ivEventImage;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            container = itemView.findViewById(R.id.Container);
            tvDay = itemView.findViewById(R.id.tvDay);
            tvMonth = itemView.findViewById(R.id.tvMonth);
            tvEventTitle = itemView.findViewById(R.id.tvEventTitle);
            tvSummary = itemView.findViewById(R.id.tvSummary);
            ivEventImage = itemView.findViewById(R.id.ivEventImage);
        }

        public void bind(final Event event) {
            tvDay.setText(event.getDayOfMonth());
            tvMonth.setText(event.getMonthOfYear());
            tvEventTitle.setText(event.getEventTitle());
            tvSummary.setText(event.getDescription());

            //Glide.with(context).load(event.getPostUrl()).into(ivEventImage);

            //register the click listener on the whole container.
            container.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //then, navigate to new activity on click.
                    Intent i = new Intent(context, DetailActivity.class);
                    i.putExtra("event", Parcels.wrap(event));
                    context.startActivity(i);
                }
            });
        }
    }
}

事件如下所示:

package com.amplifyframework.datastore.generated.model;


import java.util.List;
import java.util.UUID;
import java.util.Objects;

import androidx.core.util.ObjectsCompat;

import com.amplifyframework.core.model.Model;
import com.amplifyframework.core.model.annotations.Index;
import com.amplifyframework.core.model.annotations.ModelConfig;
import com.amplifyframework.core.model.annotations.ModelField;
import com.amplifyframework.core.model.query.predicate.QueryField;

import static com.amplifyframework.core.model.query.predicate.QueryField.field;

/** This is an auto generated class representing the Event type in your schema. */
@SuppressWarnings("all")
@ModelConfig(pluralName = "Events")
public final class Event implements Model {
  public static final QueryField ID = field("id");
  public static final QueryField EVENT_TITLE = field("EventTitle");
  public static final QueryField DESCRIPTION = field("Description");
  public static final QueryField EVENT_DATE = field("EventDate");
  public static final QueryField EVENT_TIME = field("EventTime");
  public static final QueryField CATEGORY = field("Category");
  public static final QueryField POST_URL = field("PostURL");
  public static final QueryField EXTRA_INFO = field("ExtraInfo");
  public static final QueryField VENUE = field("Venue");
  public static final QueryField TEMPLATE = field("Template");
  private final @ModelField(targetType="ID", isRequired = true) String id;
  private final @ModelField(targetType="String") String EventTitle;
  private final @ModelField(targetType="String") String Description;
  private final @ModelField(targetType="String") String EventDate;
  private final @ModelField(targetType="String") String EventTime;
  private final @ModelField(targetType="String") String Category;
  private final @ModelField(targetType="String") String PostURL;
  private final @ModelField(targetType="String") String ExtraInfo;
  private final @ModelField(targetType="String") String Venue;
  private final @ModelField(targetType="String") String Template;
  public String getId() {
      return id;
  }
  
  public String getEventTitle() {
      return EventTitle;
  }
  
  public String getDescription() {
      return Description;
  }
  
  public String getEventDate() {
      return EventDate;
  }
  
  public String getEventTime() {
      return EventTime;
  }
  
  public String getCategory() {
      return Category;
  }
  
  public String getPostUrl() {
      return PostURL;
  }
  
  public String getExtraInfo() {
      return ExtraInfo;
  }
  
  public String getVenue() {
      return Venue;
  }
  
  public String getTemplate() {
      return Template;
  }
  
  private Event(String id, String EventTitle, String Description, String EventDate, String EventTime, String Category, String PostURL, String ExtraInfo, String Venue, String Template) {
    this.id = id;
    this.EventTitle = EventTitle;
    this.Description = Description;
    this.EventDate = EventDate;
    this.EventTime = EventTime;
    this.Category = Category;
    this.PostURL = PostURL;
    this.ExtraInfo = ExtraInfo;
    this.Venue = Venue;
    this.Template = Template;
  }
  
  @Override
   public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      } else if(obj == null || getClass() != obj.getClass()) {
        return false;
      } else {
      Event event = (Event) obj;
      return ObjectsCompat.equals(getId(), event.getId()) &&
              ObjectsCompat.equals(getEventTitle(), event.getEventTitle()) &&
              ObjectsCompat.equals(getDescription(), event.getDescription()) &&
              ObjectsCompat.equals(getEventDate(), event.getEventDate()) &&
              ObjectsCompat.equals(getEventTime(), event.getEventTime()) &&
              ObjectsCompat.equals(getCategory(), event.getCategory()) &&
              ObjectsCompat.equals(getPostUrl(), event.getPostUrl()) &&
              ObjectsCompat.equals(getExtraInfo(), event.getExtraInfo()) &&
              ObjectsCompat.equals(getVenue(), event.getVenue()) &&
              ObjectsCompat.equals(getTemplate(), event.getTemplate());
      }
  }
  
  @Override
   public int hashCode() {
    return new StringBuilder()
      .append(getId())
      .append(getEventTitle())
      .append(getDescription())
      .append(getEventDate())
      .append(getEventTime())
      .append(getCategory())
      .append(getPostUrl())
      .append(getExtraInfo())
      .append(getVenue())
      .append(getTemplate())
      .toString()
      .hashCode();
  }
  
  @Override
   public String toString() {
    return new StringBuilder()
      .append("Event {")
      .append("id=" + String.valueOf(getId()) + ", ")
      .append("EventTitle=" + String.valueOf(getEventTitle()) + ", ")
      .append("Description=" + String.valueOf(getDescription()) + ", ")
      .append("EventDate=" + String.valueOf(getEventDate()) + ", ")
      .append("EventTime=" + String.valueOf(getEventTime()) + ", ")
      .append("Category=" + String.valueOf(getCategory()) + ", ")
      .append("PostURL=" + String.valueOf(getPostUrl()) + ", ")
      .append("ExtraInfo=" + String.valueOf(getExtraInfo()) + ", ")
      .append("Venue=" + String.valueOf(getVenue()) + ", ")
      .append("Template=" + String.valueOf(getTemplate()))
      .append("}")
      .toString();
  }
  
  public static BuildStep builder() {
      return new Builder();
  }
  
  /** 
   * WARNING: This method should not be used to build an instance of this object for a CREATE mutation.
   * This is a convenience method to return an instance of the object with only its ID populated
   * to be used in the context of a parameter in a delete mutation or referencing a foreign key
   * in a relationship.
   * @param id the id of the existing item this instance will represent
   * @return an instance of this model with only ID populated
   * @throws IllegalArgumentException Checks that ID is in the proper format
   */
  public static Event justId(String id) {
    try {
      UUID.fromString(id); // Check that ID is in the UUID format - if not an exception is thrown
    } catch (Exception exception) {
      throw new IllegalArgumentException(
              "Model IDs must be unique in the format of UUID. This method is for creating instances " +
              "of an existing object with only its ID field for sending as a mutation parameter. When " +
              "creating a new object, use the standard builder method and leave the ID field blank."
      );
    }
    return new Event(
      id,
      null,
      null,
      null,
      null,
      null,
      null,
      null,
      null,
      null
    );
  }
  
  public CopyOfBuilder copyOfBuilder() {
    return new CopyOfBuilder(id,
      EventTitle,
      Description,
      EventDate,
      EventTime,
      Category,
      PostURL,
      ExtraInfo,
      Venue,
      Template);
  }
  public interface BuildStep {
    Event build();
    BuildStep id(String id) throws IllegalArgumentException;
    BuildStep eventTitle(String eventTitle);
    BuildStep description(String description);
    BuildStep eventDate(String eventDate);
    BuildStep eventTime(String eventTime);
    BuildStep category(String category);
    BuildStep postUrl(String postUrl);
    BuildStep extraInfo(String extraInfo);
    BuildStep venue(String venue);
    BuildStep template(String template);
  }
  

  public static class Builder implements BuildStep {
    private String id;
    private String EventTitle;
    private String Description;
    private String EventDate;
    private String EventTime;
    private String Category;
    private String PostURL;
    private String ExtraInfo;
    private String Venue;
    private String Template;
    @Override
     public Event build() {
        String id = this.id != null ? this.id : UUID.randomUUID().toString();
        
        return new Event(
          id,
          EventTitle,
          Description,
          EventDate,
          EventTime,
          Category,
          PostURL,
          ExtraInfo,
          Venue,
          Template);
    }
    
    @Override
     public BuildStep eventTitle(String eventTitle) {
        this.EventTitle = eventTitle;
        return this;
    }
    
    @Override
     public BuildStep description(String description) {
        this.Description = description;
        return this;
    }
    
    @Override
     public BuildStep eventDate(String eventDate) {
        this.EventDate = eventDate;
        return this;
    }
    
    @Override
     public BuildStep eventTime(String eventTime) {
        this.EventTime = eventTime;
        return this;
    }
    
    @Override
     public BuildStep category(String category) {
        this.Category = category;
        return this;
    }
    
    @Override
     public BuildStep postUrl(String postUrl) {
        this.PostURL = postUrl;
        return this;
    }
    
    @Override
     public BuildStep extraInfo(String extraInfo) {
        this.ExtraInfo = extraInfo;
        return this;
    }
    
    @Override
     public BuildStep venue(String venue) {
        this.Venue = venue;
        return this;
    }
    
    @Override
     public BuildStep template(String template) {
        this.Template = template;
        return this;
    }
    
    /** 
     * WARNING: Do not set ID when creating a new object. Leave this blank and one will be auto generated for you.
     * This should only be set when referring to an already existing object.
     * @param id id
     * @return Current Builder instance, for fluent method chaining
     * @throws IllegalArgumentException Checks that ID is in the proper format
     */
    public BuildStep id(String id) throws IllegalArgumentException {
        this.id = id;
        
        try {
            UUID.fromString(id); // Check that ID is in the UUID format - if not an exception is thrown
        } catch (Exception exception) {
          throw new IllegalArgumentException("Model IDs must be unique in the format of UUID.",
                    exception);
        }
        
        return this;
    }
  }
  

  public final class CopyOfBuilder extends Builder {
    private CopyOfBuilder(String id, String eventTitle, String description, String eventDate, String eventTime, String category, String postUrl, String extraInfo, String venue, String template) {
      super.id(id);
      super.eventTitle(eventTitle)
        .description(description)
        .eventDate(eventDate)
        .eventTime(eventTime)
        .category(category)
        .postUrl(postUrl)
        .extraInfo(extraInfo)
        .venue(venue)
        .template(template);
    }
    
    @Override
     public CopyOfBuilder eventTitle(String eventTitle) {
      return (CopyOfBuilder) super.eventTitle(eventTitle);
    }
    
    @Override
     public CopyOfBuilder description(String description) {
      return (CopyOfBuilder) super.description(description);
    }
    
    @Override
     public CopyOfBuilder eventDate(String eventDate) {
      return (CopyOfBuilder) super.eventDate(eventDate);
    }
    
    @Override
     public CopyOfBuilder eventTime(String eventTime) {
      return (CopyOfBuilder) super.eventTime(eventTime);
    }
    
    @Override
     public CopyOfBuilder category(String category) {
      return (CopyOfBuilder) super.category(category);
    }
    
    @Override
     public CopyOfBuilder postUrl(String postUrl) {
      return (CopyOfBuilder) super.postUrl(postUrl);
    }
    
    @Override
     public CopyOfBuilder extraInfo(String extraInfo) {
      return (CopyOfBuilder) super.extraInfo(extraInfo);
    }
    
    @Override
     public CopyOfBuilder venue(String venue) {
      return (CopyOfBuilder) super.venue(venue);
    }
    
    @Override
     public CopyOfBuilder template(String template) {
      return (CopyOfBuilder) super.template(template);
    }
  }
    public String getDayOfMonth() {
        return EventDate.substring(5, 7);
    }

    public String getMonthOfYear() {
        return EventDate.substring(0, 3);}
  
}

到目前为止,我已经尝试eventAdapter.notifyDataSetChanged();四处移动以使其在“运行应用程序”上运行;但是,无论我把它放在哪里,它都会抛出一个错误,或者它只会在我使用调试运行它时显示数据。

我尝试移动:

//create the adapter
eventAdapter = new EventAdapter(getContext(), events);

//set a layout manager on RV
rvEvents.setLayoutManager(new LinearLayoutManager(getContext()));

//set the adapter on the recycler view
rvEvents.setAdapter(eventAdapter);

也到不同的地方,但它不会改变任何东西。我不知道我做错了什么。

标签: javaandroidandroid-fragmentsandroid-recyclerviewaws-amplify

解决方案


我不得不改变一些事情以及添加一个新线程和等待功能:

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        rvEvents = view.findViewById(R.id.rvEvents);
        //set a layout manager on RV
        rvEvents.setLayoutManager(new LinearLayoutManager(getContext()));

        //set the adapter on the recycler view
        rvEvents.setAdapter(eventAdapter);

        amplifyAndSetAdapter();
        //for some reason the code only works with both notifyDataSetChanged (other is in the other thread)
        eventAdapter.notifyDataSetChanged();

    }

  

    private void amplifyAndSetAdapter() {
        initializeAmplify();
        amplifyQuery();
    }

    private void initializeAmplify() {
        try {
            // Add these lines to add the AWSApiPlugin plugins
            Amplify.addPlugin(new AWSApiPlugin());
            Amplify.configure(getApplicationContext());

            Log.i(TAG, "Initialized Amplify");
        } catch (AmplifyException error) {
            Log.e(TAG, "Could not initialize Amplify", error);
        }
    }

    private void amplifyQuery() {


        Amplify.API.query(
                ModelQuery.list(Event.class),
                response -> {
                    for (Event event : response.getData()) {
                        Log.i("Amplify", "Title: " + event.getEventTitle() + " Date: " + event.getEventDate() + " Time: " + event.getEventTime()
                                + " PostURL: " + event.getPostUrl() + " ExtraInfo: " + event.getExtraInfo() + " Venue: " + event.getVenue() + " Template: " + event.getTemplate());
                        addEvents(event);
                    }
                    //Used to seperate the ui using a wait function to add the proper time delay so that an error isnt thrown 
                    Thread thread = new Thread(){
                        @Override
                        public void run() {
                            try {
                                synchronized (this) {
                                    wait(100);

                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            eventAdapter.notifyDataSetChanged();
                                        }
                                    });

                                }
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }};
                    };
                    thread.start();
                },
                error -> Log.e("Amplify", "Query failure", error)
        );
    }

    private void addEvents(Event event) {
        try {
            events.add(event);
            Log.i(TAG, "Events: " + events.size());
        } catch (Exception e) {
            Log.e(TAG, "Events: ", e);
        }
    }

}

推荐阅读