I'm trying to wrap my head around how to implement a custom arrayadapter to provide items for a list activity and then display that selected item in a new activity.
For example, i'm pulling a list of documents from a RESTful web service and i want to display these in a listactivity. My first call to the API will return JSON of documents with two fields: title, and id. I'd like to populate my listactivity with just the title of the documents in the UI. When i click on the item it, ideally, it will open a normal activity where it will make another API call to return the entire selected document in JSON format and display it into the new activity's UI.
After googling around, i've come up with what i think my needed steps are:
Create a RecordListItem class that will only contain the title and id's of the list items.
Create an arrayadapter of the RecordListItem type.
Attach that arrayadapter to my listactivity.
???
I'm confused on the proper way to pass the id of the selected item to the normal activity so i can make the API call to pull that specific record. Do those steps make sense?
I'm used to web dev so this is a different way of thinking and i'm stuck. Can someone explain the correct steps or possibly point me to a tutorial that displays the selected item in a new activity?
In your ArrayAdapter constructor you pass the array with the title/id
public Docs_Array(Context context, Object[] docs) {
super(context, R.layout.row, docs);
this.context = context;
this.docs = docs;
}
in the getView method you'll set each row's layout and information, the "position" argument is how you will get the document that you want. You can cast the Object[i] instance to another array if you want to have more than just one thing, like title+id.
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.row, parent, false);
TextView textView = (TextView)rowView.findViewById(R.id.row_title);
textView.setText(((String[])docs[position])[0]); // 0 for title.
}
add an onClickListener to each row view, and ((String[])docs[position])[1] will give you the id for the document title that was clicked.
Without seeing any code, it sounds like you are on the right track. I would suggest maybe storing the id's in a HashMap using the title as the key and the id as thevalue. Then, when you select your item you can look up theidusing thetitleand send it to your nextActivity`. That is probably how I would handle it.
As far as tutorials, I would start with the Docs if you haven't already. Then if you have a specific problem I'm sure you can find similar issues people have had on SO and many more on the Google. Hope this helps
Related
My android is very rusty, so this is the best way I can explain this:
A card contains an image, a value, and a URL
I have an array of values, a parallel array of images, and of URLs (values[i] <-> images[i] <-> URLs[i])
Have a GridView that I want to use to display many of these cards
The problem:
I have a class that extends BaseAdapter to create a custom view to display the three elements of the card
Using the getView method of said adapter, I use the "i" expected by getView as a mental index of which card we are talking about.
Unfortunately I realized that i=0 means the currently visible first card, I thought it meant the overall first card. This makes it useless as a system to keep track of the overall position of cards.
So, the visible elements are populated correctly in the view. But, if I scroll down and then back up, some internal elements have been jumbled up. So clicking a card might now lead to the URL of a card that was initialized after it.
What I need help with:
A better way to index or populate each card's content that will be permanent.
I am wildly confident I am doing this in a horrendous way. I'm imagining there must be some way to say that:
When GridView is created -> populate each card's details and fill in GridView.
Current Main Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_list);
gv = (GridView) findViewById(R.id.cardGridView);
gv.setAdapter(new CardView(this, cardURLs, cardNames, cardPrices, cardImages));
}
Current CardView Activity:
public CardView(CardListActivity mainActivity, String[] cardURLs, String[] cardNames, Double[] cardPrices, int[] cardImages){
//...
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public class Holder{
TextView priceTV;
ImageView cardIV;
String cardName;
}
#Override
public View getView(final int i, View convertView, ViewGroup parent) {
//...
View rowView;
rowView = inflater.inflate(R.layout.card_item_view, null);
//HERE IS WHERE I SET THE PRICE AND IMAGE USING i
holder.priceTV.setText("$" + prices[i].toString());
holder.cardIV.setImageResource(images[i]);
//...
return rowView;
}
Turns out the problem was something else.
The actual problem ended up being caused by these Dialogs I would create to verify if the user wanted to open the website.
I was creating them inside getView, all in the same variable, which meant that the last elelemnt to get initialized would be the one used in the dialog.
I fixed this by moving the dialog creation into the onClick for the view.
Firstly, You should wrap your contents into objects so that each CardContent object contains a url, an image and a value, Then pass those into your adapter. That will be much easier on you, you only need to maintain 1 List of CardContent rather than 3 individual lists and hoping the order doesn't get messed up.
Secondly, This sounds like a case for a Recyclerview. You can use a GridLayoutManager with a Recyclerview instead of a GridView so that your views get recycled and you have less overhead. Luckily the code is largely the same.
See https://developer.android.com/training/material/lists-cards.html for pretty much what you want.
I have a ListView where I want each item to have an ID number attached to it (not the same as the position number). I was hoping this could be done by setting a tag to each View item in the ListView using setTag() when these Views are being created.
Right now I'm creating the ListView like this:
final ListView listview = (ListView) findViewById(R.id.listView1);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, names);
listview.setAdapter(adapter);
The names variable in the ArrayAdapter parameters above is an ArrayList, and each string value in this list also has a unique ID that I want to link to this string somehow.
Is there any way I can get access to and modify each of the Views with a tag? One idea was to create my own extended class of ArrayAdapter and override the getView() method, but I don't really understand how it works and how I would go about doing this.
Or is there a better way to link IDs with each string like this than adding tags like I'm trying to do?
Create a ViewBinder and set the tags as the ListView is being populated with whatever you need. You can check all properties of the view to determine what tag goes where, so this should be what you're looking for.
myAdapter.setViewBinder(new MyViewBinder());
public class MyViewBinder implements ViewBinder {
#Override
public boolean setViewValue(View view, Object data, String text){
//Since it iterates through all the views of the item, change accordingly
if(view instanceof TextView){
((TextView)view).setTag("whatever you want");
}
}
}
I just used this exact same answer on another question (albeit slightly different) yesterday.
about getView , it works by using a method of recycling views. i will try to explain it in a simple way.
suppose you have tons of items that can be viewed . you don't want to really create tons of views too , since that would take a lot of memory . google thought of it and provide you the means to update only the views that need to be shown at any specific time.
so , if there is an empty space on the listview , it will be filled with a new view . if the user scrolls , the view that becomes hidden is recycled and given back to you on the getView , to be updated with the data of the one that is shown instead .
for example , if you scroll down , the upper view becomes hidden for the end user , but in fact it becomes the exact same view that is on the bottom .
in order to understand how to make the listview have the best performance and see in practice how and why it works as i've talked about , watch this video:
http://www.youtube.com/watch?v=wDBM6wVEO70
as for tags , i think you want to do something else , since the data itself (usually some sort of collection, like an arrayList) already knows where to update , because you get the position via the getView . if you want a specific view to update , you might be able to do so by using a hashmap that keeps upadting , which its key is the position in the collection , and the value is the associated view . on each time you go to getView , you need to remove the entry that belong to the view (if exists) and assign the new position with the view that you got/created .
Thanks for the answers. thisMayhem's answer would probably have been easier in the end, but on my quest to learn more I ended up making my own adapter according to this tutorial. I pass down the names and the IDs into the adapter and set the names as the text of the TextViews and the IDs as the tags.
I would rather go with the solution discussed in this thread. It is always the easiest to have all related data in same place and in this case you just create a class to hold all the information you will need for every item.
I have seen related answers and I do not know ehich one is the appropriate for me.
I have a listView and each row has a textview. I want given some conditions, each row to get different color.(Imagine that I am getting data from a DB, and given the value I get, i want text set to different color) My code is shown below:
public class TrailsConditionScreen extends ListActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
seeTrails();
}
private void seeTrails() {
String[] help=new String[] {"foo","bar"};
ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,R.layout.row,R.id.text1,help);
setListAdapter(adapter);
}
}
This code so far just prints them on the list.
Now I want when retrieving values from the db, given the value i get set a different color on each row. imagine that my codes retrieves data from a table an I want when reading the first line , given the number set the appropriate color on the first line of the listview. Then go to second lone of the db,set color for the second line of the list and so on.. i have successfully implemented the reading from the db but i do not know how to set color on specific row. In pseudo-code it looks like this.
for i=0 to number of lines in db{
read_data();
if key_value=0 then color_of_line(i)=red;
else color_of_line_i)=green;
}
Any help for this?
You must create a custom adapter to handle this instead of using the ArrayAdapter. Extend the ArrayAdapter and override the getView method. And inside the getView method based on the condition you can change the color of the text on your textView.setTextColor.
To write a custom adapter check the tutorial here (6. Tutorial: Implementing your own adapter). This example doesn't use the holder pattern but you should.
Your best bet is to extend ArrayAdapter and create your own class.
In the getView() method, execute your condition and set the color to be drawn. There are a lot of good tutorials on creating your own adapters. Check, for instance, http://www.ezzylearning.com/tutorial.aspx?tid=1763429&q=customizing-android-listview-items-with-custom-arrayadapter.
Hope it helps!
Inorder to achieve this, you will need to use a custom adapter. Since you mentioned, you are getting the data from a database, I am assuming here that you will have information in a cursor adapter. Hence, a good place to start would be to extend cursor adapter.
Within your new custom adapter, you should override getView() method. The view to be used for each item in list view is specified there. Additionally, you can also set the properties of the view there.
Depending on your business logic, you should set the text color in getView.
A tutorial here:
http://www.ezzylearning.com/tutorial.aspx?tid=1763429&q=customizing-android-listview-items-with-custom-arrayadapter
What I would do is create a CustomAdapter for the list view
public class MyCustomAdapter extends BaseAdapter
and in the funcion
public View getView(int position, View convertView, ViewGroup parent)
you have the position and you can change whatever you want.
If you search google by custom adapter listview you will get some examples
Different Color For different list item ,yes this can be achieved only if items are static only , but for dynamic content it's hard to do ...
Android and Java noob here, although I've dabbled in various languages over the years. This has been driving me bonkers all week.
Trying to write my first app, and it's the clichéd shopping list app, with a ListView made up of CheckedTextView items (as supplied by android.R.layout.simple_list_item_multiple_choice). The ListView is set to CHOICE_MODE_MULTIPLE.
The backend to the ListView is an ArrayList, called shoppingItems, where ShoppingListItem is simply defined as:
public class ShoppingListItem {
public String name;
public Boolean checked;
// The obvious constructors here...
}
and I have an ArrayAdapter with an over-ridden getView() method:
shoppingListAdapter = new ArrayAdapter<ShoppingListItem>
(this,
android.R.layout.simple_list_item_multiple_choice,
android.R.id.text1,
shoppingItems)
{
#Override
public View getView(int position, View convertView, ViewGroup parent) {
CheckedTextView rowView = (CheckedTextView)convertView;
if (rowView==null){
LayoutInflater inflater = getLayoutInflater();
rowView = (CheckedTextView)inflater.inflate(android.R.layout.simple_list_item_multiple_choice, parent, false);
}
rowView.setText(shoppingItems.get(position).name);
rowView.setChecked(shoppingItems.get(position).checked);
return rowView;
}
};
Everything works fine -- adding items, editing items, removing an individual item via its context menu -- except removing all the checked items via a "Remove" button at the bottom of the screen.
I must have tried writing my removeCheckedItems method half a dozen different ways, including various combinations of:
removing checked items using the list adapter (which from all I've read is the way that's supposed to work)
removing checked items directly from the ArrayList, then calling notifyDatasetChanged()
explicitly removing child views from the ListView
iterating over the results of the ListView's getCheckedItemPositions(), rather than the whole list
Here's my most naive attempt:
private void removeCheckedItems(){
ShoppingListItem item;
for (int i=0; i< adapter.getCount(); i++) {
item = shoppingListAdapter.getItem(i);
if (shoppingListView.isItemChecked(i)){
item = shoppingItems.get(i);
shoppingListAdapter.remove(item);
}
}
removeBtn.setEnabled(false);
}
However I do it, though: the checkboxes in the ListView just don't stay in sync with the data in the ShoppingItems ArrayList. Specifically, if I start off with:
Item one [ ]
Item two [ ]
Item three [ ]
in the list, then check Item one:
Item one [x]
Item two [ ]
Item three [ ]
then click my Remove button, which confirms the action via a popup dialog, the first item disappears, but the checkbox in the first row remains checked:
Item two [x]
Item three [ ]
At this point, I know by means of debugging messages etc. that the contents of the ArrayList are correct -- i.e. that it contains two ShoppingListItem items with the correct names, both of whose 'checked' fields are set to false.
I'm sure I'm missing something obvious, but despite reading numerous examples, and even more ListView-related answers on here, I can't see it for the life of me. (Complete code listing for the activity as it currently stands can be found here, if you need to see more.)
You just need to call the fillData() method again from your removeCheckedItems method.
Everytime you make a change to the data, you need to "fill" the data for the list again, refresh the list adapter.
Do a Google Search for 'ListActivity fillData' tutorial, and you get lots of great examples.
Here are a couple good ones:
http://www.vogella.de/articles/AndroidListView/article.html
http://www.vogella.de/articles/AndroidSQLite/article.html
http://thinkandroid.wordpress.com/2010/01/09/simplecursoradapters-and-listviews/
Let me know if you get stuck, I'll be able to help more tomorrow. I've done this a lot, so I can help you work the kinks out of it.
For the record, the only way I ever got this to work in the end was to use my own custom row layout and inflate that in getView(), rather than using android.R.layout.simple_list_item_multiple_choice. Everything worked just the way I'd expected it to all along when I did that, including the ListView updating instantly and correctly whenever I changed the data via the ArrayAdapter, and notifyDatasetChanged() doing likewise when I was changing the data directly.
I want to create a page with X questions (the questions are stored in a database and I read them), headline and buttons at the end.
When the user clicks on one question than the question should transform into a dialog where the user can modify the question, however the other questions above and beneath it should still display the same way.
The way ListActivity is used in the sample notepad application in the android documentation it seems like the class can only display multiple items of the same type.
Is there a straightforward way to go about this problem?
I should tell you that I don't like your solution as an user.
I would prefer to chose from a list and having an edit activity after a click.
That's the default approach I've seen in every android app and it will be also easier for you.
If you still want to do what you explained I would try do this:
Create a ListView
Create a class QuestionOrDialog
Create an Adapter that extends from ArrayAdapter
Override getView doing something like:
QuestionOrDialog aQuestionOrDialog = getItem(position);
if ( aQuestionOrDialog.showDialog() ) {
return mInflater.inflate(R.layout.dialog, parent, false);
} else {
view = mInflater.inflate(R.layout.question, parent, false);
TextView question = (TextView) view.findViewById(R.id.question);
question.setText(aQuestionOrDialog.getQuestion());
}
On the OnClick you will have to do a getItem() and set that it was clicked.
Tell the listView that it's item have changed.
Hope it works.