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.
Related
I have an android studio activity that contains a RecyclerView, Adapter, and an invisible button at the bottom of the activity. Each itemView thats inside the RecyclerView also has a CheckBox. Inside my Adapter Class I have my Checkbox initialized and has something like - if checkbox.isChecked - then make public static int num = 1 else num = 2; This static variable is then sent to my Activity_main where my bottom button that I need to become Visible can be visible using an if statement that says - if Adapter.num == 1 then button.MakeVisible(true);
Issue is that it's in my Oncreate which is only called once the activity is made. The static number is sent no problem but the activity doesn't update to actually show this. I have to restart the activity to have the button actually become visible.
Adapter Class
public static int p = 0;
#Override
public void onBindViewHolder(#NonNull final Adapter.CustomViewHolder holder,
final int position) {
addedCars = new ArrayList<>();
holder.car.setText(mCars.get(position).getCarName());
holder.mCheckBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(holder.mCheckBox.isChecked()){
Log.d("tag1", "checked");
addedCars.add(mCars.get(position));
String x = Integer.toString(addedCars.size());
Log.d("tag1", x );
p = 1;
holder.mButton2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
else {
Log.d("tag1", "unchecked");
addedCars.remove(mCars.get(position));
p = 2;
}
}
});
}
Activity_Main Class
public class MainActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
Adapter mAdapter;
RecyclerView.LayoutManager mLayoutManager;
Button mButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.RecyclerView);
mButton = findViewById(R.id.button);
ArrayList<Car> cars = new ArrayList<>();
cars.add(new Car("Toyota"));
cars.add(new Car("Ford"));
cars.add(new Car("Tesla"));
mAdapter = new Adapter(cars);
mRecyclerView.setAdapter(mAdapter);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(true);
if (mAdapter.p == 1){
mButton.setVisibility(View.VISIBLE);
}
}
}
If you want to send the num p from RecyclerView Adapter to the activity you need an interface to do so following steps to be followed :
have tested my code in android hope this works for you
creating an interface in the adapter
// create an instance of OnItemChangeListener
public OnItemChangeListener onItemChangeListener;
public interface OnItemChangeListener {
void onItemChanged(int p);
}
//set the instance of onItemChangeListener from the main activity
public void setOnItemChangeListener(OnItemChangeListener onItemChangeListener) {
this.onItemChangeListener = onItemChangeListener;
}
holder.mCheckBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(holder.mCheckBox.isChecked()){
Log.d("tag1", "checked");
addedCars.add(mCars.get(position));
String x = Integer.toString(addedCars.size());
Log.d("tag1", x );
p = 1;
/*
* notify updated value using call back
*/
onItemChangeListener.onItemChanged(p);
holder.mButton2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
2 finally notify update to the main activity
mAdapter = new Adapter(cars);
mAdapter.setOnItemChangeListener(new /*your adapter name */.OnItemChangeListener() {
#Override
public void onItemChanged(int p) {
// here you will get the latest updated value of p
// now you can update you view accordingly
}
});
mRecyclerView.setAdapter(mAdapter);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(true);
I am creating a simple tasklist app in Android Studios.
I have two activities as following (removed imports and package specifications):
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {
EditText taskAdd;
Button add;
public ListView tasks;
public Integer pos = 0;
public ArrayList<String> taskArray;
public ArrayAdapter<String> adapter;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
taskAdd = findViewById(R.id.taskAdd);
add = findViewById(R.id.add);
tasks = findViewById(R.id.tasks);
taskArray = FileHelper.readData(this);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, taskArray);
tasks.setAdapter(adapter);
add.setOnClickListener(this);
tasks.setOnItemClickListener(this);
}
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.add:
String entered = taskAdd.getText().toString();
if (entered != "" || entered != null || entered != "null") {
adapter.add(entered);
taskAdd.setText("");
FileHelper.writeData(taskArray, this);
Toast.makeText(this, "Task Added!", Toast.LENGTH_SHORT).show();
}
break;
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
pos = position;
Intent intent = new Intent(MainActivity.this, Pop.class);
startActivity(intent);
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
processExtraData();
}
private void processExtraData(){
Bundle extras = getIntent().getExtras();
if (extras != null) {
int value = extras.getInt("Value");
if (value == 1) {
taskArray.remove(pos);
adapter.notifyDataSetChanged();
Toast.makeText(this, "Task Removed!", Toast.LENGTH_SHORT).show();
}
}
}
}
Pop.java (a popup)
public class Pop extends Activity implements View.OnClickListener {
Button deleteButton;
Button finishedButton;
Button timerButton;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.popwindow);
deleteButton = findViewById(R.id.deleteButton);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
getWindow().setLayout((int)(width*0.5),(int)(height*0.5));
deleteButton.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent i = new Intent(this, MainActivity.class);
i.putExtra("Value", 1);
startActivity(i);
}
}
After I click deleteButton in Pop.java, processExtraData in MainActivity.java is supposed to run. The Toast does appear, but the selected object in the ListView is not deleted. No errors are thrown either. In addition, using Log.d to check the size of taskArray confirmed that this is not just a graphical issue. Why is this the case, and how should I go about fixing it?
Thank you for replying in advance.
The issue is that you are using an object reference instead of a primitive data type, and so when you are calling taskArray.remove(pos), it is looking for pos the object rather than its denoted integer value.
Instead of:
taskArray.remove(pos);
try:
taskArray.remove(pos.intValue());
I'm trying to figure out how to get the data from a listView, store it in an Array, and be able to access that array of data in another activity. Would I do an Intent for this and pass it as an extra? I've searched around but haven't gotten a clear answer. I want to be able to access that array of data so that I can randomly display it in another activity.
listView.java
public class ListView extends AppCompatActivity {
private static final String TAG = "ListView";
private EditText editText;
private android.widget.ListView listView;
DatabaseHelper mDatabaseHelper;
Button btnAdd;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
mDatabaseHelper = new DatabaseHelper(this);
btnAdd = (Button) findViewById(R.id.btnAdd);
editText = (EditText) findViewById(R.id.editText);
listView = (android.widget.ListView) findViewById(R.id.lv);
ArrayList<String> list = getIntent().getStringArrayListExtra("myList");
android.widget.ListView lv = (android.widget.ListView) findViewById(R.id.lv);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
//Takes user back to the main activity after clicking on back arrow
ImageView ivBack = (ImageView) findViewById(R.id.ivBackArrow);
ivBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: pressed back arrow");
Intent intent = new Intent(ListView.this, MainActivity.class);
startActivity(intent);
}
});
//Adds new hashtag to list and prompts if nothing is entered
btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newEntry = editText.getText().toString();
if (editText.length() != 0) {
addData(newEntry);
editText.setText("");
} else {
toastMessage("you must put something in the text field");
}
}
});
populateListView();
}
/**
* Adds new data into the Database
* #param newEntry
*/
public void addData(String newEntry) {
boolean insertData = mDatabaseHelper.addData(newEntry);
if (insertData) {
toastMessage("Successfully inserted");
recreate();
} else {
toastMessage("Whoops, something went wrong");
}
}
/**
* Default toastMessage
* #param message
*/
private void toastMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
/**
* Populate listView with data and create listener to navigate to editDeleteList
*/
private void populateListView() {
Log.d(TAG, "populateListView: displaying data in the listview");
//get data and append to list
Cursor data = mDatabaseHelper.getData();
ArrayList<String> listData = new ArrayList<>();
while(data.moveToNext()) {
//get the value from the database in column 1
//set it to the arraylist
listData.add(data.getString(1));
}
//create arraylist and set it to the adapter
ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listData);
listView.setAdapter(adapter);
//set onclick listen to edit activity
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
String name = adapterView.getItemAtPosition(position).toString();
Log.d(TAG, "onItemClick: you clicked on " + name);
Cursor data = mDatabaseHelper.getItemID(name); //get the id associated with that name
int itemID = -1;
while (data.moveToNext()) {
itemID = data.getInt(0);
}
if (itemID > -1) {
Log.d(TAG, "onItemID: the ID is: " + itemID);
Intent editScreenIntent = new Intent(ListView.this, EditDeleteList.class);
editScreenIntent.putExtra("id",itemID);
editScreenIntent.putExtra("name",name);
startActivity(editScreenIntent);
} else {
toastMessage("No ID found");
}
}
});
}
/**
* Updates the listView after navigating back from EditDeleteList activity
*/
#Override
protected void onResume() {
super.onResume();
populateListView();
}
}
Get data from listView:
public static String[] getStringArray(ListAdapter adapter){
String[] a = new String[adapter.getCount()];
for (int i = 0; i < a.length; i++)
a[i] = adapter.getItem(i).toString();
return a;}
String[] array = getStringArray(myListView.getAdapter());
Send array from activity to another one:
Intent intent = new Intent(context, Class.class);
intent.putExtra("mylist", array);
Get it back within another activity:
ArrayList<String> myList = (ArrayList<String>) getIntent().getSerializableExtra("mylist");
You can pass an ArrayList<E> the same way, if the E type is Serializable.
I am assuming 1) You are modifying the ListView, 2) On press of button you want to go to another activity and have the data updated from listview in Activity2. From the ListView's adapter, you can create an interface (UpdateListListener) which will be implemented by the Activity1. Whenever you press button(after editing) you just a)Call notifyDatasetChanged() and on the implemented method listener(onUpdatedList()) you just send the list to the other activity with intent. Since List is an object you need to send the intent as below:
Intent intent = new Intent(this,Activity2.class);
intent.putExtra("myList", ListOfItems);
startActivity(intent);
Where ListOfItems implements Parcelable. You need to study how Parcelable works.
Excuse my noobness. I just don't understand how to implement it to work with my code. What I'm doing is editing a name that's in a list view. When editing the name in "EditDeleteList" and get back to the previous activity (ListView) to see the name updated within the list view, nothing happens. I have to go out of the activity completely to see the change reflected. How do I get this to update? I implement an onActivityReult() method but then get this error message "java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference" so I removed it completely. How I could get the list view to update without getting that error message?
ListView.Java
public class ListView extends AppCompatActivity {
private static final String TAG = "ListView";
DatabaseHelper mDatabaseHelper;
Button btnAdd;
private EditText editText;
private android.widget.ListView listView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
mDatabaseHelper = new DatabaseHelper(this);
btnAdd = (Button) findViewById(R.id.btnAdd);
editText = (EditText) findViewById(R.id.editText);
listView = (android.widget.ListView) findViewById(R.id.lv);
ArrayList<String> list = getIntent().getStringArrayListExtra("myList");
android.widget.ListView lv = (android.widget.ListView) findViewById(R.id.lv);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
//Takes user back to the main activity
ImageView ivBack = (ImageView) findViewById(R.id.ivBackArrow);
ivBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: pressed back arrow");
Intent intent = new Intent(ListView.this, MainActivity.class);
startActivity(intent);
}
});
btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newEntry = editText.getText().toString();
if (editText.length() != 0) {
addData(newEntry);
editText.setText("");
} else {
toastMessage("you must put something in the text field");
}
}
});
populateListView();
}
public void addData(String newEntry) {
boolean insertData = mDatabaseHelper.addData(newEntry);
if (insertData) {
toastMessage("Successfully inserted");
recreate();
} else {
toastMessage("Whoops, something went wrong");
}
}
private void toastMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
private void populateListView() {
Log.d(TAG, "populateListView: displaying data in the listview");
//get data and append to list
Cursor data = mDatabaseHelper.getData();
ArrayList<String> listData = new ArrayList<>();
while(data.moveToNext()) {
//get the value from the database in column 1
//set it to the arraylist
listData.add(data.getString(1));
}
//create arraylist and set it to the adapter
ListAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listData);
listView.setAdapter(adapter);
//set onclick listen to edit activity
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
String name = adapterView.getItemAtPosition(position).toString();
Log.d(TAG, "onItemClick: you clicked on " + name);
Cursor data = mDatabaseHelper.getItemID(name); //get the id associated with that name
int itemID = -1;
while (data.moveToNext()) {
itemID = data.getInt(0);
}
if (itemID > -1) {
Log.d(TAG, "onItemID: the ID is: " + itemID);
Intent editScreenIntent = new Intent(ListView.this, EditDeleteList.class);
editScreenIntent.putExtra("id",itemID);
editScreenIntent.putExtra("name",name);
startActivity(editScreenIntent);
} else {
toastMessage("No ID found");
}
}
});
}
}
EditDeleteList.java
public class EditDeleteList extends AppCompatActivity {
private static final String TAG = "EditDeleteList";
DatabaseHelper mDatabaseHelper;
private ImageView ivDelete;
private ImageView ivApprove;
private EditText editHashtag;
private String selectedName;
private int selectedID;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_delete);
mDatabaseHelper = new DatabaseHelper(this);
editHashtag = (EditText) findViewById(R.id.editHashtag);
ivDelete = (ImageView) findViewById(R.id.ivDelete);
ivApprove = (ImageView) findViewById(R.id.ivApprove);
//get the intent extra from the ListView activity
final Intent receivedIntent = getIntent();
//get item ID passed as an extra
selectedID = receivedIntent.getIntExtra("id", -1);
//get name passed as an extra
selectedName = receivedIntent.getStringExtra("name");
//set text field to selected item text
editHashtag.setText(selectedName);
ivApprove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String item = editHashtag.getText().toString();
if (!item.equals(null)) {
mDatabaseHelper.updateName(item, selectedID, selectedName);
} else {
toastMessage("you must enter a #hashtag");
}
finish();
}
});
}
private void toastMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
In the EditDeleteList.java I have an onClickListener that saves the changes and goes back to the previous activity by using finish();
ivApprove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String item = editHashtag.getText().toString();
if (!item.equals(null)) {
mDatabaseHelper.updateName(item, selectedID, selectedName);
} else {
toastMessage("you must enter a #hashtag");
}
finish();
}
});
Notify the adapter in some part of the activity lifecycle.
OnCreate() should not run when you go back (this is the reason you have to completely recreate the activity to see the list updated) so you should use OnRestart/OnStart/OnResume to notify the adapter to check for new items.
Check this image
I want the clicked item to be displayed in another activity.The second activity appears but the string doesn't. I tried other methods as well but the second activity just remains blank.
Here is the Main Activity
EditText TxtOne;
Button btOne;
ListView lisOne;
ArrayList aL;
ArrayAdapter<String> adapt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TxtOne = (EditText) findViewById(R.id.TxtOne);
btOne = (Button) findViewById(R.id.btOne);
lisOne = (ListView) findViewById(R.id.lisOne);
aL = new ArrayList<String>();
adapt = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,aL);
lisOne.setAdapter(adapt);
onBClick();
lisOne.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
Intent itemInfo = new Intent(MainActivity.this, secondActivity.class);
itemInfo.putExtra("Itemis",position);
startActivity(itemInfo);
}
});
}
public void onBClick(){
btOne.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
String InpItem = TxtOne.getText().toString();
aL.add(InpItem);
adapt.notifyDataSetChanged();
}
});
}
The following is the second Activity
public class secondActivity extends AppCompatActivity {
TextView txt2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Bundle passedData = getIntent().getExtras();
txt2 = (TextView)findViewById(R.id.txt2);
txt2.setText(passedData.getString("Itemis"));
}
}
I have read other similar posts but none of them work.
Some talk about the textView not being in the active layout because of which the result is NULL. The textView is in the active layout but still it doesn't display the item.
Solution anyone??
In the below Listener, you are adding position to itemInfo Intent. Here position is of type int, So you should do getIntExtra() to retrieve the Integer data instead of getStringExtra()
lisOne.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
Intent itemInfo = new Intent(MainActivity.this, secondActivity.class);
itemInfo.putExtra("Itemis",position); //position is INT value!!
startActivity(itemInfo);
}
});
So you should do -
getIntExtra(String name, int defaultValue); //this returns the int value of position.
Replace these two lines -
txt2 = (TextView)findViewById(R.id.txt2);
txt2.setText(Integer.toString(getIntent().getExtras().getIntExtra("Itemis",0))); //getting int value in second activity and converting into string for displaying
Note - you should use getStringExtra("Itemis") for retrieving string data from Intents. Not getString("Itemis").
Refer Intent Docs Page for further details on setting and retrieving values from intents.
You are passing and reading extras incorrectly. Do the following:
itemInfo.putExtra("Itemis", position);
and
txt2.setText(String.valueof(getIntent().getIntExtra("Itemis")));