Android Studio FirestoreRecyclerAdapter Comment with Replies (nested recyclerview) - firebase

I wanted to make a Comment & Reply function for social media app
something like instagram
enter image description here
is there a way to have a nested recyclerview by using FirestoreRecyclerAdapter?
here is my plan
enter image description here
and here is the structure of my FirestoreRecyclerAdapter
homeRecycler = findViewById(R.id.homeRecycler);
linearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
homeRecycler.setLayoutManager(linearLayoutManager);
homeRecycler.setItemAnimator(null);
StorageReference profileRef = storageReference.child("ProfileImage/"+fAuth.getCurrentUser().getUid()+"/profile.jpg");
profileRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Picasso.get().load(uri).into(prof_img);
}
});
Query query = fStore.collection("Post")
.orderBy("homePostDate", Query.Direction.DESCENDING)
.limit(50);
FirestoreRecyclerOptions<HomeModel> options = new FirestoreRecyclerOptions.Builder<HomeModel>()
.setQuery(query, HomeModel.class)
.build();
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#SuppressLint("NotifyDataSetChanged")
#Override
public void onRefresh() {
adapter.notifyDataSetChanged();
swipeRefresh.setRefreshing(false);
}
});
adapter = new FirestoreRecyclerAdapter<HomeModel, ViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull ViewHolder holder, int position, #NonNull HomeModel model) {
holder.bind(model);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup group, int i) {
View view = LayoutInflater.from(group.getContext())
.inflate(R.layout.home_each, group,false);
return new ViewHolder(view);
}
};
homeRecycler.setAdapter(adapter);
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView author, title, body, authorUid, docId, timestamp, upvotecount, downvotecount;
Button addcoment;
ToggleButton upvote, downvote;
ImageView prof_img;
HomeModel model;
RecyclerView replyRecycler;
public ViewHolder(#NonNull View itemView) {...}
public void bind(HomeModel homeModel) {...}
edit:
I tried just duplicating everything within the firestorerecycleradapter viewholder but couldnt make it work and dont even know if this is the proper way..
commentRecycler = findViewById(R.id.commentRecycler);
linearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
commentRecycler.setLayoutManager(linearLayoutManager);
commentRecycler.setItemAnimator(null);
Query query = fStore.collection("Post")
.document(pdocId.getText().toString()).collection("comment")
.orderBy("commentPostDate", Query.Direction.DESCENDING)
.limit(50);
FirestoreRecyclerOptions<CommentModel> options = new FirestoreRecyclerOptions.Builder<CommentModel>()
.setQuery(query, CommentModel.class)
.build();
adapter = new FirestoreRecyclerAdapter<CommentModel, ViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull ViewHolder holder, int position, #NonNull CommentModel model) {
holder.bind(model);
linearLayoutManager2 = new LinearLayoutManager(HomeView.this, RecyclerView.VERTICAL, false);
holder.replyRecycler.setLayoutManager(linearLayoutManager2);
holder.replyRecycler.setItemAnimator(null);
Query query2 = fStore.collection("Post")
.document(pdocId.getText().toString()).collection("comment")
.document(model.docId).collection("reply")
.orderBy("commentPostDate", Query.Direction.DESCENDING)
.limit(50);
FirestoreRecyclerOptions<ReplyModel> options2 = new FirestoreRecyclerOptions.Builder<ReplyModel>()
.setQuery(query2, ReplyModel.class)
.build();
adapter2 = new FirestoreRecyclerAdapter<ReplyModel, ViewHolder2>(options2) {
#Override
protected void onBindViewHolder(#NonNull ViewHolder2 holder, int position, #NonNull ReplyModel model) {
holder.bind(model);
Toast.makeText(HomeView.this, "this is test", Toast.LENGTH_SHORT).show();
}
#NonNull
#Override
public ViewHolder2 onCreateViewHolder(#NonNull ViewGroup group, int i) {
View view = LayoutInflater.from(group.getContext())
.inflate(R.layout.comment_each, group,false);
return new ViewHolder2(view);
}
};
holder.replyRecycler.setAdapter(adapter2);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup group, int i) {
View view = LayoutInflater.from(group.getContext())
.inflate(R.layout.comment_each, group,false);
return new ViewHolder(view);
}
};
commentRecycler.setAdapter(adapter);
and then added another viewholder class
class ViewHolder extends RecyclerView.ViewHolder{
TextView author, body, authorUid, docId, timestamp, pReply, upvotecount, downvotecount;
TextInputLayout tilpReply;
ImageView prof_img;
Chip replyChip;
ToggleButton upvote, downvote;
ToggleButton replypop;
Button replyBtn;
CommentModel model;
RecyclerView replyRecycler;
public ViewHolder(#NonNull View itemView){...}
public void bind(CommentModel commentModel){...}
}
class ViewHolder2 extends RecyclerView.ViewHolder{
TextView author, body, authorUid, docId, timestamp, pReply, upvotecount, downvotecount;
TextInputLayout tilpReply;
ImageView prof_img;
Chip replyChip;
ToggleButton upvote, downvote;
ToggleButton replypop;
Button replyBtn;
CommentModel model;
RecyclerView replyRecycler;
public ViewHolder2(#NonNull View itemView){...}
public void bind(CommentModel commentModel){...}

Related

Multiple class in Firebase, and when I get it by Recycler Adapter, the "adapter" declare in different if else statement. onStart and onStop not works

I am a newbie in Android Studio and I having some problem in Firebase Recycler Adapter. I got different database in Firebase and it follow to the user ID which is eBay(Example) and Kog. I want to work like if eBay having item, it will shows and else if Kog having item, it shows too. But in the code, I only declare adapter in if...else statement. This make onStart and onStop could not listening. Here is the code. Thanks all of you...
public RecyclerView recyclerView;
public RecyclerView.LayoutManager layoutManager;
FirebaseDatabase database;
DatabaseReference requests;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_history);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
database = FirebaseDatabase.getInstance();
requests = database.getReference("Users");
recyclerView = (RecyclerView)findViewById(R.id.order_history);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
loadOrders(common.currentUser.getUid());
}
private void loadOrders(String uid) {
DatabaseReference historyRef = FirebaseDatabase.getInstance().getReference("Users/orderHistory");
historyRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.hasChild("eBay")) {
FirebaseRecyclerAdapter<ebay_Order, orderViewHolder> adapter;
FirebaseRecyclerOptions<ebay_Order> options = new FirebaseRecyclerOptions.Builder<ebay_Order>()
.setQuery(requests.child(uid).child("eBay"), ebay_Order.class).build();
adapter = new FirebaseRecyclerAdapter<ebay_Order, orderViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull orderViewHolder holder, int position, #NonNull ebay_Order model) {
holder.txtOrderName.setText(model.getEbayId());
holder.txtOrderAmount.setText(model.getEbayAmount());
holder.txtOrderServices.setText(model.getOrderChoice());
}
#NonNull
#Override
public orderViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_history, parent, false);
return new orderViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
if (snapshot.hasChild("KOG")){
FirebaseRecyclerAdapter<kog_Order, orderViewHolder> adapter;
FirebaseRecyclerOptions<kog_Order> options = new FirebaseRecyclerOptions.Builder<kog_Order>()
.setQuery(requests.child(uid).child("KOG"), kog_Order.class).build();
adapter = new FirebaseRecyclerAdapter<kog_Order, orderViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull orderViewHolder holder, int position, #NonNull kog_Order model) {
holder.txtOrderName.setText(model.getKogUsername());
holder.txtOrderAmount.setText(model.getKogAmounts());
holder.txtOrderServices.setText(model.getOrderChoice());
}
#NonNull
#Override
public orderViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_history, parent, false);
return new orderViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
#Override
public void onBackPressed(){
Intent intent = new Intent(this, InterPayMain.class);
orderHistory.this.finish();
startActivity(intent);
}
And the code for order View Holder
public class orderViewHolder extends RecyclerView.ViewHolder {
public TextView txtOrderName, txtOrderAmount, txtOrderServices;
public LinearLayout root;
public orderViewHolder(#NonNull View itemView) {
super(itemView);
root = itemView.findViewById(R.id.list_root);
txtOrderName = itemView.findViewById(R.id.order_id);
txtOrderAmount = itemView.findViewById(R.id.order_amount);
txtOrderServices = itemView.findViewById(R.id.order_choice);
}
And the error is
error: cannot find symbol adapter.startListening();
Is that got anyway to declare adapter in begining and able to work for different class.
As mentioned in the answer to this question: How to set two adapters to one RecyclerView?, a single RecyclerView can have only one adapter. You can create an adapter that has two different ViewHolders and chooses between them via overriding getItemViewType - see the question I linked for more information on implementing that solution.
An alternative is to have two separate RecyclerViews: one for each of your lists (eBay and Kog).

Search in Fragments that hold Recyclerview

I have 3 Fragments and they all are holding a recyclerView. But I don't know how I should call adapter.getFilter().filter(newText); in onQueryTextChange. Any ideas?
MainActivity:
public class MainActivity extends AppCompatActivity {
DatabaseHelper myDB;
private BottomNavigationView bottomNavigationView;
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
myDB = new DatabaseHelper(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//----Start Bottom Navigation Bar
bottomNavigationView = findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(bottomNavMethod);
getSupportFragmentManager().beginTransaction().replace(R.id.container, new PasswortFragment()).commit();
String id = getResources().getResourceEntryName(bottomNavigationView.getId());
//----End Bottom Navigation Bar
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
return true;
}
private BottomNavigationView.OnNavigationItemSelectedListener bottomNavMethod =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch(item.getItemId()){
case R.id.passwoerter:
fragment = new PasswortFragment();
break;
case R.id.bankdaten:
fragment = new BankdatenFragment();
break;
case R.id.kreditkarten:
fragment = new KreditkartenFragment();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment).commit();
return true;
}
};
#Override
public void onBackPressed() {
super.onBackPressed();
Fragment f = MainActivity.this.getSupportFragmentManager().findFragmentById(R.id.container);
if(f instanceof PasswortFragment)
recyclerView = findViewById(R.id.recyclerViewPasswoerter);
if(f instanceof KreditkartenFragment)
recyclerView = findViewById(R.id.recyclerViewKreditkarten);
if(f instanceof BankdatenFragment)
recyclerView = findViewById(R.id.recyclerViewBankdaten);
}
#Override
public boolean onCreateOptionsMenu(#NonNull Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) item.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
recyclerView.getAdapter().getFilter().filter(newText); //<--This is not working
return false;
}
});
return true;
}
Adapter:
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> implements Filterable{
String type;
List<String> dataAll, data1;
Context context;
public Adapter(Context ct, List<String> s1, String typ){
context = ct;
data1 = s1;
type = typ;
dataAll = new ArrayList<>(data1);
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.reihen, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, final int position) {
holder.mytext1.setText(data1.get(position));
holder.mainLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(type.equals("Passwoerter")){
Intent intent = new Intent(context, DetailsP.class);
intent.putExtra("data1", data1.get(position));
context.startActivity(intent);
} else if(type.equals("Kreditkarten")){
Intent intent = new Intent(context, DetailsK.class);
intent.putExtra("data1", data1.get(position));
context.startActivity(intent);
} else if(type.equals("Bankdaten")){
Intent intent = new Intent(context, DetailsB.class);
intent.putExtra("data1", data1.get(position));
context.startActivity(intent);
}
}
});
}
#Override
public int getItemCount() {
return data1.size();
}
#Override
public Filter getFilter() {
return filter;
}
private Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<String> filteredList = new ArrayList<>();
if(constraint == null || constraint.length() == 0){
filteredList.addAll(dataAll);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for(String item: dataAll){
if(item.toLowerCase().contains(filterPattern)){
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
data1.clear();
data1.addAll( (List) results.values);
notifyDataSetChanged();
}
};
;
public class MyViewHolder extends RecyclerView.ViewHolder{
TextView mytext1;
ConstraintLayout mainLayout;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
mytext1 = itemView.findViewById(R.id.title);
mainLayout = itemView.findViewById(R.id.mainLayout);
}
}
PasswortFragment (the other two fragments are pretty much the same):
public class PasswortFragment extends Fragment {
public PasswortFragment() {
// Required empty public constructor
}
RecyclerView recyclerView;
String tabelle = "Passwort";
List<String> titel;
DatabaseHelper myDB;
Adapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_passwort, container, false);
myDB = new DatabaseHelper(getActivity());
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerViewPasswoerter);
titel = Arrays.asList(myDB.getItems(tabelle));
final LinearLayoutManager layoutManager = new LinearLayoutManager((getActivity()));
layoutManager.setOrientation((LinearLayoutManager.VERTICAL));
recyclerView.setLayoutManager(layoutManager);
adapter = new Adapter(getActivity(), titel, "Passwoerter");
recyclerView.setAdapter(adapter);
setHasOptionsMenu(true);
return view;
}

