Recycler View Item onClick - java

I have Googled a number of possibilities on how to get the item which is clicked in a recycler view but none of them seem to work. The code below should work but I dont understand why its not. In android studio, the getPosition() method is crossed out. I am running out of ideas, Is there a way i can at least toast the name of the recycler view is clicked?
ViewHolder
public class ShoppingListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public CardView cv;
public TextView name;
public TextView description;
Context context;
public ShoppingListViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.cardView);
name = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("RecyclerView", "onClick:" + getPosition());
}
});
}
public void bindView(int position) {
}
#Override
public void onClick(View v) {
Log.d("TAG", "onClick " + getPosition() + " " + name);
}
Adapter
public class MainShoppingListViewActivity extends AppCompatActivity {
List<Data> list = new ArrayList<>();
RecyclerView recyclerView;
ShoppingListViewAdapter adapter;
Context context;
EditText listName;
Firebase ref;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_shoppinglist_view);
Firebase.setAndroidContext(this);
ref = new Firebase("https://shoppinglistshare.firebaseio.com/");
// Getting the recycler view, using the Recycler View
recyclerView = (RecyclerView) findViewById(R.id.shopping_list_recycler_view);
// The setLayoutManager which contains the main container where the Recycler View is contained
recyclerView.setLayoutManager(new LinearLayoutManager(MainShoppingListViewActivity.this));
// Floating action bar initiated, background color is set and then onClickListener to act when the
// button is pressed to which the createDialogBox(); method is called
FloatingActionButton addFloat = (FloatingActionButton) findViewById(R.id.fab);
addFloat.setBackgroundTintList(ColorStateList.valueOf(Color
.parseColor("#3F51B5")));
addFloat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Click action
createDialogBox();
}
});
}
/*
* This method is used to add a new item to the Recycler View
*/
public void addNewShoppingListItem(String val) {
ref = new Firebase("https://shoppinglistshare.firebaseio.com/");
adapter = new ShoppingListViewAdapter(list, MainShoppingListViewActivity.this);
recyclerView.setAdapter(adapter);
adapter.addItem(new Data(val, "Created by: Me"));
ref.child("List Name: ").setValue(val);
}
/*
* This method is used to add a new item to the Recycler View
*/
public void removeShoppingListItem(String val) {
adapter = new ShoppingListViewAdapter(list, MainShoppingListViewActivity.this);
recyclerView.setAdapter(adapter);
adapter.addItem(new Data(val, "Created by: Me"));
}
/*
* This method is called inside the float action bar to create a dialog box when the floating action button is pressed.
*/
public void createDialogBox() {
// Alert Dialog Builder
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// Using Layout Inflater class and assigned to a variable and using getLayout
LayoutInflater inflater = this.getLayoutInflater();
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout.
// Using the view class to inflate the layout.
View rootView = inflater.inflate(R.layout.custom_alert_dialog, null);
listName = (EditText) rootView.findViewById(R.id.ShoppinglistName);
// Using the AlertDialog Builder created above as "builder" to set the view.
builder.setView(rootView)
.setPositiveButton("Create", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
String val = listName.getText().toString();
if (!val.isEmpty()) {
addNewShoppingListItem(val);
} else {
Toast.makeText(MainShoppingListViewActivity.this, "Please enter a value", Toast.LENGTH_SHORT).show();
}
}
})
// Show the dialog
.show();
}
}
Logs
FATAL EXCEPTION: main
Process: familyshopshare.com.familyshopshare, PID: 17889
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
at android.widget.Toast.<init>(Toast.java:102)
at android.widget.Toast.makeText(Toast.java:259)
at familyshopshare.com.familyshopshare.ShoppingListViewHolder$1.onClick(ShoppingListViewHolder.java:33)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Made small changes, here is the solution i got. I am going to alter the onClick onto another method instead of where it is. If there are any suggestions on how i can make the code better please let me know, any advise is much appreciated :)
public class ShoppingListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public CardView cv;
public TextView name;
public TextView description;
Context context;
public ShoppingListViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.cardView);
name = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Data test = new Data(name.getText().toString(), description.getText().toString());
Toast.makeText(v.getContext(), "onClick " + test.getName(), Toast.LENGTH_SHORT).show();
Log.d("RecyclerView", "onClick is this:" + getAdapterPosition());
}
});
}
#Override
public void onClick(View v) {
Toast.makeText(context, "onClick " + getAdapterPosition() + " " + name, Toast.LENGTH_SHORT).show();
}
}

