Android listview data doesn't persist when re-created - java

I have a listview that uses a custom arrayadapter that loads a layout with text + a radiobutton. The user should only be able to select a single item in the list at a time - so basically only one radio button should be 'checked' at any time. This works perfectly except when the activity is recreated, like when the screen is rotated. I can't figure out why it's doing this, so maybe you all can think of something?
Here's the code for the activity that has the listview:
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.support.v4.app.NavUtils;
import android.widget.AdapterView;
public class TimeForm extends Activity implements AdapterView.OnItemClickListener {
private MyArrayAdapter maa;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time_form);
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
ListView lv = (ListView) findViewById(R.id.listView1);
lv.setItemsCanFocus(false);
String listitems[] = new String[16];
listitems[0] = "Other";
for(int i = 1; i < 16; i++)
{
listitems[i] = "Job " + i;
}
maa = new MyArrayAdapter(this, R.layout.layout_list, listitems);
if(savedInstanceState != null)
maa.selIndex = savedInstanceState.getInt("selIndex");
lv.setAdapter(maa);
lv.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
EditText et = (EditText) this.findViewById(R.id.editText1);
if(position == 0)
{
et.setVisibility(View.VISIBLE);
} else {
et.setVisibility(View.GONE);
}
if(maa.selItem != null)
{
RadioButton rOld = (RadioButton) maa.selItem.findViewById(R.id.radioButton1);
rOld.setChecked(false);
}
RadioButton r = (RadioButton) view.findViewById(R.id.radioButton1);
r.setChecked(true);
maa.selIndex = position;
maa.selItem = view;
}
public void onSaveInstanceState(Bundle b)
{
b.putInt("selIndex", maa.selIndex);
super.onSaveInstanceState(b);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_time_form, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
}
Code for MyArrayAdapter class:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.RadioButton;
import android.widget.TextView;
public class MyArrayAdapter extends ArrayAdapter<String> {
private Context context;
private String[] strings;
private int layoutID;
public int selIndex;
public View selItem;
public MyArrayAdapter(Context c, int id, String[] values)
{
super(c, id, values);
selIndex = -1;
selItem = null;
this.strings = values;
this.context = c;
layoutID = id;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rView = inflater.inflate(layoutID, parent, false);
TextView tv = (TextView) rView.findViewById(R.id.textView1);
tv.setText(strings[position]);
if(position == selIndex)
{
RadioButton r = (RadioButton) rView.findViewById(R.id.radioButton1);
r.setChecked(true);
selItem = rView;
}
return rView;
}
}

Well, first thing's first, with regards to 're-creating' the view.. check out http://developer.android.com/guide/topics/resources/runtime-changes.html.
You can define public void onConfigurationChanged(Configuration newConfig) to ensure that your activity isn't recreated on rotation, for example.
That said, if you want to persist the values, you'll have to actually do that, and then apply any selections to your collection passed into your ArrayAdapter.

I figured it out. I'm not sure it's the best possible solution, but it works and doesn't cause any noticeable performance loss. ^_^
In the TimeForm activity's onItemClick() method, i added this at the bottom:
ListView lv = (ListView) findViewById(R.id.listView1);
lv.invalidateViews();
This forces the listview to redraw all the child views. Thanks to everyone who took the time to help me figure this out.

Related

Moving from one activity to another by click on card created in a list view

