问题
I'm trying to read the data from Firebase and display it in a recyclerview with a card layout. I have a seperate activity for writing to Firebase and a fragment that actually displays the data in the app.
The app builds fine and runs, but crashes when I try to look at the fragment containing the recyclerView.
1) Fragment displays RecyclerView
package com.nikelspot.alpha;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.List;
import static android.content.ContentValues.TAG;
public class FragExplore extends Fragment {
public FragExplore() {
//required empty default constructor
}
public DatabaseReference comBaseRef;
public FirebaseAuth mAuth;
public List<ComicBase> list = new ArrayList<>();
public RecyclerView recView;
private RecyclerView.Adapter adapter;
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.frag_explore,
container, false);
recView = rootView.findViewById(R.id.rec_view_buy);
recView.setLayoutManager(new LinearLayoutManager(getActivity()));
mAuth = FirebaseAuth.getInstance();
comBaseRef = FirebaseDatabase.getInstance().getReference();
comBaseRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
ComicBase comicBase = dataSnapshot.getValue(ComicBase.class);
list.add(comicBase);
adapter = new RecViewAdapter(getActivity(), list);
recView.setAdapter(adapter);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
return rootView;
}
}
2) RecyclerViewAdapter java
package com.nikelspot.alpha;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
public class RecViewAdapter extends RecyclerView.Adapter<RecViewAdapter.ViewHolder> {
public Context context;
public List<ComicBase> list;
public RecViewAdapter(Context context, List<ComicBase> List) {
this.list = List;
this.context = context;
}
// Create new views (invoked by the layout manager)
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// create a new view
View comicView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_items, null);
// create ViewHolder
ViewHolder viewHolder = new ViewHolder(comicView);
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ComicBase comicBase = list.get(position);
holder.comTitleHolder.setText(comicBase.getComTitle());
}
@Override
public int getItemCount() {
return list.size();
}
// inner class to hold a reference to each item of RecyclerView
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView comTitleHolder;
public ViewHolder(View comView) {
super(comView);
comTitleHolder = comView.findViewById(R.id.com_title);
}
}
}
3) Updated Getters/Setters java
package com.nikelspot.alpha;
public class ComicBase {
private String comTitle, comIssue, comGrade, comPrice;
public ComicBase(){
//No-argument constructor
//can leave empty
}
public ComicBase(String comTitle,
String comIssue,
String comGrade,
String comPrice){
this.comTitle = comTitle;
this.comIssue = comIssue;
this.comGrade = comGrade;
this.comPrice = comPrice;
}
public String getComTitle() {
return comTitle;
}
public void setComTitle(String comTitle) {
this.comTitle = comTitle;
}
public String getComIssue() {
return comIssue;
}
public void getComIssue(String comIssue) {
this.comIssue = comIssue;
}
public String getComGrade() {
return comGrade;
}
public void setComGrade(String comGrade) {
this.comGrade = comGrade;
}
public String getComPrice() {
return comPrice;
}
public void setComPrice(String comPrice) {
this.comPrice = comPrice;
}
}
4) Card View XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/cardview1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
card_view:cardElevation="5dp"
card_view:contentPadding="5dp"
card_view:cardCornerRadius="5dp"
card_view:cardMaxElevation="5dp">
<android.support.constraint.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ECEFF1"
android:padding="10dp">
<TextView
android:id="@+id/com_title_show"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#000"
android:textSize="20sp"
card_view:layout_constraintBottom_toBottomOf="parent"
card_view:layout_constraintEnd_toStartOf="@+id/com_issue_show"
card_view:layout_constraintHorizontal_bias="0.5"
card_view:layout_constraintStart_toStartOf="parent"
card_view:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/com_issue_show"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textColor="#000"
android:textSize="20sp"
card_view:layout_constraintBottom_toBottomOf="parent"
card_view:layout_constraintEnd_toStartOf="@+id/com_price_show"
card_view:layout_constraintHorizontal_bias="0.5"
card_view:layout_constraintStart_toEndOf="@+id/com_title_show"
card_view:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/com_grade_show"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:gravity="center"
android:textColor="#000"
android:textSize="20sp"
card_view:layout_constraintBottom_toBottomOf="parent"
card_view:layout_constraintEnd_toEndOf="parent"
card_view:layout_constraintStart_toEndOf="@+id/com_price_show"
card_view:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/com_price_show"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:gravity="center"
android:textColor="#000"
android:textSize="20sp"
card_view:layout_constraintBottom_toBottomOf="parent"
card_view:layout_constraintEnd_toStartOf="@+id/com_grade_show"
card_view:layout_constraintHorizontal_bias="0.5"
card_view:layout_constraintStart_toEndOf="@+id/com_issue_show"
card_view:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
5) Updated StackTrace
06-18 19:40:41.811 16590-16590/com.nikelspot.alpha E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.nikelspot.alpha, PID: 16590
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.nikelspot.alpha.RecViewAdapter.onBindViewHolder(RecViewAdapter.java:38)
at com.nikelspot.alpha.RecViewAdapter.onBindViewHolder(RecViewAdapter.java:13)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6673)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6714)
at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5647)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5913)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5752)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5748)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2232)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1559)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1519)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:614)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3812)
at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3225)
at android.view.View.measure(View.java:22024)
at android.support.constraint.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:1212)
at android.support.constraint.ConstraintLayout.onMeasure(ConstraintLayout.java:1552)
at android.view.View.measure(View.java:22024)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6584)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:22024)
at android.support.constraint.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:1212)
at android.support.constraint.ConstraintLayout.onMeasure(ConstraintLayout.java:1552)
at android.view.View.measure(View.java:22024)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6584)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:141)
at android.view.View.measure(View.java:22024)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6584)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1514)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:806)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:685)
at android.view.View.measure(View.java:22024)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6584)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:22024)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6584)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1514)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:806)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:685)
at android.view.View.measure(View.java:22024)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6584)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:746)
at android.view.View.measure(View.java:22024)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2434)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1522)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1775)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1410)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6816)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
06-18 19:40:41.812 16590-16590/com.nikelspot.alpha E/AndroidRuntime: at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6665)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:772)
回答1:
- In Your activity
public class ApprovedMeetingsActivity extends AppCompatActivity {
DatabaseReference rootRef, pendingMeetingsRef;
ListView pendingMeetingslist;
List<Meeting> meetings = new ArrayList<>();
MeetingsAdapter meetingsAdapter;
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pending_meetings);
pendingMeetingslist = findViewById(R.id.list);
rootRef = FirebaseDatabase.getInstance().getReference();
pendingMeetingsRef = rootRef.child("approved_meetings");
loadListFromFirebase();
}
private void loadListFromFirebase() {
pendingMeetingsRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
meetings.add(postSnapshot.getValue(Meeting.class));
meetingsAdapter = new MeetingsAdapter(ApprovedMeetingsActivity.this, meetings, "startmeet");
pendingMeetingslist.setAdapter(meetingsAdapter);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
- Getters and setters
public class Meeting {
String id;
String user;
String training;
String trainer;
String location;
String trainee;
public Meeting() {
//Empty Constructor For Firebase
}
public void setallmeetings(String id, String user, String training, String trainer, String location)
{
this.id = id;
this.user = user; //Parameterized for Program-Inhouse objects.
this.training = training;
this.trainer = trainer;
this.location = location;
}
//Getters and Setters
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getUser()
{
return user;
}
public void setUser(String user)
{
this.user = user;
}
public String getTraining()
{
return training;
}
public void setTraining(String training)
{
this.training = training;
}
public String getTrainer()
{
return trainer;
}
public void setTrainer(String trainer)
{
this.trainer = trainer;
}
public String getLocation()
{
return location;
}
public void setLocation(String location)
{
this.location = location;
}
public String getTrainee()
{
return trainee;
}
public void setTrainee(String trainee)
{
this.trainee = trainee;
}
- Then finally in adapter set the data
public class MeetingsAdapter extends BaseAdapter {
private List<Meeting> listData;
private LayoutInflater layoutInflater;
Context context;
String text;
List<String> ids = new ArrayList<>();
DatabaseReference rootRef, pendingMeetingsRef, canceledMeetingsRef;
SendMsgViewModel sendMsgViewModel;
CompositeSubscription subscription = new CompositeSubscription();
Float lat , lng ;
Location currentLocation;
private SimpleLocation location;
public MeetingsAdapter(Context context, List<Meeting> listData, String text) {
this.listData = listData;
layoutInflater = LayoutInflater.from(context);
this.context = context;
this.text = text;
}
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int position) {
return listData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.item_meeting_list, null);
holder = new ViewHolder();
holder.meeting = convertView.findViewById(R.id.training_txt);
holder.trainer = convertView.findViewById(R.id.trainer_txt);
holder.location = convertView.findViewById(R.id.location_txt);
holder.cancelMeetBtn = convertView.findViewById(R.id.cancel_meet_btn);
holder.startMeetBtn = convertView.findViewById(R.id.start_meet_btn);
if(text.equals("hidebtn")){
holder.cancelMeetBtn.setVisibility(View.GONE);
holder.startMeetBtn.setVisibility(View.GONE);
}
else if(text.equals("startmeet")){
holder.cancelMeetBtn.setVisibility(View.GONE);
holder.startMeetBtn.setVisibility(View.VISIBLE);
}
else {
holder.cancelMeetBtn.setVisibility(View.VISIBLE);
holder.startMeetBtn.setVisibility(View.GONE);
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
sendMsgViewModel = new SendMsgViewModel(new SendMsgInteractorImpl(), AndroidSchedulers.mainThread());
location = new SimpleLocation(context);
final PermissionListener permissionlistener = new PermissionListener() {
@Override
public void onPermissionGranted() {
Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show();
NotifyData notifydata = new NotifyData(String.valueOf(location.getLatitude()),
String.valueOf(location.getLongitude()));
subscription.add(sendMsgViewModel.sendMsg("key=AIzaSyCJT3Osi3pHf3K6nr_LRs1Xx0m0M5fID04",
new Message("cDjrAZSBTP4:APA91bG1hbHafiCuLRW_yy1OLbySkTXd0BPIvT5jA9xzZn4dW-4Cy0WRoqGKM9E6GSMumCd63Uu6xiksPYB1EmcOjn6v_jlZWsZ41I2z6laQtYlu7j57vimQVYOVXBNe1d8eBIqIZAfi",
notifydata,""))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Message>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Message message) {
}
}));
}
@Override
public void onPermissionDenied(ArrayList<String> deniedPermissions) {
Toast.makeText(context, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
}
};
rootRef = FirebaseDatabase.getInstance().getReference();
pendingMeetingsRef = rootRef.child("requested_meetings");
canceledMeetingsRef = rootRef.child("canceled_meetings");
for(int i=0; i < listData.size(); i++) {
ids.add(listData.get(position).getId());
}
holder.meeting.setText(listData.get(position).getTraining());
holder.trainer.setText(listData.get(position).getTrainer());
holder.location.setText(listData.get(position).getLocation());
holder.cancelMeetBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MaterialDialog.Builder(context)
.title("Cancel Meeting")
.backgroundColor(context.getResources().getColor(R.color.white))
.titleColor(context.getResources().getColor(R.color.black))
.contentColor(context.getResources().getColor(R.color.textColor))
.content("Are you sure you want to cancel this Meeting ?")
.positiveText("Yes")
.negativeText("No")
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
}
})
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
Meeting meet = new Meeting();
String id = canceledMeetingsRef.push().getKey();
meet.setId(id);
meet.setUser(listData.get(position).getUser());
meet.setTraining(listData.get(position).getTraining());
meet.setTrainer(listData.get(position).getTrainer());
meet.setLocation(listData.get(position).getLocation());
canceledMeetingsRef.child(id).setValue(meet);
listData.remove(position);
pendingMeetingsRef.child(ids.get(position)).removeValue();
ids.remove(position);
notifyDataSetChanged();
Toast.makeText(context,"Meeting successfully cancelled", Toast.LENGTH_SHORT).show();
}
})
.show();
}
});
holder.startMeetBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!location.hasLocationEnabled()) {
// ask the user to enable location access
SimpleLocation.openSettings(context);
return;
}
new MaterialDialog.Builder(context)
.title("Start Meeting")
.backgroundColor(context.getResources().getColor(R.color.white))
.titleColor(context.getResources().getColor(R.color.black))
.contentColor(context.getResources().getColor(R.color.textColor))
.content("Are you sure you want to start this Meeting ?")
.positiveText("Yes")
.negativeText("No")
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
}
})
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
location.beginUpdates();
TedPermission.with(context)
.setPermissionListener(permissionlistener)
.setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
.setPermissions(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
.check();
}
})
.show();
}
});
return convertView;
}
static class ViewHolder {
TextView meeting, trainer, location;
ImageView cancelMeetBtn;
LinearLayout startMeetBtn;
}
void updateLocation(Location location) {
currentLocation = location;
lat = (float) currentLocation.getLatitude();
lng = (float) currentLocation.getLongitude();
}
}
来源:https://stackoverflow.com/questions/50918372/reading-firebase-data-and-populating-recyclerview