I can not list the foods I have added to the cart

I can add foods,orderi adress and phone number information and see all of them under Firebase's Request/ID. However when I click on the Navigation drawer and the orders and cart buttons in the main menu, I can not list the foods I have added to the cart. There seems to be a problem in the query section. Please help me what to do
OrderStatus.java
public class OrderStatus extends AppCompatActivity {
RecyclerView recyclerView;
RecyclerView.LayoutManager layoutManager;
FirebaseDatabase database;
DatabaseReference requests;
FirebaseRecyclerAdapter<Request, OrderViewHolder> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_status);
//firebase
database = FirebaseDatabase.getInstance();
requests = database.getReference("Request");
recyclerView = findViewById(R.id.listOrders);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
loadOrders(user.getEmail().toString());
}
private void loadOrders(String email) {
Query query = FirebaseDatabase.getInstance()
.getReference("Request")
.orderByChild("email")
.startAt(email.toString()).equalTo(true,email)
.limitToLast(50);
FirebaseRecyclerOptions<Request> options = new FirebaseRecyclerOptions.Builder<Request>().setQuery(query, Request.class).build();
adapter = new FirebaseRecyclerAdapter<Request, OrderViewHolder>(options) {
#NonNull
#Override
public OrderViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_layout, parent, false);
return new OrderViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull OrderViewHolder viewHolder, int position, #NonNull Request model) {
viewHolder.txtOrderID.setText(adapter.getRef(position).getKey());
viewHolder.txtOrderStatus.setText(convertCarttoStatus(model.getStatus()));
viewHolder.txtOrderAddress.setText(model.getAddress());
viewHolder.txtOrderPhone.setText(model.getPhone());
}
};
recyclerView.setAdapter(adapter);
}
private String convertCarttoStatus(String status) {
if (status == "0")
return "PLaced";
else if (status == "1")
return "On My Way";
else
return "Shipped";
}
this worked. If you need you can use
public class OrderStatus extends AppCompatActivity {
RecyclerView recyclerView;
RecyclerView.LayoutManager layoutManager;
FirebaseDatabase database;
DatabaseReference requests;
FirebaseRecyclerAdapter<Request, OrderViewHolder> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_status);
//firebase
database = FirebaseDatabase.getInstance();
requests = database.getReference("Request");
recyclerView = findViewById(R.id.listOrders);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
phoneNumber = getIntent().getStringExtra("phoneNumber");
loadOrders(phoneNumber);
}
private void loadOrders(String email) {
Query query = FirebaseDatabase.getInstance()
.getReference("Request")
.limitToLast(50);
FirebaseRecyclerOptions<Request> options = new FirebaseRecyclerOptions.Builder<Request>().setQuery(query, Request.class).build();
adapter = new FirebaseRecyclerAdapter<Request, OrderViewHolder>(options) {
#NonNull
#Override
public OrderViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_layout, parent, false);
return new OrderViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull OrderViewHolder viewHolder, int position, #NonNull Request model) {
viewHolder.txtOrderID.setText(adapter.getRef(position).getKey());
viewHolder.txtOrderStatus.setText(convertCarttoStatus(model.getStatus()));
viewHolder.txtOrderAddress.setText(model.getAddress());
viewHolder.txtOrderPhone.setText(model.getPhone());
}
};
recyclerView.setAdapter(adapter);
}
protected void onStart() {
super.onStart();
adapter.startListening();
}
protected void onStop() {
super.onStop();
adapter.stopListening();
}
private String convertCarttoStatus(String status) {
if (status == "0")
return "PLaced";
else if (status == "1")
return "On My Way";
else
return "Shipped";
}