#beginner ...i created the cards list here is the image using list view
i want to get to the new screen frm the click on the card made in list view...please help me to solve this problem .... please give me the full details of the ways by which i can do the task to solve my problems....
.... here is what i coded::::
Main_Activity.java
package com.android.mezohn.nepstudy.app;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.android.mezohn.nepstudy.Adapter.subjectAdapter;
import com.android.mezohn.nepstudy.R;
import com.android.mezohn.nepstudy.model.ListDetails;
import com.android.mezohn.nepstudy.model.model;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ListView listView;
private ArrayList<model>models;
private subjectAdapter subjectAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
listView = (ListView)findViewById(R.id.list_view);
models = ListDetails.getList();
subjectAdapter = new subjectAdapter(MainActivity.this,models);
listView.setAdapter(subjectAdapter);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
model.java
package com.android.mezohn.nepstudy.model;
/**
* Created by ecspc on 25/10/2017.
*/
public class model {
private int subjectImage;
private String subjectTitle;
private String count;
public model(int subjectImage, String subjectTitle, String count) {
this.subjectImage = subjectImage;
this.subjectTitle = subjectTitle;
this.count = count;
}
public int getSubjectImage() {
return subjectImage;
}
public void setSubjectImage(int subjectImage) {
this.subjectImage = subjectImage;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
public String getSubjectTitle() {
return subjectTitle;
}
public void setSubjectTitle(String subjectTitle) {
this.subjectTitle = subjectTitle;
}
}
subjectAdapter.java
package com.android.mezohn.nepstudy.Adapter;
import android.content.Context;
import android.graphics.ColorSpace;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.mezohn.nepstudy.R;
import com.android.mezohn.nepstudy.model.model;
import java.util.ArrayList;
/**
* Created by ecspc on 25/10/2017.
*/
public class subjectAdapter extends BaseAdapter {
private Context context;
private ArrayList<model> models;
public subjectAdapter(Context context, ArrayList<model> models) {
this.context = context;
this.models = models;
}
#Override
public int getCount() {
return models.size();
}
#Override
public Object getItem(int position) {
return models.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView ==null){
convertView = View.inflate(context, R.layout.list_view,null);
ImageView images = convertView.findViewById(R.id.cardImage);
TextView title = convertView.findViewById(R.id.cardTitle);
TextView count = convertView.findViewById(R.id.count);
model model = models.get(position);
images.setImageResource(model.getSubjectImage());
title.setText(model.getSubjectTitle());
count.setText(model.getCount());
}
return convertView;
}
}
ListDetails.java
package com.android.mezohn.nepstudy.model;
import com.android.mezohn.nepstudy.R;
import java.util.ArrayList;
/**
* Created by ecspc on 25/10/2017.
*/
public class ListDetails {
public static ArrayList<model> getList(){
ArrayList<model> subjectList = new ArrayList<>();
subjectList.add(new model(R.drawable.phy,"Physics","4 chapters available"));
subjectList.add(new model(R.drawable.che,"Chemistry","5 chapters available "));
subjectList.add(new model(R.drawable.que,"Model Questions","10 model Questions available"));
return subjectList;
}
}
i am a beginner so i hope i would get sufficient help from it.
So it appears you have not attempted to add a listener to your ListView. You can do this via AdapterView.OnItemClickListener
listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
//.. launch your new activity here using Intent
Intent intent = new Intent(MainActivity.this, NewActivity.class);
startActivity(intent);
}
});
Another note, you should really get better at naming your classes. Recommended reading: Effective Java
You should also read: Making a listview scroll smooth which talks about the ViewHolder pattern, or simply move to a RecyclerView once you know a bit more android.

Android Studio Radio button save state in listview fetched from sqlite

So i have an application where i fetched some poll from an sqlite db and used them in listview and now i tried to add a radio button but when i hit a button back that i created it doesn't save the choice i did from the radio button.
i open the app and...
i choose the second thing
but when i go back and in again the first is selected
here is my listAdapter.java
package com.hfad.myapp.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.RadioButton;
import android.widget.TextView;
import com.hfad.myapp.R;
import com.hfad.myapp.model.Cases;
import java.util.List;
public class ListCases extends BaseAdapter {
private Context mContext;
private List<Cases> mCasesList;
public ListCases(Context mContext, List<Cases> mCasesList) {
this.mContext = mContext;
this.mCasesList = mCasesList;
}
int pose = 0;
#Override
public int getCount() {
return mCasesList.size();
}
#Override
public Object getItem(int position) {
return mCasesList.get(position);
}
#Override
public long getItemId(int position) {
return mCasesList.get(position).getID();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = View.inflate(mContext, R.layout.item_listview, null);
TextView tvName = (TextView)v.findViewById(R.id.tv_case_name);
TextView tvSize = (TextView)v.findViewById(R.id.tv_case_size);
TextView tvMsize = (TextView)v.findViewById(R.id.tv_case_msize);
RadioButton radioButton = (RadioButton)v.findViewById(R.id.radioButton);
radioButton.setChecked(position == pose);
radioButton.setTag(position);
radioButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
pose = (Integer)view.getTag();
notifyDataSetChanged();
}
});
tvName.setText(mCasesList.get(position).getBrand());
tvSize.setText(mCasesList.get(position).getSize());
tvMsize.setText(mCasesList.get(position).getMsize());
return v;
}
}
i remind you that i did a database connection with an external database
it's really frustrating i couldn't find something similar and i can't solve this please help.
p.s. for any mistakes...i am really new in java and android studio in general.

