I am trying to display the following JSON structure in a recyclerView using FirebaseUI and its recyclerAdapter.
I am following the example (with my own changes here and there) made by the Firebase team I presume, found here Firebase Quickstart - Database
JSON Firebase structure:
{
"restaurants": {
"pushID": {
"name": "string",
"address": "string",
"times": "string",
"logo": "string",
"phone": "string",
"email": "string",
"order": "true", //Boolean
"booking": "true",
"delivery": "false"
},
...
}
}
I have already looked at the current posts about receiving "NoSuchMethodException" on here and other sites i.e. GitHub.
The general answer seems to be that there are two likely causes for this:
1) make sure that your viewHolder class is public
2) if your TaskViewHolder is an inner class of e.g. your activity, make sure it's static
Here are is the relevant code.
Model:
@IgnoreExtraProperties
public class Restaurant {
public String name, address,
time, logo, phone;
public String uid;
public int favoriteCount = 0;
public Map<String, Boolean> favorites = new HashMap<>();
public Restaurant(){
// Default constructor required for calls to DataSnapshot.getValue(Restaurant.class)
}
public Restaurant(String name, String address, String time,
String logo, String phone, String uid){
this.name = name;
this.address = address;
this.time = time;
this.logo = logo;
this.phone = phone;
this.uid = uid;
}
@Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("uid", uid);
result.put("name", name);
result.put("time", time);
result.put("logo", logo);
result.put("favoriteCount", favoriteCount);
result.put("favorites", favorites);
return result;
}
}
My viewHolder class (which is a separate class; therefore no need for "static").
The EllipsisUtil.class is a method I use keep the text view restricted to a single line. Nothing fancy.
public class RestaurantViewHolder extends RecyclerView.ViewHolder {
public TextView restaurantName, restaurantAddress; //tvDate, tvTime, tvPeople;
public ImageView restaurantImageLogo, restaurantFavorite;
private final Activity activity;
private Locale locale = Locale.US;
//private SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM dd yyyy", locale);
public RestaurantViewHolder(Activity activity, View itemView){
super(itemView);
this.activity = activity;
restaurantName = (TextView) itemView.findViewById(R.id.resName);
restaurantAddress = (TextView) itemView.findViewById(R.id.resAddress);
restaurantImageLogo = (ImageView) itemView.findViewById(R.id.RestaurantLogo);
restaurantFavorite = (ImageButton) itemView.findViewById(R.id.rFavorite);
//additional views for bookings activity
/*
tvDate = (TextView) itemView.findViewById(R.id.bookingDate);
tvTime = (TextView) itemView.findViewById(R.id.bookingTime);
tvPeople = (TextView) itemView.findViewById(R.id.numberPeople);
*/
}
public void bindToRestaurant(Restaurant restaurant, View.OnClickListener favoriteClickListener) {
//final int peopleNum = Integer.parseInt(restaurantInfo.booking_people);
restaurantName.setText(restaurant.name);
singleLineText(restaurantName);
restaurantAddress.setText(restaurant.address);
singleLineText(restaurantAddress);
restaurantFavorite.setOnClickListener(favoriteClickListener);
// Create a storage reference from our app
String dirName = "restaurantLogos/";
String bucketUrl = "myFirebaseURL/";
// Initialize Storage
StorageReference mStorageRef = FirebaseStorage.getInstance().getReference();
StorageReference storageRef = mStorageRef.getStorage().
getReferenceFromUrl(bucketUrl+dirName+restaurant.logo+".png");
String logoUrl = storageRef.getDownloadUrl().toString();
Glide.with(activity).load(logoUrl).into(restaurantImageLogo);
//additional views for bookings activity
/*
tvDate.setText(dateFormat.format(restaurantInfo.booking_date));
tvTime.setText(restaurantInfo.booking_time);
String people;
if (peopleNum > 1){
people = restaurantInfo.booking_people+" people";
}else{
people = restaurantInfo.booking_people+" person";
}
tvPeople.setText(people);
*/
}
public void singleLineText(TextView textView){
EllipsisUtil ellipsisUtil = new EllipsisUtil(textView);
ellipsisUtil.singleLineText();
}
}
My activity class that handles the Firebase adapter
// Set up FirebaseRecyclerAdapter with the Query
Query restaurantQuery = getQuery(mDatabase);
mAdapter = new FirebaseRecyclerAdapter<Restaurant, RestaurantViewHolder>(Restaurant.class, R.layout.list_row,
RestaurantViewHolder.class, restaurantQuery) {
@Override
protected void populateViewHolder(final RestaurantViewHolder viewHolder, final Restaurant model, int position) {
final DatabaseReference restaurantRef = getRef(position);
final String restaurantKey = restaurantRef.getKey();
//setting Strings data for intent data passing
//final String time = model.restaurant_time;
//final String phone = model.restaurant_phone;
//Log.d(TAG, "2: "+time+" / "+phone);
// Set click listener for the whole post view
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//starting a new intent from onClick action
Context context = v.getContext();
//RV = Restaurant View
Intent intentRV = new Intent(context, Restaurant.class);
intentRV.putExtra("rName", viewHolder.restaurantName.getText().toString());
intentRV.putExtra("rAddress", viewHolder.restaurantAddress.getText().toString());
//intentRV.putExtra("rTime",time);
//intentRV.putExtra("rPhone",phone);
//pass RID to next activity
intentRV.putExtra("resID", restaurantKey);
context.startActivity(intentRV);
}
});
// Determine if the current user has liked this post and set UI accordingly
if (model.favorites.containsKey(getUid())) {
viewHolder.restaurantFavorite.setImageResource(R.drawable.ic_favorite_white_24dp);
} else {
viewHolder.restaurantFavorite.setImageResource(R.drawable.ic_favorite_border_white_24dp);
}
viewHolder.bindToRestaurant(model, new View.OnClickListener() {
@Override
public void onClick(View favoriteView) {
// Need to write to both places the post is stored
DatabaseReference globalRestaurantRef = mDatabase.child("favorites").child(restaurantRef.getKey());
DatabaseReference userRestaurantRef = mDatabase.child("user_favorites").child(model.uid).child(restaurantRef.getKey());
// Run two transactions
onFavoriteClicked(globalRestaurantRef);
onFavoriteClicked(userRestaurantRef);
}
});
}
};
recyclerView.setAdapter(mAdapter);
}
My query method
public Query getQuery(DatabaseReference databaseReference){
// All the restaurants
return databaseReference.child("restaurants");//restaurants
}
The Logcat error I get:
java.lang.RuntimeException: java.lang.NoSuchMethodException: <init> [class android.view.View]
at com.firebase.ui.database.FirebaseRecyclerAdapter.onCreateViewHolder(FirebaseRecyclerAdapter.java:171)
at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6290)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5478)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5363)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5359)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2141)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1525)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1488)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:585)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3506)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3254)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1623)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:331)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:549)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.NoSuchMethodException: <init> [class android.view.View]
at java.lang.Class.getConstructor(Class.java:531)
at java.lang.Class.getConstructor(Class.java:495)
at com.firebase.ui.database.FirebaseRecyclerAdapter.onCreateViewHolder(FirebaseRecyclerAdapter.java:168)
at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6290)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5478)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5363)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5359)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2141)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1525)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1488)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:585)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3506)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3254)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1623)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:331)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:549)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
java.lang.RuntimeException: java.lang.NoSuchMethodException: <init> [class android.view.View]
at com.firebase.ui.database.FirebaseRecyclerAdapter.onCreateViewHolder(FirebaseRecyclerAdapter.java:171)
at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6290)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5478)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5363)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5359)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2141)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1525)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1488)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:585)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3506)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3254)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1623)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:331)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:549)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.NoSuchMethodException: <init> [class android.view.View]
at java.lang.Class.getConstructor(Class.java:531)
at java.lang.Class.getConstructor(Class.java:495)
at com.firebase.ui.database.FirebaseRecyclerAdapter.onCreateViewHolder(FirebaseRecyclerAdapter.java:168)
at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6290)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5478)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5363)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5359)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2141)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1525)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1488)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:585)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3506)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3254)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1623)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:331)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:549)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
This is my grandle dependencies:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.1.0'
compile 'com.android.support:design:25.1.0'
compile 'com.android.support:recyclerview-v7:25.1.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.android.volley:volley:1.0.0'
compile 'com.firebaseui:firebase-ui-database:1.0.0'
compile 'com.google.firebase:firebase-database:10.0.1'
compile 'com.google.firebase:firebase-storage:10.0.1'
compile 'com.google.firebase:firebase-crash:10.0.1'
compile 'com.google.firebase:firebase-auth:10.0.1'
compile 'com.google.firebase:firebase-ads:10.0.1'
compile 'com.google.firebase:firebase-invites:10.0.1'
compile 'com.google.firebase:firebase-core:10.0.1'
compile 'com.android.support:support-v4:25.1.0'
compile 'com.google.firebase:firebase-appindexing:10.0.1'
}
This is my progaurd-rules:
-keepattributes Signature
-keepattributes *Annotation*
-keepattributes EnclosingMethod
-keepattributes InnerClasses
-keep class package.ViewHolder.** {
*;
}
-keepclassmembers class package.Models.** {
*;
}
I have tried writing it all several times with no luck thus far.
Please assist me in finding a solution.