ListView replaces first object instead of adding a new one - android

I created a test project, and in that project I am trying to create a listview that the user can add to when they click a button. The button opens an new activity with an editText and another button to go back to the listview activity and an item should have been added. It works the first time, but when I add another Item it replaces the old one. I have search for a while now, and all the other answer don't seem to help me. Thanks in advance.
public class MainActivity extends Activity {
ListView simpleList;
String input;
ArrayList<Item> listItems =new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
simpleList = (ListView) findViewById(R.id.listView);
addData();
MyAdapter myAdapter=new MyAdapter(this,R.layout.row, listItems);
simpleList.setAdapter(myAdapter);
}
public void addData(){
Bundle extras = getIntent().getExtras();
if (extras != null) {
input = extras.getString("Homework");
listItems.add(new Item(input, input, input));
}
}
public void toInput(View view){
Intent intent = new Intent(this, inputScreen.class);
startActivity(intent);
}}
This is my main activity, the adapter is a custom adapter that is made in this class.
public class MyAdapter extends ArrayAdapter<Item> {
ArrayList<Item> listItems = new ArrayList<>();
public MyAdapter(Context context, int textViewResourceId, ArrayList<Item> objects){
super(context, textViewResourceId, objects);
listItems = objects;
}
public int getCount(){
return super.getCount();
}
public View getView(int position, View convertView, ViewGroup parent){
View v = convertView;
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.row, null);
TextView textView = (TextView) v.findViewById(R.id.homeworkDisplay);
TextView textView2 = (TextView) v.findViewById(R.id.dueDisplay);
TextView textView3 = (TextView) v.findViewById(R.id.classDisplay);
textView.setText(listItems.get(position).getHomework());
textView2.setText(listItems.get(position).getDate());
textView3.setText(listItems.get(position).getClasses());
return v;
}}
The string that is added to the listview is sent from the another activity that gets it from an editText, here is it's class
public class inputScreen extends Activity{
EditText userInput;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.input_screen);
userInput = (EditText) findViewById(R.id.editText);
}
public void sendInfo(View view){
Intent goingBack = new Intent(this,MainActivity.class);
goingBack.putExtra("Homework", userInput.getText().toString());
startActivity(goingBack);
}}
I know there is alot of code there, you don't need to go through it all as I am sure the problem is in MainActivity. I have another class called items that returns homework. Thank you!

Used startActivity() is not correct.
your activity stack is like this :
the start
~~~~~~~~~~~~
MainActivity
~~~~~~~~~~~~
after you call toInput in MainActivity()
~~~~~~~~~~~~
InputScreen(activity)
MainActivity
~~~~~~~~~~~~
then when you call send() in InputScreen
~~~~~~~~~~~~
MainActivity
InputScreen
MainActivity
~~~~~~~~~~~~
see what's happening?
the first time in InputScreen you called send() start MainActivity with extras
then you started a new MainActivity ,then went the addData() ,you got data, and changed listView.
but when you do it again , you always start new Activities ,so only the first one was gonna change
always repeat the first step always start a new activity
you should call startActivityForResult() in MainActivity to start inputScreen and override the onActivityResult method in MainActivity
just google startActivity and startActivityForResult you will work this out .
and anther key word you should google is ,listView --> data source
sorry,I am not a native English speaker, if I did something wrong ,please forgive me ~~~~

Written by: https://stackoverflow.com/users/2936153/rohit5k2
Source: Listview replaces first item instead of creating new items
Every time you call changeText() your adapter is reset so only one
item will be displayed
Change your fragment like this
public class ListViewFragment1 extends Fragment {
protected ArrayAdapter<String> adapter1;
ListView list1;
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_view_fragment1, container, false);
adapter1 = new ArrayAdapter<String>(getActivity(), R.layout.items);
list1 = (ListView) view.findViewById(R.id.listview1);
list1.setAdapter(adapter1);
return view;
}
public void changeText(String data){
adapter1.add(data);
adapter1.notifyDataSetChanged();
}
}

Related

How can I reload an activity from a listview to update information of a database?