FirebaseRecyclerAdapter - populateViewHolder is not populating the data for first time it runs?

FirebaseRecyclerAdapter - populateViewHolder is not populating the data for the first time it runs but when I closed the app and opened it, the data is binded in RecyclerView View Holder.
I am not getting why data is not populating for first time, it is showing blank screen
Here's my MainActivity
mDatabase = FirebaseDatabase.getInstance().getReference();
// [END create_database_reference]
mRecycler = (RecyclerView) findViewById(R.id.recycler_view);
mRecycler.setHasFixedSize(true);
setSupportActionBar(toolbar);
final LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
mRecycler.setLayoutManager(layoutManager);
// Set up FirebaseRecyclerAdapter with the Query
//Query postsQuery = mDatabase.child("EN").child("Courses") ;
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("EN").child("Courses");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Toast.makeText(MainActivity.this, dataSnapshot.toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(MainActivity.this, databaseError.toString(), Toast.LENGTH_SHORT).show();
}
});
Log.d("ref", String.valueOf(ref));
// Log.d("Query", String.valueOf(postsQuery));
mAdapter = new FirebaseRecyclerAdapter<Course, CourseViewHolder>(Course.class, R.layout.item_home,
CourseViewHolder.class, ref) {
#Override
protected void populateViewHolder(final CourseViewHolder viewHolder, final Course model, final int position) {
viewHolder.bindToPost(model);
}
};
mRecycler.setAdapter(mAdapter);
And the ViewHolder
public class CourseViewHolder extends RecyclerView.ViewHolder {
public TextView titleView;
public TextView descriptionView;
public ImageView IconView;
public TextView lessonCountView;
public CourseViewHolder(View itemView) {
super(itemView);
titleView = (TextView) itemView.findViewById(R.id.title);
descriptionView = (TextView) itemView.findViewById(R.id.description);
//IconView = (ImageView) itemView.findViewById(R.id.star);
}
public void bindToPost(Course post) {
// Log.d("Post", String.valueOf(post));
titleView.setText(post.getName());
descriptionView.setText(post.getDescription());
}
}
My Model Pojo
public class Course {
public String description;
public String title;
public Course() {
// Default constructor required for calls to DataSnapshot.getValue(Post.class)
}
public Course(String title, String description) {
// this.description = author;
this.title = title;
this.description =description;
}
public String getName() {
return title;
}
public String getDescription() {
return description;
}
}
Found the Solution.
The Problem is RecyclerView had a height of wrap_content. So Please make sure your RecyclerView height is set to match_parent. This will fix this issue.
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
If you don't want to use match_parent you shouldn't call mRecycler.setHasFixedSize(true);