Updating an ArrayAdapter from inside an onClickListener in getView

I am making a shopping cart app where users can add and remove items from the cart. When a user views their cart, a list of items they have added appear. This list is made using an ArrayAdapter. Each row contains a remove button where the user can remove the item from the cart. I have successfully been able to remove the item from the Cart object. However, I am running into trouble when it comes to updating the screen when the user clicks the remove button. I have heard of the notifydatasetchanged() method for adapters, but I am not sure how to implement that from inside the OnClickListener in getView. Here is the code:
CartScreen.java
package com.livilatenight.livilatenight;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;
import com.parse.ParseException;
import com.parse.ParseUser;
import com.parse.SaveCallback;
public class CartScreen extends ActionBarActivity {
ListView items;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart_screen);
final ParseUser current = ParseUser.getCurrentUser();
try{
Cart userCart = (Cart) current.fetchIfNeeded().get("cart");
String[] itemNames = userCart.getItems();
String[] itemPrices = userCart.getPrices();
int[] quantities = userCart.getQuantities();
Integer[] itemPictures = userCart.getPictures();
CartListAdapter adapter = new CartListAdapter(CartScreen.this, itemNames,itemPrices,quantities,itemPictures);
items = (ListView) findViewById(R.id.listView);
items.setAdapter(adapter);
}catch(ParseException e){
Toast.makeText(CartScreen.this, e.toString(),Toast.LENGTH_LONG).show();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_cart_screen, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
CartListAdapter.java
package com.livilatenight.livilatenight;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.parse.ParseUser;
public class CartListAdapter extends ArrayAdapter<String> {
private final Activity context;
private final String[] items;
private final String[] prices;
private final int[] quantities;
private final Integer[] pictures;
public CartListAdapter(Activity context, String[] itemnames, String[] prices, int[] quantities, Integer[] pictures) {
super(context, R.layout.item_list, itemnames);
this.context=context;
this.items=itemnames;
this.prices=prices;
this.quantities=quantities;
this.pictures=pictures;
}
public View getView(final int position,View view,ViewGroup parent) {
LayoutInflater inflater=context.getLayoutInflater();
View rowView=inflater.inflate(R.layout.cart_item, null,true);
TextView itemName = (TextView) rowView.findViewById(R.id.tvItemName);
TextView itemPrice = (TextView) rowView.findViewById(R.id.tvPrice);
ImageView itemPicture = (ImageView) rowView.findViewById(R.id.ivItemPicture);
View blankView = (View) rowView.findViewById(R.id.blankView);
Button removeCart = (Button) rowView.findViewById(R.id.btnRemoveCart);
final Spinner spinner = (Spinner) rowView.findViewById(R.id.spinnerQty);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context, R.array.spinner_numbers, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setSelection(quantities[position]-1);
itemName.setText(items[position]);
itemPrice.setText(prices[position]);
itemPicture.setImageResource(pictures[position]);
removeCart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ParseUser current = ParseUser.getCurrentUser();
int quantity = spinner.getSelectedItemPosition()+1;
Cart userCart = (Cart) current.get("cart");
boolean success = userCart.removeFromCart(items[position]);
if(success){
Toast.makeText(getContext(), "Removed from Cart", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getContext(), "Item is already in your shopping cart", Toast.LENGTH_LONG).show();
}
current.saveInBackground();
}
});
return rowView;
};
}
I want to update the cart list when a user clicks the removeCart button. How could I do this?
UPDATE
I did a workaround where I just set a new adapter each time an item is removed. Not what I wanted to do but it works so I'll keep it the way it is.
try this
if (success) {
Toast.makeText(getContext(), "Removed from Cart", Toast.LENGTH_LONG).show();
final String s = items[position];
List<String> list = new ArrayList<String>(Arrays.asList(items));
list.remove(s);
items = list.toArray(array);
this.notifyDataSetChanged()
}
In your custom adapter call this.notifyDataSetChanged(); where you are performing delete functionality and deleting that element from arrayList which is set to that adapter.
You have to remove that record from the ArrayList too that you have set to your adapter if you know which record it is you can use ArrayList.remove(index); and then use notifyDataSetChanged();
EDIT:
Go to your adapter and add a method delete();
public void delete(int position){
data.remove(position);
notifyItemRemoved(position);
}
In your onClick(); method add this:
delete(getPosition());
Here is the solution that worked in my case.
In your CartListAdapter override remove method of Array Adapter.
#Override
public void remove(String var){
// Call your utility methods you defined to delete the item
// Notify ListView that their is a change
notifyDataSetChanged();
}
Make the following changes in your Click Listener
removeCart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Call this.remove(var) with String you want to delete
}
});
notifyDataSetChanged() works only in case of add(), insert(), remove(), and clear(). Read this
HTH