I'm trying to implement something like this:
I have a main class with a layout from where I get some data from the database and plot it as shown in the image (with another layout complex_list):
public class main_class extends Activity{
DatabaseHelper myDB;
ListView list;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
myDB=new DatabaseHelper(this);
list = (ListView) findViewById(R.id.list);
Cursor res = myDB.getAllData();
if (res.getCount()==0){
Toast.makeText(this,R.string.nothing_found,Toast.LENGTH_LONG).show();
}
else{
...
list.setAdapter(new listAdapter(..., this.getBaseContext()));
}
I've a class to implement the BaseAdapter:
class listAdapter extends BaseAdapter {
public View getView(final int position, View convertView, final ViewGroup parent) {
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE );
View row;
row = inflater.inflate(R.layout.complex_list, parent, false);
...
Delete = (Button) row.findViewById(R.id.delete_entry_list);
...
Delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
deleteEntry(id[position]);
Intent refresh = new Intent(context, main_class.class);
refresh.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //I've added this line because otherwise I get an error an the app crashes.
context.startActivity(refresh);
//((Activity)context).finish();
}
});
return (row);
}
public void deleteEntry ( int id){
DatabaseHelper myDB = new DatabaseHelper(context);
myDB.deleteData(Integer.toString(id));
}
What I'm trying to do is refreshing the whole activity once the delete button is pressed to see an updated version of the database.
What I've written does work, but when I press the return button in the phone it returns to the old image of the database instead of going to the menu from where I accessed to this activity.
I've been researching similar questions and the only solution I've found is to add the line which is commented:
//((Activity)context).finish();
But it makes my app crash with this error:
java.lang.ClassCastException: android.app.ContextImpl cannot be cast to android.app.Activity
Could anyone give me a hint of what I'm doing wrong or if there is an easier way to this?
ClassCastException: android.app.ContextImpl cannot be cast to android.app.Activity
Probably starts from
list.setAdapter(new listAdapter(..., this.getBaseContext()));
You should use this in place of this.getBaseContext() there as Activity extends Context

Populating Custom List with Intent Extras - Android

I am an application, which is basically an empty activity (empty list-view) where in the toolbar there is an Add button, clicking the button takes you to another activity with two edit text fields and a button (to submit the activity, in other words send the intent extras to the first activity). I want to take those input (both are strings) from that activity and display them in the list-view in the first activity.
I have made the toolbar and the button, and placed the custom list-view with its adapter in the first activity, and in the second activity I created the necessary views and along with the intent (for passing the two strings).
The problem is, that in the second activity, when I pass the intent extras to the first activity, a new list-view gets created every time instead of appending the list-view.
Can someone help me append the intent extras rather than creating a new list every time the user adds the two inputs?
This is the onCreate method in the first activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_countries);
ActionBar actionBar = getActionBar();
if(actionBar != null)
actionBar.setDisplayHomeAsUpEnabled(true);
listView = (ListView) findViewById(R.id.listView);
populateList();
}
This is the populateList();
public void populateList(){
Bundle countryData = getIntent().getExtras();
if (countryData == null){
return;
}
String country = countryData.getString("country");
String year = countryData.getString("year");
ArrayAdapter<Country> adapter = new CustomAdapter();
listView.setAdapter(adapter);
countryList.add(new Country(country, year));
}
This is the adapter:
private class CustomAdapter extends ArrayAdapter<Country>{
public CustomAdapter() {
super(MyCountries.this, R.layout.list_item, countryList);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null){
view =getLayoutInflater().inflate(R.layout.list_item, parent, false);
}
Country currentCountry = countryList.get(position);
TextView countryText = (TextView) view.findViewById(R.id.countryName);
countryText.setText(currentCountry.getCountryName());
TextView yearText = (TextView) view.findViewById(R.id.yearOfVisit);
yearText.setText(currentCountry.getYear());
notifyDataSetChanged();
return view;
}
}
And this is the onClick() for submitting the input:
public void onClick(View v) {
String country = addCountry.getText().toString();
String year = addYear.getText().toString();
Intent result = new Intent(this, MyCountries.class);
result.putExtra("country", country);
result.putExtra("year", year);
startActivity(result);
}
Thank you very much.
Any help, or guidance will be greatly appreciated.

Listview not updating after arraylist is updated?