There are a few ways you can do it. Personally, I like to set the listener in the onBindViewHolder inside of the adapter class(wherever you have your viewholder):
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.YourTargetObject.setOnClickListener(new View.onClickListener(){
public void onClick(View view){
//do something
}
});
}

Related

How to getItemCount() when using FirestoreRecyclerAdapter because it always return 0?

I'm currently building a booking application for laundry's machine. I need to get the item count and if the count is zero it will show the dialog box which told user that there is no data in the system.
The Activity code:
public class DobbySelection2 extends AppCompatActivity {
String local;
private Dialog dialog;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private DobbyAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dobby_selection2);
dialog = new Dialog(this);
dialog.setContentView(R.layout.custom_dialog2);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
dialog.getWindow().setBackgroundDrawable(getDrawable(R.drawable.custom_dialogbackground));
}
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
dialog.setCancelable(false); //Optional
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation; //Setting the animations to dialog
Button Yes = dialog.findViewById(R.id.btn_yes);
Yes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(DobbySelection2.this, MainActivity.class );
dialog.dismiss();
startActivity(intent);
}
});
setUpRecyclerView();
}
private void setUpRecyclerView(){
Intent i = getIntent();
local = i.getStringExtra("PLACE");
if (local == null){
local = "Selangor";
}
CollectionReference dobbyRef = db.collection("locality")
.document(local)
.collection("Dobby");
Query query = dobbyRef.orderBy("name", Query.Direction.DESCENDING);
FirestoreRecyclerOptions<Dobby> options = new FirestoreRecyclerOptions.Builder<Dobby>()
.setQuery(query, Dobby.class)
.build();
adapter = new DobbyAdapter(options);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
//recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setLayoutManager(new CustomLinearLayoutManager(this));
recyclerView.setAdapter(adapter);
if(adapter.getItemCount() == 0){
dialog.show();
}
adapter.setOnItemClickListener(new DobbyAdapter.OnItemClickListener() {
#Override
public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
Dobby dobby = documentSnapshot.toObject(Dobby.class);
String id = documentSnapshot.getId();
Toast.makeText(DobbySelection2.this, "ID : " + id, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(DobbySelection2.this, Booking2.class);
intent.putExtra("PLACE", local);
intent.putExtra("ID", id);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
}
Adapter code:
public class DobbyAdapter extends FirestoreRecyclerAdapter<Dobby, DobbyAdapter.DobbyHolder>{
private OnItemClickListener listener;
/**
* Create a new RecyclerView adapter that listens to a Firestore Query. See {#link
* FirestoreRecyclerOptions} for configuration options.
*
* #param options
*/
public DobbyAdapter(#NonNull FirestoreRecyclerOptions<Dobby> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull DobbyHolder holder, int position, #NonNull Dobby model) {
holder.textViewName.setText(model.getName());
holder.textViewAddress.setText(model.getAddress());
holder.textViewDistance.setText(model.getDistance());
}
#NonNull
#Override
public DobbyHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.itemdobby, parent, false);
return new DobbyHolder(v);
}
class DobbyHolder extends RecyclerView.ViewHolder{
TextView textViewName;
TextView textViewAddress;
TextView textViewDistance;
public DobbyHolder(#NonNull View itemView) {
super(itemView);
textViewName = itemView.findViewById(R.id.nameDobby);
textViewAddress = itemView.findViewById(R.id.addressDobby);
textViewDistance = itemView.findViewById(R.id.distanceDobby);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION && listener != null){
listener.onItemClick(getSnapshots().getSnapshot(position), position);
}
}
});
}
}
public interface OnItemClickListener {
void onItemClick(DocumentSnapshot documentSnapshot, int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
}
But the dialog box always pop up indicating that the count is zero even though there is data inside of the recycler view. How can I fix this?
My guess is that the dialog you're talking about comes from here:
if(adapter.getItemCount() == 0){
dialog.show();
}
If so, it makes sense that it shows up as this code runs before any data has been loaded.
Data is loaded from Firestore (and most modern cloud APIs) asynchronously, and this changes the order in which code executes. It's easiest to see this if you set breakpoint on the if line above, on adapter.startListening(); and on the first line inside your onBindViewHolder.
If you now run the code in the debugger, you'll see that it:
First hits the if(adapter.getItemCount() == 0){ line
Then adapter.startListening()`
Then gets to onBindViewHolder
So now it hopefully makes sense why your code always show the dialog: no data has been loaded yet at that point.
The solution for this is always the same: you need to make sure that the code that needs the data runs after the data has been loaded. Since you're using the FirestoreRecyclerAdapter from FirebaseUI, you can do this inside its onDataChanged method that signals that a complete snapshot was loaded (regardless of whether there was any data in that snapshot) and is shown in the documentation on data and error events.
So if you move your if check into a onDataChanged method in your DobbyAdapter, it will get called whenever the adapter has loaded a complete snapshot, and it will show the dialog when there are no items.

passing data from itemView of Adapter between two Fragments

Below code of adapter of RecyclerView
public interface SelectMarket {
void selectMarket(DataMarket dataMarket);
}
public class viewHolder extends RecyclerView.ViewHolder{
TextView marketTitleName;
public viewHolder(#NonNull View itemView) {
super(itemView);
marketTitleName = itemView.findViewById(R.id.market_title_custom);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectMarket.selectMarket(marketName.get(getAdapterPosition()));
Toast.makeText(ctx, "id "+getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
}
}
In the code I shows you the ViewHolder
where I set onClickListener
I want to click on that and then go to other Fragment called SelectRoomFragment
and in Method of SelectMarket() I wrote inside the codes which will help me to go the the Next Fragment like this :
#Override
public void selectMarket(DataMarket dataMarket) {
SelectRoomFragment selectRoomFragment= new SelectRoomFragment();
Bundle args = new Bundle();
args.putString("market",dataMarket.getTitle());
selectRoomFragment.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.fragment_container,
selectRoomFragment).commit();
}
The Output Is
Which is not looking Good like I want.
move the code below to onBindViewHolder
marketTitleName = itemView.findViewById(R.id.market_title_custom);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectMarket.selectMarket(marketName.get(getAdapterPosition()));
Toast.makeText(ctx, "id "+getAdapterPosition(),Toast.LENGTH_SHORT).show();
}
});

Get error when I want to display detail in new activity after click on RecyclerView. Using Firebase

I would like the ViewProduct activity to show the detail of the item clicked on the recyclerView. My aim later is to change the textView to a editText to edit the products, but for now I would like it to show.
My problem is filling the textView with the data from the particular product from Firebase.
You will see there is a toast message that is commented out which works and show the position, so I know I am on the right track somehow. Now the app just crashes if I click on the item, giving error:
Unable to start activity ComponentInfo
Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
All I need now is to populate the textfields with the data from Firebase.
Here is my itemView in my RecyclerAdapter:
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
//Toast.makeText(context,"Position"+ position, Toast.LENGTH_SHORT).show();
if (position != RecyclerView.NO_POSITION && listener != null) {
//listener.onItemClick(getSnapshots().getSnapshot(position), position);
listener.onItemClick(getSnapshots().getSnapshot(position),(position));
Intent intent = new Intent(itemView.getContext(), ViewProduct.class);
intent.putExtra("product_ID:", position);
itemView.getContext().startActivity(intent);
}
}
});
And here is my ViewProduct Activity where I want to see the details:
public class ViewProduct extends AppCompatActivity {
private String edit_product_ID;
private TextView mProduct, mPrice;
private TextView mSave, mDelete;
private DatabaseReference product_ref;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_product);
product_ref = FirebaseDatabase.getInstance().getReference().child("ultra_liquors");
edit_product_ID = getIntent().getExtras().get("product_ID").toString();
//Toast.makeText(this, "The Product ID:" + edit_product_ID, Toast.LENGTH_SHORT).show();
mProduct = (TextView) findViewById(R.id.product);
mPrice = (TextView) findViewById(R.id.price);
mSave = (TextView) findViewById(R.id.save);
mDelete = (TextView) findViewById(R.id.delete);
RetrieveProductInfo();
}
private void RetrieveProductInfo() {
product_ref.child(edit_product_ID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if ((dataSnapshot.exists()) && (dataSnapshot.hasChild(edit_product_ID))) {
String product_name = dataSnapshot.child("product").getValue().toString();
String product_price = dataSnapshot.child("price").getValue().toString();
mProduct.setText(product_name);
mPrice.setText(product_price);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The string in intent.putExtra("product_ID:", position); has a trailing colon-symbol behind it. which causes getExtras().get(...) to return null. null.toString() throws the error
Add this line with Intent
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
I think that was the issue try it and let me know!

SetText from a Class to the main XML file

I'm trying to use the .setText within a java class to try to change the value of a TextView on the activity_main XML file, so far i'm getting the NullpointerExeption error and I've read that its due an error when declaring my variable. How can i achieve this? Do i need to declare it first at the mainActivity.java?
On my activity_main.xml i have a button -> it opens a custom listView -> if you press the 2 item on the list view -> it opens a custom alert dialog -> the custom alert dialog it contains 2 buttons -> if you press the second button -> it has to set the text of a TextView that is on activity_main.xml
Any help is appreciated!
MainActivity.java
final TextView KMLabel = (TextView)findViewById(R.id.KMlabel);
activity.main.xml
<TextView
android:id="#+id/KMlabel"
android:layout_alignBottom="#+id/TVKm"
android:layout_toRightOf="#+id/TVKm"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#e6c009"
android:text="KM/H"
android:textStyle="italic"/>
custom.java
public class custom extends BaseAdapter{
Context context;
String Item[];
String SubItem[];
int flags[];
LayoutInflater inflter;
public custom(Context applicationContext, String[] Item, String[] SubItem , int[] flags) {
this.context = context;
this.Item = Item;
this.SubItem = SubItem;
this.flags = flags;
inflter = (LayoutInflater.from(applicationContext));
}
#Override
public int getCount() {
return Item.length;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = inflter.inflate(R.layout.activity_items, null);
//TextView Prueba = (TextView)view.findViewById(R.id.KMlabel);
TextView item = (TextView) view.findViewById(R.id.item);
TextView subitem = (TextView) view.findViewById(R.id.subitem);
ImageView image = (ImageView) view.findViewById(R.id.image);
item.setText(Item[i]);
subitem.setText(SubItem[i]);
image.setImageResource(flags[i]);
return view;
}
viewdialog.java
public class ViewDialog {
public void showDialog(Activity activity, String msg){
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(false);
dialog.setContentView(R.layout.custom_dialog);
//I'm declaring it like this
final TextView KMLabel = (TextView)activity.findViewById(R.id.KMlabel);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//and calling it this way:
KMLabel.setText("MLL/H");
}
});
dialog.show();
}
}
LOGCAT:
FATAL EXCEPTION: main
Process: com.example.dell.getspeed, PID: 3925
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.example.dell.getspeed.ViewDialog$2.onClick(ViewDialog.java:38)
at android.view.View.performClick(View.java:5721)
at android.widget.TextView.performClick(TextView.java:10936)
at android.view.View$PerformClick.run(View.java:22620)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7406)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
You have to move your code
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//and calling it this way:
KMLabel.setText("MLL/H");
}
});
final TextView KMLabel = (TextView)dialog.findViewById(R.id.KMlabel);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
below the dialog.show() code because code findViewById only work after you pop up dialog.
Create a Global class which extends to application class, then create a texview in Global
Textview t = null;
Then create two static methods to set and get this textview
Public static void setT(TextView p){
t = p;
}
And get it from
Public static TextView getT(){
return t;
}
Set TextView in your activity ,then access this textview from wherever you want until your activity is alive.
Try the code below:
MainActivity class:-------
public class MainActivity extends AppCompatActivity {
private TextView KMlabel;
private Button b;
private ViewDialog vd;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo2);
vd = new ViewDialog();
KMlabel = (TextView) findViewById(R.id.KMlabel);
b = (Button) findViewById(R.id.b);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
vd.showDialog(MainActivity.this , KMlabel , "Your Message" , "Your Text");
}
});
}
}
ViewDialog class:------
public class ViewDialog {
public void showDialog(Context context, final TextView v , String msg , final String text) {
createYesNoInfoDialog(context, msg, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
}, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
v.setText(text);
}
}).show();
}
private AlertDialog createYesNoInfoDialog(Context finalContext, String message,
DialogInterface.OnClickListener onNoListener, DialogInterface.OnClickListener onYesListener) {
AlertDialog a = new AlertDialog.Builder(finalContext).setTitle(
message)
.setNegativeButton("No", onNoListener)
.setPositiveButton("Yes", onYesListener).create();
return a;
}
}
demo2.xml:-----
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="xcxc"
android:id="#+id/KMlabel"/>
<Button
android:layout_width="match_parent"
android:text="Create Dialog"
android:layout_height="wrap_content"
android:id="#+id/b"/>
</LinearLayout>
R.id.KMlabel is on activity_main.xml so you have to initialize the TextView from MainActivity reference.
final TextView KMLabel = (TextView)activity.findViewById(R.id.KMlabel);
Edit:
You can use callback pattern for this:
ViewDialog:
public class ViewDialog {
// interface for callback
public interface OnSelectListener {
public void onOkSelect();
}
OnSelectListener mOnSelectListener;
public void showDialog(Activity activity, String msg, OnSelectListener mListener){
mOnSelectListener = mListener;
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(false);
dialog.setContentView(R.layout.custom_dialog);
//I'm declaring it like this
final TextView KMLabel = (TextView)activity.findViewById(R.id.KMlabel);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//pass to the implementation if not null
if( mOnSelectListener != null){
mOnSelectListener.onOkSelect();
}
}
});
dialog.show();
}
}
In MainActivity:
// initialize interface
ViewDialog.OnSelectListener mOnSelectListener = new ViewDialog.OnSelectListener(){
public void onOkSelect(){
KMLabel.setText("MLL/H");
}
};
ViewDialog viewDialog = new ViewDialog();
viewDialog.showDialog(this, "Message", mOnSelectListener);
This happens since you are trying to call the TextView within the custom alert dialog. TextView only belongs to the MainActivity. You can call or change that only within the MainActivity class. So please try this below.
MainActivity.class
public class MainActivity extends AppCompatActivity {
private TextView KMlabel;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
KMlabel = (TextView) findViewById(R.id.KMlabel);
}
public void setTextKM(String string){
KMlabel.setText(string);
}
}
ViewDialog class
public class ViewDialog {
public void showDialog(Activity activity, String msg){
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(false);
dialog.setContentView(R.layout.custom_dialog);
Button dialogButton = (Button) dialog.findViewById(R.id.btn_dialog);
dialogButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Button KmPerHr = (Button)dialog.findViewById(R.id.KmPerH);
KmPerHr.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MainActivity mainActivity = new MainActivity();
mainActivity.setTextKM("MLL/H");
}
});
dialog.show();
}
}

viewAdapter causing app to crash

I have been trying to figure out why my app has been crashing every time I try to view the list of player names by clicking leaderboard. This is not complete in terms of functionality yet, but I cannot get past the step of two players entering their names and the data being transferred to the list of names upon clicking the button (which will eventually be a leaderboard). I'm just trying to learn android basics and cannot understand why the crash keeps happening. Any help would be greatly appreciated.
public class ListAdapter extends ArrayAdapter<Player> {
LayoutInflater inflater;
public ListAdapter(Context context, ArrayList<Player> players){
super(context, R.layout.user_item, players);
inflater = LayoutInflater.from(context);
}
#Override
#NonNull
public View getView(int position, View view, #NonNull ViewGroup parent){
if (view == null){
view = inflater.inflate(R.layout.user_item, parent, false);
}
Player user = getItem(position);
String text = user.getName() + "" + "Score:" + user.getScore();
((TextView) view.findViewById(R.id.result)).setText(text);
return view;
}
}
Main activity
public class MainActivity extends AppCompatActivity {
private ArrayList<Player> players = new ArrayList<>();
#Override
/*
Creates buttons and assigns listeners.
*/
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button newgame = findViewById(R.id.newgame);
Button leader = findViewById(R.id.leader);
final EditText player1 = (EditText) findViewById(R.id.player1);
final EditText player2 = (EditText) findViewById(R.id.player2);
//New Game Button listener, irrelevant for right now
leader.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String name1 = player1.getText().toString();
String name2 = player2.getText().toString();
Player user1 = new Player(name1);
Player user2 = new Player(name2);
players.add(user1);
players.add(user2);
Intent list = new Intent(view.getContext(), Leaderboard.class);
list.putParcelableArrayListExtra(getString(R.string.players), players);
startActivity(new Intent(MainActivity.this, Leaderboard.class));
}
});
}
}
What should be a listview of players
public class Leaderboard extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leaderboard);
ArrayList<Player> players = getIntent().getParcelableArrayListExtra(getString(R.string.players));
ListView listView = findViewById(R.id.list);
ListAdapter adapter = new ListAdapter(this, players);
listView.setAdapter(adapter); //LINE CAUSING CRASH
Button reset = findViewById(R.id.reset);
Button menu = findViewById(R.id.menu);
reset.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
menu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(Leaderboard.this, MainActivity.class));
}
});
}
}
Error Log:
Caused by: java.lang.NullPointerException: Attempt to invoke interface
method 'int java.util.List.size()' on a null object reference
at android.widget.ArrayAdapter.getCount(ArrayAdapter.java:380)
at android.widget.ListView.setAdapter(ListView.java:575)
I do not understand how the size is null, if I am entering player names.
ArrayList players is null after you are assigning it using getIntent().getParcelableArrayListExtra(getString(R.string.players));
When you pass players to the adapter, the adapter tries to get the size of the arraylist and throws an exception because the list is null.
Make sure that your arraylist is not null before instantiating the adapter and assigning it to the listview.

Categories