Create a Context Menu when Click Long in a Custom ListView

I want to show a context menu (OnClickLong)with delete and edit option, in a custom list i created with a custom list adapter. i will post the code
SpotListFragment
package com.pap.myspots.fragments;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.pap.myspots.R;
import com.pap.myspots.R.layout;
import com.pap.myspots.database.DBAdapter;
import com.pap.myspots.listView.SpotList;
import com.pap.myspots.listView.SpotListAdapter;
import android.annotation.SuppressLint;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
public class SpotListFragment extends Fragment implements OnClickListener{
String nome;
String local;
Button createToast;
List<String> nomes ;
List<String> locais ;
ListView listView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_spotlist, container, false);
DBAdapter db = new DBAdapter(getActivity());
db.open();
Cursor cursor = db.getAllTitles();
nomes = new ArrayList<String>();
while(cursor.moveToNext()){
String uname = cursor.getString(cursor.getColumnIndex("nome"));
nomes.add(uname);
}
Cursor cursor2 = db.getAllTitles();
locais = new ArrayList<String>();
while(cursor2.moveToNext()){
String ulocal = cursor2.getString(cursor.getColumnIndex("local"));
locais.add(ulocal);
}
SpotListAdapter adapter = new SpotListAdapter(getActivity(), generateData());
// 2. Get ListView from activity_main.xml
listView = (ListView) rootView.findViewById(R.id.spotList);
// 3. setListAdapter
listView.setAdapter(adapter);
return rootView;
}
private ArrayList<SpotList> generateData(){
ArrayList<SpotList> items = new ArrayList<SpotList>();
int i = 0;
while(nomes.size()>i){
items.add(new SpotList(new String(nomes.get(i)),new String(locais.get(i))));
i++;
}
return items;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
//Deleted individual cart items
}
SpotListAdapter
package com.pap.myspots.listView;
import java.util.ArrayList;
import com.pap.myspots.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class SpotListAdapter extends ArrayAdapter<SpotList> {
private final Context context;
private final ArrayList<SpotList> itemsArrayList;
public SpotListAdapter(Context context, ArrayList<SpotList> itemsArrayList) {
super(context, R.layout.list_row, itemsArrayList);
this.context = context;
this.itemsArrayList = itemsArrayList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// 1. Create inflater
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// 2. Get rowView from inflater
View rowView = inflater.inflate(R.layout.list_row, parent, false);
// 3. Get the two text view from the rowView
TextView labelView = (TextView) rowView.findViewById(R.id.title);
TextView valueView = (TextView) rowView.findViewById(R.id.place);
// 4. Set the text for textView
labelView.setText(itemsArrayList.get(position).getNome());
valueView.setText(itemsArrayList.get(position).getLocal());
// 5. retrn rowView
return rowView;
}
}
SpotList(Beans)
package com.pap.myspots.listView;
public class SpotList {
public SpotList(String nome, String local) {
super();
this.nome = nome;
this.local = local;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getLocal() {
return local;
}
public void setLocal(String local) {
this.local = local;
}
private String nome;
private String local;
}
So first of all register your listView for a context menu in the onCreate method:
registerForContextMenu(yourListView);
Create the contextmenu by overridig the onCreateContextMenu:
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
_listPosition = info.position; // Get Index of long-clicked item
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle("Choose Action"); // Context-menu title
menu.add(0, v.getId(), 0, "Edit"); // Add element "Edit"
menu.add(0, v.getId(), 1, "Delete"); // Add element "Delete"
}
React on clicks in context-menu:
#Override
public boolean onContextItemSelected(MenuItem item)
{
if(item.getTitle() == "Edit") // "Edit" chosen
{
// Do stuff
}
else if(item.getTitle() == "Delete") // "Delete" chosen
{
// Do stuff
}
else
{
return false;
}
return true;
}
Next time just spend few minutes and google it yourself:
http://developer.android.com/guide/topics/ui/menus.html#context-menu
http://www.stealthcopter.com/blog/2010/04/android-context-menu-example-on-long-press-gridview/
Override onCreateContextMenu() to create the menu and onContextItemSelected() to handle the click event
You also need to register listView for the contextual menu. You can do it in fragment's onActivityCreated() method:
registerForContextMenu(listView);
You have to register your custom ListView with Context Menu. Use Method registerForContextMenu(listView); . Call this method in onCreate
I would define the onLongClickListener in the getView() method of your overriden ArrayList extension. Just register the view inside the long click listener, using registerForContextView(convertView).
Now in your Activity code, simply define the context menu as you would in any other case:
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
...
menu.setHeaderTitle(...);
menu.add(...);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
final int mId = item.getItemId();
switch (mId) {
case 0:
...
break;
default:
break;
}
More precision:
#Override
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
TreeViewList v1=(TreeViewList) v; //my custom listview
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
final LinearLayout viewLayout = (LinearLayout) v1.getChildAt(info.position-v1.getFirstVisiblePosition());//if in list many items
final TextView descriptionView = (TextView) viewLayout
.findViewById(R.id.list_item_description);
menu.add(0, v.getId(), 0, descriptionView.getText());
menu.add(0, v.getId(), 0, "Action 2");
}