I've seen many other posts in this context, but none helped. Problem is when i click on the addField button, the listview inside dialog adds new view just once. But at other clicks it doesn't get updated though The adapter works correctly (I mean the getView is called and also the arrayList in the adapter is changed in size).
I've used notifyDataSetChanged() in the adapter class. No result! I used an instance of adpater class in activity and called myAdapter.notifyDataSetChanged(). No result!
here is my code:
public class MainActivity extends Activity {
ListView lvfid;
FieldAdapter fAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some code
showFid();
}
private void showFiD(){
final ArrayList <HashMap<String,String>> al = new ArrayList<HashMap<String,String>>();
final Dialog dialog = new Dialog(MainActivity.this , R.style.DialogTheme);
dialog.setContentView(R.layout.field_dialog);
dialog.setCancelable(true);
dialog.show();
Button addField = (Button) dialog.findViewById(R.id.btnfidField);
lvfid = (ListView) dialog.findViewById(R.id.lvfid);
//Another plan i have tested, but no result:
//fAdapter = new FieldAdapter(dialog.getContext(),al);
//lvfid.setAdapter(fAdapter);
addField.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
HashMap<String,String> h = new HashMap<String,String>();
h.put("name", "");
h.put("value", "");
al.add(h);
lvfid.setAdapter(new FieldAdapter(dialog.getContext(), al));
//fAdapter.notifyDataSetChanged();
}
});
}
public class FieldAdapter extends BaseAdapter{
private ArrayList <HashMap <String,String>> arrayList;
private LayoutInflater inflater;
public FieldAdapter(Context context, ArrayList<HashMap <String,String>> arrayList) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.arrayList = arrayList;
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup arg2) {
View view = null;
if (convertView == null)
view = inflater.inflate(R.layout.field_inflater, null);
else
view = convertView;
Holder holder = new Holder();
holder.edName = (EditText) view.findViewById(R.id.edfidName);
holder.edValue = (EditText) view.findViewById(R.id.edfidValue);
//holder.edName.setText(arrayList.get(position).get("name"));
//holder.edValue.setText(arrayList.get(position).get("value"));
return view;
}
private class Holder {
private EditText edName;
private EditText edValue;
}
}
}
UPDATE:
I'm sorry i took everybody's time. The stupid problem was that my listview was inside a scrollview where it must not be! I hope this helps others who have the same issue!
Use the notifyDataSetChanged() every time the list is updated.
I had the same problem. I was facing with this problem when I wanted to update the listView after onDateChanged(). I resolved it with an extra ArrayList variable and an extra custom adapter in your case FieldAdapter variable.
Update your listView with a refresh adapter and array list variables after any operations. For example after button clicks.
1. Define a counter.
2. Check when the button is clicked, increase counter by one
3. Every time check the counter, if counter is greater than 1 it means the button is clicked more than once so update the list view with new variables (arrayList, FeildAdapter)
I recommend you to define the variables as a private class fields and name them such as refreshedArrayList and refreshedAdapter
Option
Try to use the ArrayAdapter. And don't create a new adapter every
time you click on the button.
only call the add(T o) function from the ArrayAdapter.
Other Option:
add a add function to your FieldAdapter in the add field adapter add the object to your arraylist and call notifiyDataSetChanged(the adapter has aslo one and the adapter notifies all his observers)
also don't create a new adapter every time you click the button.
public class MainActivity extends Activity {
ListView lvfid;
FieldAdapter fAdapter;
ArrayList <HashMap<String,String>> al ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//some code
al = new ArrayList<HashMap<String,String>>();
lvfid.setAdapter(new FieldAdapter(MainActivity.this , al));
showFid();
}
private void showFiD(){
final Dialog dialog = new Dialog(MainActivity.this , R.style.DialogTheme);
dialog.setContentView(R.layout.field_dialog);
dialog.setCancelable(true);
dialog.show();
Button addField = (Button) dialog.findViewById(R.id.btnfidField);
lvfid = (ListView) dialog.findViewById(R.id.lvfid);
//Another plan i have tested, but no result:
//fAdapter = new FieldAdapter(dialog.getContext(),al);
//lvfid.setAdapter(fAdapter);
addField.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
HashMap<String,String> h = new HashMap<String,String>();
h.put("name", "");
h.put("value", "");
al.add(h);
fAdapter.notifyDataSetChanged();
}
});
}
I'm sorry i took everybody's time! The stupid problem was just my listview was inside a scrollview where it must not be! after getting the listview out of scrollview the problem got solved.

ListView displays item after 2nd item has been created

