NullPointerException when using FirebaseUI and RecyclerView - firebase

I followed this guide How to display data from Firestore in a RecyclerView with Android?, but am facing a NullPointerException in the setter in the ViewHolder. I'm also actually very unsure of what to do in the setter in the ViewHolder...
![database]https://imgur.com/a/wquZ08f
Model:
public class FoodModel {
private String foodName;
private String foodType;
private String foodQty;
private String foodExpDate;
public FoodModel() {}
public FoodModel(String name, String type, String qty, String expDate) {
this.foodName = name;
this.foodType = type;
this.foodQty = qty;
this.foodExpDate = expDate;
}
public String getFoodName() {return foodName;}
public void setFoodName(String name) {foodName = name;}
public String getFoodType() {return foodType;}
public void setFoodType(String type) {foodType = type;}
public String getFoodQty() {return foodQty;}
public void setFoodQty(String qty) {foodQty = qty;}
public String getFoodExpDate() {return foodExpDate;}
public void setFoodExpDate(String expDate) {foodExpDate = expDate;}
}
Activity code:
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
Query foodQuery = db.collection("Food")
.orderBy("food_name", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<FoodModel> options = new FirestoreRecyclerOptions.Builder<FoodModel>()
.setQuery(foodQuery, FoodModel.class)
.build();
adapter = new FirestoreRecyclerAdapter<FoodModel, FoodViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull FoodViewHolder holder, int position, #NonNull FoodModel model) {
holder.setFoodName(model.getFoodName());
}
#NonNull
#Override
public FoodViewHolder onCreateViewHolder(#NonNull ViewGroup group, int viewType) {
View view = LayoutInflater.from(group.getContext()).inflate(R.layout.recycler_view_row, group, false);
return new FoodViewHolder(view);
}
};
recyclerView.setAdapter(adapter);
}
private class FoodViewHolder extends RecyclerView.ViewHolder {
private View view;
FoodViewHolder(View itemView) {
super(itemView);
view = itemView;
}
void setFoodName(String foodName) {
TextView textView = view.findViewById(R.id.editName);
textView.setText(foodName);
}
}
xml of recycler_view_row:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/foodListRow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
errors:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.qremind, PID: 17735
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.example.qremind.FoodList$FoodViewHolder.setFoodName(FoodList.java:91)
at com.example.qremind.FoodList$1.onBindViewHolder(FoodList.java:70)
at com.example.qremind.FoodList$1.onBindViewHolder(FoodList.java:67)
at com.firebase.ui.firestore.FirestoreRecyclerAdapter.onBindViewHolder(FirestoreRecyclerAdapter.java:158)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7065)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7107)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6012)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6279)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1897)
at androidx.recyclerview.widget.RecyclerView$1.run(RecyclerView.java:414)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:878)
at android.view.Choreographer.doCallbacks(Choreographer.java:690)
at android.view.Choreographer.doFrame(Choreographer.java:622)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:864)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:185)
at android.app.ActivityThread.main(ActivityThread.java:6473)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:916)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:806)

You have defined the Textview inside the function. Define it as
private class FoodViewHolder extends RecyclerView.ViewHolder {
private View view;
TextView textView;
FoodViewHolder(View itemView) {
super(itemView);
view = itemView;
textView = view.findViewById(R.id.editName);
}
void setFoodName(String foodName) {
textView.setText(foodName);
}
}

Change this:
TextView textView = view.findViewById(R.id.editName);
into this:
TextView textView = view.findViewById(R.id.foodListRow);

In FoodViewHolder class:
This method:
void setFoodName(String foodName) {
//here is your problem
TextView textView = view.findViewById(R.id.editName);
textView.setText(foodName);
}
Must be like this, you are pointing to the wrong ID:
void setFoodName(String foodName) {
TextView textView = view.findViewById(R.id.foodListRow);
textView.setText(foodName);
}

Related

How to get data from RecyclerView item position