DialogFragment created by an event from a button in a custom ArrayAdapter always has same position

I'm a newb so try to be patient with me
Here is some background information about the problem I am having:
I have a fragment, ViewFragment, that consists of two components: a Spinner and a ListView. The Spinner is a default Spinner with a regular ArrayAdapter that fills the Spinner with values taken from an ArrayList called "metaList" that is basically and ArrayList of objects that each themselves have an ArrayList called "mainList".
The ListView has the custom ArrayAdapter (called "CustomAdapter") I mentioned in the title. The CustomAdapter fills the ListView with values taken from the "mainList" of the selected item in the Spinner.
Now, the CustomAdapter for the ListView has two buttons. The only button that does anything yet (called "viewButton") creates a DialogFragment when pushed.
The problem I am having relates to this DialogFragment. Each item in the ListView should create a unique DialogFragment when its viewButton is pressed. However, regardless of which item in the ListView has its button pressed, the DialogFragment is always the same and displays the DialogFragment for the last item in the ListView.
I think that this problem is due to the fact that the ListView items themselves are not being pressed, only their buttons, so the position value in the getView() method for the CustomAdapter never really changes.
How do I fix this problem?
Here is the code for the ViewFragment that contains the Spinner and ListView components:
package com.statbot;
import java.util.ArrayList;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.AdapterView.OnItemSelectedListener;
public class ViewFragment extends Fragment{
static int spinPos;
private ArrayList<String> names;
private ArrayList<String> nums;
private Spinner spinner;
private View view;
private ViewGroup container;
private ListView listView;
private Fragment frag;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.view_layout, container, false);
this.container = container;
frag = this;
names = new ArrayList<String>();
nums = new ArrayList<String>();
spinner = (Spinner)view.findViewById(R.id.view_frag_spinner1);
listView = (ListView) view.findViewById(R.id.view_frag_listView2);
for(int k = 0; k < MainActivity.metaList.size(); k++)
{
names.add(MainActivity.metaList.get(k).getName());
}
ArrayAdapter<String> adapter = new ArrayAdapter<String> (container.getContext(),android.R.layout.simple_spinner_item, names);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new SpinListener());
return view;
}
private class SpinListener extends Activity implements OnItemSelectedListener{
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
// TODO Auto-generated method stub
spinPos = pos;
nums.clear();
for(int k = 0; k < MainActivity.metaList.get(pos).mainList.size(); k++)
{
nums.add("" + MainActivity.metaList.get(pos).mainList.get(k).quantity);
}
CustomAdapter adapter2 = new CustomAdapter(container.getContext(), android.R.layout.simple_spinner_item, nums);
adapter2.setFrag(frag);
listView.setAdapter(adapter2);
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
spinPos = 0;
}
}
}
Here is the code for the CustomAdapter:
package com.statbot;
import java.util.List;
import android.app.Fragment;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
public class CustomAdapter extends ArrayAdapter{
private TextView quantity;
private ImageButton editButton;
private ImageButton deleteButton;
private ImageButton viewButton;
private Context mContext;
private int id;
private Fragment frag;
private int pos;
private List<String> objects;
#SuppressWarnings("unchecked")
public CustomAdapter (Context context, int textViewResourceId, List<String> objects){
super(context, textViewResourceId, objects);
mContext = context;
id = textViewResourceId;
this.objects = objects;
}
public View getView(int position, View v, ViewGroup parent){
this.pos = position;
final int POSITION = position;
View mView = v;
if (mView == null){
LayoutInflater vi = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = vi.inflate(R.layout.cust_list_view, parent, false);
}
editButton = (ImageButton) mView.findViewById(R.id.cust_list_view_button1);
viewButton = (ImageButton) mView.findViewById(R.id.cust_list_view_button2);
quantity = (TextView) mView.findViewById(R.id.cust_list_view_textView1);
if(quantity == null)
{
System.out.println("The poop is a lie");
}
quantity.setText("" + pos + "," + ViewFragment.spinPos);
viewButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
System.out.println("" + POSITION);
showContents(ViewFragment.spinPos, POSITION);
}
});
return mView;
}
private void showContents(int metaPos, int mainPos){
NumStatDialog contents = new NumStatDialog();
contents.setMainPosition(pos);
contents.setMetaPosition();
contents.show(frag.getFragmentManager(), "content_dialog");
}
public void setFrag(Fragment f){
frag = f;
}
}
Here is the code for the DialogFragment, called NumStatDialog:
package com.statbot;
import android.annotation.SuppressLint;
import android.app.DialogFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
#SuppressLint("ValidFragment")
public class NumStatDialog extends DialogFragment{
private View view;
private int metaPosition;
private int mainPosition;
private TextView title;
private TextView info;
private boolean type;//if true, sets up a dialog to display information on a list. if false, displays information on an item of that list.
public NumStatDialog(int metaPos, int mainPos){
type = false;
metaPosition = metaPos;
mainPosition = mainPos;
}
public NumStatDialog(int metaPos){
type = true;
metaPosition = metaPos;
}
public NumStatDialog(){
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.numstat_dialog_layout, container);
info = (TextView) view.findViewById(R.id.numstat_dialog_textView2);
title = (TextView) view.findViewById(R.id.numstat_dialog_textView1);
if(!type){
//info.setText((CharSequence) MainActivity.metaList.get(metaPosition).mainList.get(mainPosition).toString());
info.setText((CharSequence) ("" + mainPosition));
//title.setText((CharSequence) ("" + MainActivity.metaList.get(metaPosition).mainList.get(mainPosition).quantity));
title.setText((CharSequence) ("" + metaPosition));
}
if(type){
info.setText((CharSequence) MainActivity.metaList.get(metaPosition).toString());
title.setText((CharSequence) MainActivity.metaList.get(metaPosition).getName());
}
return view;
}
public void setMainPosition(int mp){
mainPosition = mp;
}
public void setMetaPosition(){
metaPosition = ViewFragment.spinPos;
}
}
and here are some screenshots to make things easier to understand. The spinner is at the top with the ListView directly below it. The first number of each ListView item is its position, and the second number is the position of the Spinner. The button of interest is the paper-shaped one. ignore the pencil, it doesn't do anything yet.
and here is a DialogFragment. The title is the Spinner position and the bottom number is the position of the item whose button was pushed, but notice that even though the 1st item on the ListView had its button pushed to display this dialog, the number at the bottom of the fragment displays a three for the 4th item.
Any help on this problem would be greatly appreciated, this is one of the last major hurdles I need to overcome for this project, everything else should be pretty basic.
Thanks!
In your showContents(), you completely ignore the two parameters passed in and instead use this.pos, which would indeed be the position of the last view inflated by the ListView. Just use your parameters (and set up your IDE to warn you about unused variables and parameters).
On a different note, passing data to a fragment like this would not survive configuration changes (unless you have setRetainInstance everywhere, but that's riddled with different sorts of problems). Consider using setArguments, serializing state in onSaveInstanceState and deserializing it in onCreate (using getArguments or savedInstanceState, if that's available).

Categories