Quick question, I wanted to make a listview that only displays certain items from an array, stored in a different class called MyArray. I would like the list view, in this case, to display only items whose title is 'example'. Is it possible to do this? I would also need to know this to make items deleted from the array ("" items) not appear in the listview. Thank you, I've included my whole listview code to avoid confusion! Hope this isnt too complicated of a question!
public class List extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list);
setListAdapter(new MyAdapter(this,
android.R.layout.simple_list_item_1, R.id.textView1,
MyArray.myarr));
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> adapter, View v, int position,
long arg3)
{
String index = (String)adapter.getItemAtPosition(position);
//Intent myIntent = new Intent(List.this, Show.class);
//List.this.startActivity(myIntent);
Intent i = new Intent(getApplicationContext(), Show.class);
i.putExtra("index", ""+position);
startActivity(i);
}
});
}
private class MyAdapter extends ArrayAdapter<String> {
public MyAdapter(Context context, int resource,
int textViewResourceId, String[] strings) {
super(context, resource, textViewResourceId, strings);
// TODO Auto-generated constructor stub
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater inflator = (LayoutInflater) getSystemService (Context.LAYOUT_INFLATER_SERVICE);
View row = inflator.inflate(R.layout.customlist, parent, false);
String[] items = MyArray.myarr;
ImageView iv = (ImageView) row.findViewById(R.id.imageView1);
TextView tv = (TextView) row.findViewById(R.id.textView1);
if (items[position].equalsIgnoreCase("Example")){
}
else
{
tv.setText(items[position]);
iv.setImageResource(R.drawable.base);
}
return row;
}
}
}
I would not recommend the described approach in your question. If you don't need items in a ListView, don't pass them in your Array or List. Do some prefiltering. If you dynamically want to modify the contents of a ListView after it has been loaded, well, different topic and more sophisticated.
ListAdapter depends on the number of items in it, there are methods like getCount, getItem(int position) and you would have to implement all of those to avoid NULL - Pointer or index - out -of bound execptions.
Related
This is example from Android for beginners book. I think that problem is with mNoteAdapter but I can't find where it exactly is. I tried to use adapter from other source and it was working(I mean click) so I could see at least log in logcat. How does mNoteAdapter affect on possibility of seeing users click by app? How can I find where problem is?
mNoteAdapter = new NoteAdapter();
ListView listNote = (ListView) findViewById(R.id.listView);
listNote.setAdapter(mNoteAdapter);
listNote.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> adapter, View view, int
whichItem, long id) {
Log.e("CLICK", "CliCK");
}
});
}
Here is a piece of NoteAdapter class
public class NoteAdapter extends BaseAdapter {
List<Note> noteList = new ArrayList<Note>();
#Override
public int getCount() {
}
#Override
public Note getItem(int whichItem) {
}
#Override
public long getItemId(int whichItem) {
}
#Override
public View getView(int whichItem, View view, ViewGroup viewGroup) {
if (view == null) {
LayoutInflater inflater = (LayoutInflater)
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.listitem, viewGroup, false);
}
TextView txtTitle = (TextView) view.findViewById(R.id.txtTitle);
ImageView ivImportant = (ImageView) view.findViewById(R.id.imageViewImportant);
Note tempNote = noteList.get(whichItem);
if (!tempNote.isImportant()) {
ivImportant.setVisibility(View.GONE);
}
txtTitle.setText(tempNote.getTitle());
return view;
}
public void addNote(Note n) {
}
}
There are many ways to display items as list on Android..
--> ListView, RecyclerView etc.
Lists need a source right? Let's assume that your source is an array of 1000 elements. Your ListView has to have as many columns to display all of them right?
Adapter is responsible for taking the array, and assigning each element to every list placeholders
This row was added to the top of .xml file
android:descendantFocusability="blocksDescendants"
I can get the text to set once but after it sets the app crashes and it shows an out of bounds error:
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
But i'm not sure why it is out of bounds when I have set a counter and it gets the text then increments the counter.
What I want to do is when the user writes a note on the Edit text and clicks a button this sets the text in a textview, then the user can add another note and this will go under the previous textview and so on. But tried various things and it's not working:
In my Tab I have this:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.tab3, container, false);
final EditText notes = (EditText) v.findViewById(R.id.editText);
listView=(ListView)v.findViewById(R.id.list);
int[] cross = new int[]{R.drawable.cross};
notesofrules = new ArrayList<String>();
adapter = new CustomListAdapter(this.getActivity(), notesofrules, cross);
listView=(ListView) v.findViewById(R.id.list);
Button button = (Button)v.findViewById(R.id.button3);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
notesofrules.add(counter, notes.getText().toString());
listView.setAdapter(adapter);
counter++;
notes.setText("");
}
});
return v;
}
}
CustomListAdapter:
public class CustomListAdapter extends ArrayAdapter<String> {
private final Activity context;
ArrayList<String> notes = new ArrayList<String>();
int[]imageCross;
public CustomListAdapter(Activity context, ArrayList<String> notes, int[] imageCross) {
super(context, R.layout.item,notes);
// TODO Auto-generated constructor stub
this.context=context;
this.notes = notes;
this.imageCross = imageCross;
}
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater=context.getLayoutInflater();
View rowView=inflater.inflate(R.layout.item, null,false);
TextView ruleNotesSet = (TextView) rowView.findViewById(R.id.textView1);
ImageView image = (ImageView) rowView.findViewById(R.id.icon);
image.setImageResource(imageCross[position]);
ruleNotesSet.setText(notes.get(position));
return rowView;
}
}
It looks like the issue is that you are using the adapter of a listview incorrectly.
You only need one instance of a listview adapter attached to a listview and it is simply the data contained in the listview adapter (e.g. List notes and int[] imageCross) that need to be updated. The adapter populates the amount of cells and their content based on the data of the list view adapter.
In your case when you try to add a second listcell the getView of the adapter attempts to populate cells and grabs data from positon = 0 and position = 1. But since only 1 element was passed into the adapter, it causes the out of bound error for position 1.
Updating data - add a method to access and modify your data in the adapter. Once you have added/removed the data you want, make sure to call adapter.notifyDataSetChanged() to refresh the cells in the listview.
Tab:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.tab3, container, false);
final EditText notes = (EditText) v.findViewById(R.id.editText);
listView=(ListView)v.findViewById(R.id.list);
int cross = R.drawable.cross;
notesofrules = new ArrayList<String>(); //initial data list
adapter = new CustomListAdapter(this.getActivity(), notesofrules, cross);
listView=(ListView) v.findViewById(R.id.list);
listView.setAdapter(adapter); //set the adapter once, only manipulate the data within
Button button = (Button)v.findViewById(R.id.button3);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
String newNote = notes.getText().toString();
adapter.addNote(newNote); //add new note to the adapter list
adapter.notifyDataSetChanged(); //very important to notify adapter and refresh the listview
notes.setText("");
}
});
return v;
}
}
Adapter:
public class CustomListAdapter extends ArrayAdapter<String> {
private final Activity context;
ArrayList<String> notes = new ArrayList<>();
int imageCross; //make this a list if you have multiple images and add similar to notes list
public CustomListAdapter(Activity context, ArrayList<String> notes, int imageCross) {
super(context, R.layout.item,notes);
// TODO Auto-generated constructor stub
this.context=context;
this.notes = notes;
this.imageCross = imageCross;
}
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater=context.getLayoutInflater();
View rowView=inflater.inflate(R.layout.item, null,false);
TextView ruleNotesSet = rowView.findViewById(R.id.textView1);
ImageView image = rowView.findViewById(R.id.icon);
image.setImageResource(imageCross);
ruleNotesSet.setText(notes.get(position));
return rowView;
}
public void addNote(String data) {
notes.add(data);
}
}
I am trying to create an onDisimiss listener to my app as for now this is what i have
The activity
public class listview_test extends Activity {
ListView list;
String[] web = {
"Google Plus",
"Twitter",
"Windows",
} ;
Integer[] imageId = {
R.drawable.ic_launcher,
R.drawable.icon,
R.drawable.ic_launcher,
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_test);
final CustomList adapter = new
CustomList(listview_test.this, web, imageId);
list=(ListView)findViewById(R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(listview_test.this, "You Clicked at " +web[+ position], Toast.LENGTH_SHORT).show();
}
});
SwipeDismissListViewTouchListener touchListener =
new SwipeDismissListViewTouchListener(
list,
new SwipeDismissListViewTouchListener.DismissCallbacks() {
#Override
public boolean canDismiss(int position) {
return true;
}
#Override
public void onDismiss(ListView listView, int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
adapter.remove(adapter.getItem(position));
}
adapter.notifyDataSetChanged();
}
}
);
list.setOnTouchListener(touchListener);
// Setting this scroll listener is required to ensure that during ListView scrolling,
// we don't look for swipes.
list.setOnScrollListener(touchListener.makeScrollListener());
}
}
And the custom adapter
public class CustomList extends ArrayAdapter<String>{
private final Activity context;
private final String[] web;
private final Integer[] imageId;
public CustomList(Activity context,
String[] web, Integer[] imageId) {
super(context, R.layout.weather_item, web);
this.context = context;
this.web = web;
this.imageId = imageId;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.weather_item, null, true);
TextView txtTitle = (TextView) rowView.findViewById(R.id.city);
ImageView imageView = (ImageView) rowView.findViewById(R.id.info_image);
txtTitle.setText(web[position]);
imageView.setImageResource(imageId[position]);
return rowView;
}
For some reason every time i am swiping an item to dismiss it force closes and gives me this exception
java.lang.UnsupportedOperationException
In this line
adapter.remove(adapter.getItem(position));
java.lang.UnsupportedOperationException
is thrown when you back an Adapter by an array or non-modifiable List. Since you cannot change their size, deleting is impossible.
Instead, modify your Adapter so it accepts a List instead of an array and make sure that the List you pass off is fully flexible.
Something like
List <String> web = new ArrayList <String> ();
web.add ("Google Plus");
web.add ("Twitter");
//etc.
is enough to ensure a flexible list.
This means that your CustomList adapter should also call up to the superclass constructor that also accepts in a List, which in this case is
public ArrayAdapter (Context context, int resource, List<T> objects)
For more information refer to the ArrayAdapter documentation.
What I am trying to do is access an ArrayList that is in my main activity from a customer adapter for a listview.
I have a listview that I am making clickable, which I have done within the customer adapter(where the onclick resides). When the user clicks it they will enter a caption(text) which will update an arraylist(string) in the main activity.
I have read a few other questions about this topic but I'm lost on how to make this work.
I didn't see the need to post a code snippet because it's just a basic arraylist(string) and a custom adapter for a listview. If code is needed I can post though. Thanks!
Here part of the adapter code:
public class PhotoAdapter extends ArrayAdapter<Photo> {
private final ArrayList<Photo> objects;
public PhotoAdapter(Context context, int textViewResourceId,
ArrayList<Photo> objects) {
super(context, textViewResourceId, objects);
this.objects = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final Photo i = objects.get(position);
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.listview_row, null);
v.setClickable(true);
v.setFocusable(true);
}
Here is come code from the main activity
public ArrayList<Photo> m_photos = new ArrayList<Photo>();
public ArrayList<String> m_photo_captions = new ArrayList<String>();
private PhotoAdapter m_adapter;
this.list1 = (ListView) findViewById(R.id.lstPhotos);
m_adapter = new PhotoAdapter(this, R.layout.listview_row, m_photos);
LayoutInflater infalter = getLayoutInflater();
list1.setAdapter(m_adapter);
if (Intent.ACTION_SEND_MULTIPLE.equals(action)
&& intentGallery.hasExtra(Intent.EXTRA_STREAM)) {
ArrayList<Parcelable> list = intentGallery
.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
for (Parcelable p : list) {
Uri uri = (Uri) p;
imagePath = getPath(uri);
m_photos.add(new Photo(imagePath, ""));
m_photo_locations.add(imagePath);
m_photo_captions.add("");
m_adapter.notifyDataSetChanged();
}
}
onclick listener
list1.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
// Do whatever you want with m_photo_captions here
Log.v("listview", "listview item clicked");
appErrorAlert("test", "test");
}
});
You can define the ArrayList you want to access as a global instance variable, that way you can access it from inside your custom adapter.
It'll also be helpful if you provided a code snippet for your problem.
Now that you have posted your code, I would suggest a different approach than Mohamed A. Karim's.
You are trying to set a simple OnClickListener on the entire row in your Adapter but access members of your Activity. Why not just set an OnItemClickListener in your ListView which already has access to the List that you want?
list1.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
// Do whatever you want with m_photo_captions here
}
});
Next remove everything that will intercept the touch event before it reaches your ListView. You can also make your getView() a little smaller and faster, like this:
public class PhotoAdapter extends ArrayAdapter<Photo> {
LayoutInflater mInflater;
public PhotoAdapter(Context context, int textViewResourceId,
ArrayList<Photo> objects) {
super(context, textViewResourceId, objects);
mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final Photo i = get(position);
View v = convertView;
if (v == null) {
v = mInflater.inflate(R.layout.listview_row, null);
// Initialize your ViewHolder here!
}
// Update your TextViews, ImageViews, etc here
...
}
}
Hope that helps!
Hi its my first post here nad my first a little bit more advanced app for my Android phone... I know that this subject was mentioned here, google knows many examples, however they are not exacty what im looking form ;(
I admit I'm a n00000b... in terms of Android coding... I started... ust few days ago, please forgive me :)
The problem is that my listview element is not beeing populated. App compiles and runs without errors, BUT it doesnt lunch getView. From what i have read on the web... I need this to display my beloved listview with its content...
Please help :)
package com.test.stackParser;
public class StackParserActivity extends Activity {
/** Called when the activity is first created. */
private ProgressDialog pd;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//final TextView tv = (TextView) findViewById(R.id.textView1);
//tv.setMovementMethod(new ScrollingMovementMethod());
Button button = (Button)findViewById(R.id.button1);
button.setOnClickListener(myListener);
}
private OnClickListener myListener = new OnClickListener() {
public void onClick(View v) {
pd = ProgressDialog.show(StackParserActivity.this, "Working...", "request to server", true, false);
new ParseSite().execute("http://multikino.pl/pl/repertuar/warszawa-ursynow/2011-09-02/");
}
};
private class ParseSite extends AsyncTask<String, Void, List<String>> {
protected List<String> doInBackground(String... arg) {
List<String> output = new ArrayList<String>();
try
{
HtmlHelper hh = new HtmlHelper(new URL(arg[0]));
List<TagNode> links = hh.getLinksByClass("title");
for (Iterator<TagNode> iterator = links.iterator(); iterator.hasNext();)
{
TagNode divElement = (TagNode) iterator.next();
output.add(divElement.getText().toString());
}
Log.d("dupa", "siteParsed");
}
catch(Exception e)
{
e.printStackTrace();
}
return output;
}
protected void onPostExecute(List<String> output) {
pd.dismiss();
Log.d("dupa", "postExecute");
ListView listview = (ListView) findViewById(R.id.listViewData);
//listview.setAdapter(new ArrayAdapter<String>(StackParserActivity.this, android.R.layout.simple_list_item_1 , output));
MyAdapter dupa = new MyAdapter(StackParserActivity.this, android.R.layout.simple_list_item_1, R.id.movieTitle, output);
dupa.notifyDataSetChanged();
listview.setAdapter(dupa);
dupa.notifyDataSetChanged();
}
}
private class MyAdapter extends ArrayAdapter<string> {
String[] tabObj;
public MyAdapter(Context context, int resource, int textViewResourceId, List<String> output) {
super(context, resource, textViewResourceId);
tabObj = output.toArray(new String[]{});
Log.d("dupa", tabObj[2].toString());
notifyDataSetChanged();
// TODO Auto-generated constructor stub
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Log.d("dupa", "!!!!getView");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.row_layout,parent,false);
TextView tv = (TextView) row.findViewById(R.id.movieTitle);
tv.setText(tabObj[position]);
//Button buton1 = (Button) row.findViewById(R.id.buttonInfo);
//Button button2 = (Button) row.findViewById(R.id.buttonReserve);
return super.getView(position, convertView, parent);
}
};
}
Return row from getView method. Also remove the notifyDatasetChanged() from the MyAdapter constructor.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Log.d("dupa", "!!!!getView");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.row_layout,parent,false);
TextView tv = (TextView) row.findViewById(R.id.movieTitle);
tv.setText(tabObj[position]);
//Button buton1 = (Button) row.findViewById(R.id.buttonInfo);
//Button button2 = (Button) row.findViewById(R.id.buttonReserve);
return row;
}
EDIT :
Try overriding getCount in adapter where you return the size() of tabObj
Since you set the adapter onPostExecute, there is no need to set notifyDataChanged in any of the places that you call it.
The reason that notifyDataChanged is used is to notify the adapter that has been set to a listview that the data have changed and you should update it. Hope this helps!
private class MyAdapter extends ArrayAdapter<string> {
String[] tabObj;
public MyAdapter(Context context, int resource, int textViewResourceId, List<String> output) {
super(context, resource, textViewResourceId);
tabObj = output.toArray(new String[]{});
When we are creating a custom arrayadapter we must be using either
public ArrayAdapter (Context context, int textViewResourceId, T[] objects)
public ArrayAdapter (Context context, int resource, int textViewResourceId, T[] objects)
public ArrayAdapter (Context context, int textViewResourceId, List<T> objects)
public ArrayAdapter (Context context, int resource, int textViewResourceId, List<T> objects)
if we are not using above mention adapter, we need to override getCount() method.
In your case,
super(context, resource, textViewResourceId,output);
will solve your problem.