So I'm having a weird order of events in my code. It'll probably be something minor that I haven't seen yet. A have ListView that and is pulling the string from an EditText after button click.
The EditText lives in a dialog that's being pulled back to the main Activity by an interface
What happens now, is when I type something in the EditText field say "a", nothing shows up. But when I go to add another, "b", "a" shows up. and so forth. So one has to be created in order for the previous to show up.
Here's my what I have.
public class NewActivity extends FragmentActivity implements AddSiteDialog.AddSiteDialogListener {
ListView mSiteListView;
ArrayList<String> siteList = new ArrayList<String>();
CustomAdapter arrayAdapter = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_site);
mSiteListView = (ListView) findViewById(R.id.siteAddList);
arrayAdapter = new CustomAdapter();
mSiteListView.setAdapter(arrayAdapter);
Button b = (Button) findViewById(R.id.addSiteButton);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog();
}
});
}
public void showDialog() {
FragmentManager fm = getSupportFragmentManager();
AddSiteDialog addSiteDialog = new AddSiteDialog();
addSiteDialog.show(fm, "main");
}
public void onSignIn(String inputText) {
siteList.add(inputText);
}
class CustomAdapter extends ArrayAdapter<String> {
CustomAdapter() {
super(NewActivity.this, R.layout.add_site, siteList);
}
public View getView(int position, View convertView, ViewGroup parent){
View row = convertView;
if (row == null){
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.list_row, parent, false);
}
((TextView) row.findViewById(R.id.textViewId)).setText(siteList.get(position));
return (row);
}
}
}
Can anyone spot where this is happening?
Simple.
call arrayAdapter.notifyDataSetChanged() in
public void onSignIn(String inputText) {
siteList.add(inputText);
//add that here
}
If the data which is backed by your adapter changes, you need to call notifyDataSetChanged() on your adapter to instruct the ListView to update itself.
I don't see anything like that in your code.
Just to add:
Your adapter implementation is sub-optimal - although in this case it doesn't really matter.
You should create a ViewHolder and store it as your View's tag, so that you can retrieve it if convertView is given. The ViewHolder should keep references to all sub-views of your view (TextView, ImageView, whatever you need to update). This would avoid the repeated call to findViewById() - which is slow.

How to let OnClick in ListView's Adapter call Activity's function

I have an Android application with a ListView in it, the ListView will setup fine but now I want a image in the ListView to be clickable. I do this by using 2 classes, the Activity class (parent) and an ArrayAdapter to fill the list. In the ArrayAdapter I implement a OnClickListener for the image in the list that I want to be clickable.
So far it all works.
But now I want to run a function from the activity class when the onClick, for the image in the list, is run but I do not know how. Below are the 2 classes that I use.
First the Activity class:
public class parent_class extends Activity implements OnClickListener, OnItemClickListener
{
child_class_list myList;
ListView myListView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// setup the Homelist data
myList = new child_class_list (this, Group_Names, Group_Dates);
myListView = (ListView) findViewById(R.id.list);
// set the HomeList
myListView.setAdapter( myList );
myListView.setOnItemClickListener(this);
}
void function_to_run()
{
// I want to run this function from the LiscView Onclick
}
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
// do something
}
}
And the ArrayAdapter from where I want to call a function from the Activity class:
public class child_class_list extends ArrayAdapter<String>
{
// private
private final Context context;
private String[] mName;
private String[] mDate;
public child_class_list (Context context, String[] Name, String[] Date)
{
super(context, R.layout.l_home, GroupName);
this.context = context;
this.mName = Name;
this.mDate = Date;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.l_home, parent, false);
ImageView selectable_image = (ImageView) rowView.findViewById(R.id.l_selectable_image);
selectable_image.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
// I want to run the function_to_run() function from the parant class here
}
}
);
// get the textID's
TextView tvName = (TextView) rowView.findViewById(R.id.l_name);
TextView tvDate = (TextView) rowView.findViewById(R.id.l_date);
// set the text
tvName.setText (mName[position]);
tvDate.setText (mDate[position]);
return rowView;
}
}
If anyone knows how to run the function in the activity class from the arrayadapter or how to set the image onClickListener in the Activity Class I would greatly apriciate the help.
Inside onClick() Do something like this:
((ParentClass) context).functionToRun();
Just for clarity to expand on provided answers
In a BaseAdapter you can get the parent class by calling this.getActivity();If you then typecast this to the actual activity class you can then call a function as per #AdilSoomro answer below so you actually end up with something like this
public class MyAdapter extends BaseAdapter<Long> {
public MyAdapter(Activity activity,
TreeStateManager<Long> treeStateManager, int numberOfLevels) {
super(activity, treeStateManager, numberOfLevels);
}
#Override
public void handleItemClick(final View view, final Object id) {
((MyActivity) this.activity).someFunction();
}
}
Then just declare someFunction in MyActivity to do what you want
protected void someFunction(){
// Do something here
}

Categories

Resources