Good evening. I'm stuck on this problem. I'm populating a RecyclerView with data from Firebase Realtime Database. This part is ok, it's work well. My doubt is how I get the firebase id from the user on the click event. As the id not shows in the layout, I have no ideia how I can work with this data. Here the class:
Adapter
public class TecnicosAdapter extends RecyclerView.Adapter<TecnicosViewHolders>{
private List<TecnicosObject> tecnicosList;
private Context context;
public TecnicosAdapter (List<TecnicosObject> tecnicosList, Context context){
this.tecnicosList = tecnicosList;
this.context = context;
}
#NonNull
#Override
public TecnicosViewHolders onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_tecnicos, null, false);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutView.setLayoutParams(lp);
TecnicosViewHolders rcv = new TecnicosViewHolders((layoutView));
return rcv;
}
#Override
public void onBindViewHolder(#NonNull TecnicosViewHolders holder, int position) {
// holder.mTecnicoId.setText(tecnicosList.get(position).getUsuarioId());
holder.mTecnicoNome.setText(tecnicosList.get(position).getNome());
holder.mTecnicoProfissao.setText(tecnicosList.get(position).getProfissao());
if (!tecnicosList.get(position).getImagemPerfilUrl().equals("default")){
Glide.with(context).load(tecnicosList.get(position).getImagemPerfilUrl()).into(holder.mTecnicoImagem);
}
}
public TecnicosObject getItem(int position){
return tecnicosList.get(position);
}
#Override
public int getItemCount() {
return this.tecnicosList.size();
}
}
Model
public class TecnicosObject {
private String usuarioId;
private String nome;
private String profissao;
private String imagemPerfilUrl;
public TecnicosObject(String usuarioId, String nome, String profissao, String imagemPerfilUrl) {
this.usuarioId = usuarioId;
this.nome = nome;
this.profissao = profissao;
this.imagemPerfilUrl = imagemPerfilUrl;
}
public String getUsuarioId() {
return usuarioId;
}
public void setUsuarioId(String usuarioId) {
this.usuarioId = usuarioId;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getProfissao() {
return profissao;
}
public void setProfissao(String profissao) {
this.profissao = profissao;
}
public String getImagemPerfilUrl() {
return imagemPerfilUrl;
}
public void setImagemPerfilUrl(String imagemPerfilUrl) {
this.imagemPerfilUrl = imagemPerfilUrl;
}
}
ViewHolder
public class TecnicosViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView mTecnicoNome, mTecnicoProfissao;
public ImageView mTecnicoImagem;
private Context context;
String clienteId;
private Bundle extras;
public TecnicosViewHolders(View itemView) {
super(itemView);
this.context = context;
mTecnicoNome = (TextView) itemView.findViewById(R.id.TecnicoNome);
mTecnicoProfissao = (TextView) itemView.findViewById(R.id.TecnicoProfissao);
mTecnicoImagem = (ImageView) itemView.findViewById(R.id.TecnicoImagem);
}
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
if (pos!=RecyclerView.NO_POSITION){
}
}
}
Main Activity
public class TelaTecnicos extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mTecnicosAdapter;
private RecyclerView.LayoutManager mTecnicosLayoutManager;
private String usuarioAtualID;
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tela_tecnicos);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
usuarioAtualID = FirebaseAuth.getInstance().getCurrentUser().getUid();
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(true);
mTecnicosLayoutManager = new LinearLayoutManager(TelaTecnicos.this);
mRecyclerView.setLayoutManager(mTecnicosLayoutManager);
mTecnicosAdapter = new TecnicosAdapter(getDataSetTecnicos(), TelaTecnicos.this);
mRecyclerView.setAdapter(mTecnicosAdapter);
getUsuarioTecnicoId();
}
private void getUsuarioTecnicoId() {
DatabaseReference tecnicoDb = FirebaseDatabase.getInstance().getReference().child("Usuarios").child("Clientes").child(usuarioAtualID).child("conexoes").child("tecnicos");
tecnicoDb.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
for (DataSnapshot tecnico: dataSnapshot.getChildren()){
FetchtecnicoInformation(tecnico.getKey());
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void FetchtecnicoInformation(final String key) {
DatabaseReference usuarioDb = FirebaseDatabase.getInstance().getReference().child("Usuarios").child("Tecnicos").child(key);
usuarioDb.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
String usuarioId = dataSnapshot.getKey();
String nome = "";
String profissao = "";
String imagemPerfilUrl = "";
if (dataSnapshot.child("nome").getValue()!=null){
nome = dataSnapshot.child("nome").getValue().toString();
}
if (dataSnapshot.child("profissao").getValue()!=null){
profissao = dataSnapshot.child("profissao").getValue().toString();
}
if (dataSnapshot.child("imagemPerfilUrl").getValue()!=null){
imagemPerfilUrl = dataSnapshot.child("imagemPerfilUrl").getValue().toString();
}
TecnicosObject obj = new TecnicosObject(usuarioId, nome, profissao, imagemPerfilUrl);
resultmTecnicos.add(obj);
mTecnicosAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private ArrayList<TecnicosObject> resultmTecnicos = new ArrayList<TecnicosObject>();
private List<TecnicosObject> getDataSetTecnicos() {
return resultmTecnicos;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home){
this.finish();
}
return super.onOptionsItemSelected(item);
}
}
Someone have a tip? Thanks.
Put this in your ViewHolder onclick() method technicoId = technicolist.get(pos.getId())
The implementation should look like this ->>
`
String technicoId = "";
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
if (pos!=RecyclerView.NO_POSITION){
technicoId = technicolist.get(pos).getId();
}
}
`
Edit:
if your view holder is in a separate file it is better you implement viewholder class in the adapter class(that's what I do) so you can easily reference technicolist in viewholder. it will look like this
`
public class TecnicosAdapter extends RecyclerView.Adapter<TecnicosViewHolders>{
private List<TecnicosObject> tecnicosList;
....other methods
class TecnicosViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener{
//you can use tecnicolist here
#Override
public void onClick(View v){
....
}
}
}
`

ViewPager returning empty array

When I start my app I want my customSwipeAdapter.java to wait until my savedImages ArrayList has received and been populated with the data from firebase. But instead my class is being ran and my whole page is empty because getCount() method is returning savedImages.size() as 0 because my arraylist hasn't been populated in time. Any help on maybe running my class when my array list is populated. Not sure what to do here :)
customSwipeAdapter.java
public class customSwipeAdapter extends PagerAdapter {
private Firebase mRef;
private Context ctx;
private LayoutInflater layoutInflator;
public customSwipeAdapter(Context ctx) {
this.ctx = ctx;
}
private int[] frontImages = {R.drawable.amen_parham, R.drawable.janel_parham, R.drawable.kevin_parham};
// Populate ArrayList with firebase data
List<String> savedImages = new ArrayList<String>();
Boolean goingToCallOnce = false;
Boolean finishedLoadingData = false;
#Override
public int getCount() {
return savedImages.size();
}
#Override
public boolean isViewFromObject(View view, Object o) {
return (view == o);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
getSavedImages_FromDB();
layoutInflator = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View item_view = layoutInflator.inflate(R.layout.swipe_layout, container, false);
final EasyFlipView mYourFlipView = (EasyFlipView) item_view.findViewById(R.id.flipView);
ImageView imageView_Front = (ImageView) item_view.findViewById(R.id.imageView_Front);
imageView_Front.setImageResource(frontImages[position]);
container.addView(item_view);
System.out.println(savedImages);
return item_view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((RelativeLayout)object);
}
public void getSavedImages_FromDB() {
mRef = new Firebase("");
if (goingToCallOnce == false) {
goingToCallOnce = true;
mRef.child("Q6i3fI6lNdYYS0z5Jty4WUYE9g13").child("SavedImages").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String savedImage = (String) dataSnapshot.child("Image").getValue();
savedImages.add(0, savedImage);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
mRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
finishedLoadingData = true;
System.out.println("finishedLoadingData");
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
}
savedCardsViewController.java
public class savedCardsViewController extends AppCompatActivity {
private Swipe swipe;
ViewPager viewPager;
customSwipeAdapter adapter;
private Firebase mRef;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_saved_cards_view_controller);
viewPager = (ViewPager) findViewById(R.id.view_pager);
adapter = new customSwipeAdapter(this);
viewPager.setAdapter(adapter);
viewPager.setPageTransformer(false, new DefaultTransformer());
}
}
'Context' to 'ValueEventListener'
2'nd 'Context' to 'ValueEventListener'
I suggest you load the data from Firebase on your Activity first and then pass it as a parameter to the adapter's constructor. This way your CustomSwipeAdapter would look similar to this:
public class customSwipeAdapter extends PagerAdapter {
private Firebase mRef;
private Context ctx;
private LayoutInflater layoutInflator;
List<String> savedImages = new ArrayList<String>();
public customSwipeAdapter(Context ctx, List<String> savedImages){
this.ctx = ctx;
this.savedImages = savedImages
}
...
}
Another note on Loading data from firebase on the Activity: use A SingleValueListener with an iterator instead of onChildAdded:
mRef.child("Q6i3fI6lNdYYS0z5Jty4WUYE9g13").child("SavedImages").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterator<DataSnapshot> data = dataSnapshot.getChildren().iterator();
while(data.hasNext())
{
String savedImage = (String) data.next().child("Image").getValue();
savedImages.add(0, savedImage);
}
//Data has finished loading. Load your adapter
adapter = new customSwipeAdapter(this, savedImages);
viewPager.setAdapter(adapter);
viewPager.setPageTransformer(false, new DefaultTransformer());
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});

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);