how to open a new fragment using RecyclerView

I am trying to make an app that which is like a place picker, meaning you write down a product like pizza or burger, and u get all the places around you that have pizza or burger.
now I'm using RecyclerView in my fragment and i also have Map fragment
when you click on an item in the RV, it will show its location on the map using the map fragment.
my problem is when I'm clicking on an item in the recyclerview i get nullpointerexception
here is my code of the first fragment
public class PlacesFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> , AdapterView.OnItemClickListener{
ClickListener listener;
static Places places;
PlacesAdapter adapter;
public FragmentManager fm;
MyMapFragment mapFragment;
Cursor cursor;
public PlacesFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View myFragView= inflater.inflate(R.layout.fragment_places, container, false);
RecyclerView rv= (RecyclerView)myFragView.findViewById(R.id.placesRecyclerView);
//this create the line beetween every list to do so i have import to the build gradle a flexible divider
rv.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).color(Color.BLACK).build());
cursor = getActivity().getContentResolver().query(CONTENT_URI, null, null, null, null);
adapter= new PlacesAdapter(cursor, getActivity());
rv.setAdapter(adapter);
adapter.notifyItemRangeChanged(cursor.getPosition(), cursor.getCount());
adapter.notifyDataSetChanged();
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
rv.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), rv, new ClickListener() {
#Override
public void onPlaceClick(String latlng) {
//when i click on a place it will go to the map fragment
// Toast.makeText(getActivity(), "on click" + position, Toast.LENGTH_LONG).show();
/* FragmentManager fm = getFragmentManager();
// get the map object from the fragment:
mapFragment = MyMapFragment.newInstance(places);
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragmantContainer, mapFragment, "map");
ft.addToBackStack(null);
ft.commit();*/
}
})
);
// getLoaderManager().initLoader(1, null,);
return myFragView;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (ClickListener)context;
} catch (ClassCastException e) {
throw new ClassCastException("context " + context.toString()
+ "must implement PlacesFragmantListener!");
}
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// CursorLoader c=getContext().getContentResolver().query(PlacesContract.Places.CONTENT_URI, null, null,null, null);
return new CursorLoader(getActivity(),CONTENT_URI, null, null,null, null );
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
public static interface PlacesFragmantListener {
public void onLocationSelected(Places places);
}
class RecyclerTouchListener implements RecyclerView.OnItemTouchListener{
private GestureDetector gestureDetector;
private ClickListener clickListener;
MyMapFragment mapFragment;
public RecyclerTouchListener(Context context, RecyclerView recyclerView, ClickListener clickListener){
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
#Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
#Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
}
});
this.clickListener = clickListener;
}
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(),e.getY());
return false;
}
#Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
Log.d("PlaceAdapter", "onTouchEvent"+e);
}
#Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
}
here is my map fragment
public class MyMapFragment extends Fragment {
public MyMapFragment(){
}
public static MyMapFragment newInstance(Places places) {}
if (places == null) {
places = new Places(0,"no Location selected","","", "");
}
// the arguments to pass
Bundle args = new Bundle();
args.putString("location", places.getLocation());
args.putDouble("lat", location.getLat());
args.putDouble("lon", location.getLon());
MyMapFragment mapFragmant = new MyMapFragment();
mapFragmant.setArguments(args);
return mapFragmant;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.mapfragment, container, false);
Bundle b=getArguments();
String latlng= b.getString("location");
Log.d("fragment...", latlng);
String[] latlongarr= latlng.split(",");
double lat= Double.parseDouble(latlongarr[0]);
double lon= Double.parseDouble(latlongarr[1]);
FragmentManager fm = getFragmentManager();
MapFragment mapFragment = (MapFragment) fm.findFragmentById(R.id.map);
// get the map object from the fragment:
GoogleMap map = mapFragment.getMap();
if(map!= null) {
// setup the map type:
map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
// setup map position and zoom
LatLng position = new LatLng(b.getDouble("lat"), b.getDouble("lon"));
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(position, 15);
map.moveCamera(update);
}
return view;
}
}
here is my adapter
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.PlaceHolder> {
private Cursor cursor;
private Context context;
private static TextView placeName, address, distance, url;
public static ImageView imgplace;
public static PlaceHolder.ClickListener clickListener;
private static Places place;
private DataSetObserver mDataSetObserver;
MyMapFragment mapFragment;
private boolean mDataValid;
ClickListener listener;
public PlacesAdapter(Cursor cursor, Context context) {
this.context = context;
this.cursor = cursor;
mDataSetObserver = new NotifyingDataSetObserver();
if (cursor != null) {
cursor.registerDataSetObserver(mDataSetObserver);
}
}
#Override
public PlaceHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// cursor.setNotificationUri(context.getContentResolver(), CONTENT_URI);
LayoutInflater inflater = LayoutInflater.from(context);
View myView = inflater.inflate(R.layout.single_place, parent, false);
PlaceHolder placeHolder = new PlaceHolder(myView, new PlaceHolder.PlacesFragmantListener() {
#Override
public void onLocationSelected(Places places) {
}
});
return placeHolder;
}
#Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(true);
}
#Override
public void onBindViewHolder(PlacesAdapter.PlaceHolder holder, final int position) {
if (cursor.moveToPosition(position)) {
int column_number = cursor.getColumnIndex(PLACES_NAME);
String name = cursor.getString(column_number);
placeName.setText(name);
int column_number2 = cursor.getColumnIndex(PLACES_ADDRESS);
String adr = cursor.getString(column_number2);
address.setText(adr);
int column_number3 = cursor.getColumnIndex(PLACES_DISTANEC);
String dis = cursor.getString(column_number3);
distance.setText(dis);
int column_number4 = cursor.getColumnIndex(PLACE_PHOTO);
String photo = cursor.getString(column_number4);
if(!photo.equals(""))
{
GoogleAccess.myImageDownloader loader= new GoogleAccess.myImageDownloader(imgplace);
loader.execute(photo);
}
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "Item click at " + position, Toast.LENGTH_LONG).show();
if(cursor.moveToPosition(position))
{
String latlong= cursor.getString(cursor.getColumnIndex(PlacesDbconstanst.CurrentPlaces.PLACES_DISTANEC));
listener.onPlaceClick(latlong);
}
}
});
}
public void setClickListener(PlaceHolder.ClickListener clickListener){
this.clickListener = clickListener;
}
#Override
public int getItemCount() {
return cursor.getCount();
}
public static class PlaceHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
PlacesFragmantListener listener;
public PlaceHolder(View itemView, PlacesFragmantListener placesFragmantListener) {
super(itemView);
listener = placesFragmantListener;
placeName = (TextView) itemView.findViewById(R.id.placeNametextView);
address = (TextView) itemView.findViewById(R.id.addressTextView);
distance = (TextView) itemView.findViewById(R.id.distanceTextView);
imgplace = (ImageView) itemView.findViewById(R.id.placesImageViewId);
imgplace.setOnClickListener(this);
itemView.setOnClickListener(this);
}
RecyclerView rv;
#Override
public void onClick(View v) {
if(clickListener!=null){
clickListener.itemClicked(v, getPosition());
}
}
public static interface PlacesFragmantListener {
void onLocationSelected(Places places);
}
public interface ClickListener{
public void itemClicked (View view, int position);
}
}
private class NotifyingDataSetObserver extends DataSetObserver {
#Override
public void onChanged() {
super.onChanged();
mDataValid = true;
notifyDataSetChanged();
}
#Override
public void onInvalidated() {
super.onInvalidated();
mDataValid = false;
notifyDataSetChanged();
}
}
}
can you tell me what i did wrong
here is the log comment
03-30 04:55:28.042 2318-2318/com.myapps.pinkas.placesofintrest W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0xa4c8cb20)
03-30 04:55:28.042 2318-2318/com.myapps.pinkas.placesofintrest E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.myapps.pinkas.placesofintrest, PID: 2318
java.lang.NullPointerException
at com.myapps.pinkas.placesofintrest.PlacesAdapter$2.onClick(PlacesAdapter.java:112)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
distance = (TextView) itemView.findViewById(R.id.distanceTextView);
is this line come in 112 in your class file, it's seems like, you have not defined view id or view in XML, please check line number 112 in PlacesAdapter.class
Problem 1: Setting onclick listener twice. In onbindviewholder you have put holder.itemView.setOnclicklistener and then again in static class viewholder, you have put itemview.setOnclickListener. When you assign setOnclicklistener inside the static viewholder class, it means it will behave in a particular way uninfluenced by values present in any other views (like textview, imageview) or any such factors which depend on some 'value' property of the views. For most purposes you should have setOnClicklistener onto the itemview/textview/etc inside the static viewholder class which in your case is called placeholder.
Problem 2: Here is the reason why I believe you are getting NullPointerException. onbindviewholder has access to only the views declared in static viewholder class. If you want itemview to be accessible to onbindviewholder then make the following changes:
public static class PlaceHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
PlacesFragmantListener listener;
View iv;
public PlaceHolder(View itemView, PlacesFragmantListener placesFragmantListener) {
super(itemView);
iv = (View)itemView;
//then rest of the code
Now in your onbindviewholder write the following instead of holder.itemview.setonclicklistener
holder.iv.setonclicklistener...
Problem 3: in your static viewholder, you have put:
imgplace.setOnClickListener(this);
itemView.setOnClickListener(this);
itemview is the layout in which imgplace exists. And you have setonclicklistener on both of them. This is like putting a button on a button. It makes no sense. I think this will lead you into lot of mess. For some reason you want both to perform the same function on being clicked (you have put 'this' inside setOnClickListener). This is completely illogical. So set the clicklistener to either imgplace or itemview but not both

Resources