cannot resolve constructor 'FirebaseListAdapter'

It says unable to resolve constructor firebaseListAdapter.
This is my MainActivity.
Error on line:
listAdapter = new FirebaseListAdapter(this, chat.class, android.R.layout.two_line_list_item, mRef)
public class MainActivity extends AppCompatActivity {
private DatabaseReference mRef;
private FirebaseListAdapter < chat > listAdapter;
ListView lv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Firebase.setAndroidContext(this);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
lv = (ListView) findViewById(R.id.lv);
mRef = FirebaseDatabase.getInstance().getReference();
listAdapter = new FirebaseListAdapter < chat > (this, chat.class, android.R.layout.two_line_list_item, mRef) {
#Override
protected void populateView(View view, chat chatMessage, int position) {
((TextView) view.findViewById(android.R.id.text1)).setText(chatMessage.getName());
((TextView) view.findViewById(android.R.id.text2)).setText(chatMessage.getMsg());
}
};
lv.setAdapter(listAdapter);
}
}
This is my Chat.class
public class chat {
String name, msg;
public chat() {}
public chat(String name, String msg) {
this.name = name;
this.msg = msg;
}
public String getName() {
return name;
}
public String getMsg() {
return msg;
}
}
I got the answer. It was just a small glitch.
I had imported;
com.firebase.ui.FirebaseListAdapter
The correct import package should be;
com.firebase.ui.database.FirebaseListAdapter
That's it and the problem is solved.
add:
compile 'com.firebase:firebase-client-android:2.3.1'
compile 'com.firebase:firebase-ui:0.1.0'
and then
import com.firebase.ui.FirebaseListAdapter;

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