I have a process in which a user selects a city, then sees medical practitioners in that state.
I have results that show the name of the medical practice:
#Override
protected void onResume() {
super.onResume();
setProgressBarIndeterminateVisibility(true);
Bundle b = getIntent().getExtras();
final String[] resultArr = b.getStringArray("selectedItems");
String location = b.getString("selectedItems");
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.orderByAscending(ParseConstants.KEY_PRACTICE_NAME);
query.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> users, ParseException e) {
setProgressBarIndeterminateVisibility(false);
if (e == null) {
// Success
//store users variable in Parse to mMidwifeLocations
mMidwives = users;
mCurrentUser = ParseUser.getCurrentUser();
//mMidwifeType = ParseUser.getString("usertype");
//store users in string array, locations
String[] midwives = new String[mMidwives.size()];
String[] locations = new String[mMidwives.size()];
String check;
String location;
int i = 0;
for(ParseUser user : mMidwives) {
//get city value from user, assign it to check variable
location = user.getString("city");
check = user.getString("userType");
if (!Arrays.asList(midwives).contains(check) && type != "patient" && Arrays.asList(resultArr).contains(location) ) {
//in locations array, assign practiename values
midwives[i] = user.getString("practicename");
}
}
i++;
I also want to return in the list the primary contact, address, and practice philosophy..what is the best strategy to do this? I am using a simple_list_item_1 list type...there are other list types...wondering if using one of those might be the answer..thanks in advance..
First of all you probably want to do all of this inside the onCreate() method.
Im not to sure if this is what you want but from what i understand i am writing this.
I would personally write down all the data you want in a string-array in your strings.XML
<string-array name="string_array">
<item name ="item1"> item1 </item>
.......
</string-array>
Then I would just grab that data and sort it in order of what order your states are in. So they would match. But by looking at what you have done you have done that with ease
Then creating a custom layout assign each string to it.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
Change this layout how you would like to see your data, also add more textviews to how many you would need.
Now you would need to create a adapter for this listview.
class adapter extends BaseAdapter {
ArrayList<SingleRow> arrayList;
Context context;
adapter(Context contxt) {
context = contxt;
arrayList = new ArrayList<SingleRow>();
Resources res = contxt.getResources();
String[] items= res.getStringArray(R.array.string_array);
for (int i = 0; i < 1; i++) {//Change the 1 in i < 1 to how big your list is.
arrayList.add(new SingleRow(items[i]));
}
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public Object getItem(int position) {
return arrayList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.items_layout, parent, false);
TextView item1 = (TextView) row.findViewById(R.id.txtItem1);
SingleRow temp = arrayList.get(position);
items.setText(temp.items);
return row;
}
}
class SingleRow {
String items;
SingleRow(String items) {
this.items = items;
}
}
After reading the code and analyzing it you would figure out how to add data to the textviews for each row item, and do so by how many you will need.
Now you will have to set the adapter to the listview by...
ListView listView = (ListView) findViewById(R.id.itemListView);
listView.setAdapter(new adapter(getActivity()));
Now you should be able to make a custom listview layout. If any problems occur please just comment on this answer and ill try to fix it.
Good luck.
Related
I am trying to filter a custom List View with a custom Adapter. I am having problems with duplicating the original Data and putting it back in the list, when the search parameter changes or goes to empty. The filtering does work for the first input character, but if this is changed, it won't search the whole dataset again. I know that this is because I need a duplicate list of the original data but I can't really get it to work, because I don't know how to properly implement it because I am using a custom Class as my Datatype. I only use the name and category property of it though, the names are the actual items and it is also sorted by categories.
I based my Adapter off of this example: https://gist.github.com/fjfish/3024308
And here is my code for the List Adapter:
class DataListAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private List<Object> originalData = null;
private List<Object> filteredData = null;
private static final int CARRIER = 0;
private static final int HEADER = 1;
private LayoutInflater inflater;
private ItemFilter mFilter = new ItemFilter();
DataListAdapter(Context context, List<Object> input) {
this.mContext = context;
this.originalData = input;
this.filteredData = input;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getItemViewType(int position) {
if (originalData.get(position) instanceof Carrier) {
return CARRIER;
} else {
return HEADER;
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getCount() {
return originalData.size();
}
#Override
public Object getItem(int position) {
return originalData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#SuppressLint("InflateParams")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
switch (getItemViewType(position)) {
case CARRIER:
convertView = inflater.inflate(R.layout.listview_item_data_layout, null);
break;
case HEADER:
convertView = inflater.inflate(R.layout.listview_header_data_layout, null);
break;
}
}
switch (getItemViewType(position)) {
case CARRIER:
TextView name = (TextView) convertView.findViewById(R.id.fragment_data_list_view_carrier_name);
name.setText(((Carrier) originalData.get(position)).get_name());
break;
case HEADER:
TextView category = (TextView) convertView.findViewById(R.id.fragment_data_list_view_category);
category.setText((String) originalData.get(position));
break;
}
return convertView;
}
#Override
public Filter getFilter() {
return mFilter;
}
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, null, 1);
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<Object> list = originalData;
int count = list.size();
final List<Object> nlist = new ArrayList<>(count);
String filterableString = "";
for (int i = 0; i < count; i++) {
switch (getItemViewType(i)) {
case CARRIER:
filterableString = ((Carrier)list.get(i)).get_name();
break;
case HEADER:
filterableString = "";
break;
}
if(filterableString.toLowerCase().contains(filterString)) {
nlist.add(dbHelper.getCarriersWithName(filterableString).get(0));
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if(results.count == 0) {
notifyDataSetInvalidated();
} else {
originalData = (List<Object>)results.values;
notifyDataSetChanged();
}
}
}
}
My main activity obviously looks like this, which should be fine. The problem lays in the filtered Data List, which I can't get to work.
List<Object> combinedCategoryCarrierList = dbHelper.getCombinedCategoryCarrierList();
adapter = new DataListAdapter(mContext, combinedCategoryCarrierList);
listView.setAdapter(adapter);
listView.setTextFilterEnabled(true);
searchEditText = (EditText) view.findViewById(R.id.fragment_data_search);
searchEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
adapter.getFilter().filter(searchEditText.getText().toString());
}
});
I would greatly appreciate it if someone can show me an example of how to do that with custom data types and section headers combined. Or even change my code :) I can't really find examples where all of that applies.
Edit: The screen looks like this, so I want to keep the category headers when filtering.
I did not find a solution to my original problem, but I came up with a better approach to the whole situation. I didn't know there was an ExpandableListView available in Android. This is basically a ListView, but the items are divided into Groups and their Childs which are expandable and collapsable, so exactly what I wanted.
Here is how I implemented it with working filters and groups:
So, to start off, here is my main layout file. Please note that I am using Fragments, which is why the code is a bit different in terms of getting the context for example. The functionality of the component stays the same though.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="#+id/fragment_data_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="#string/data_search_hint"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" />
<ExpandableListView
android:id="#+id/fragment_data_expandable_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:groupIndicator="#null" />
</LinearLayout>
You will also need two layout files for your header/group items and for your child items. My header item has a TextView which displays the category name and an ImageView which displays a + or - to show if the category is collapsed or expanded.
Here is my header layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorAccent"
android:descendantFocusability="blocksDescendants" >
<TextView
android:id="#+id/fragment_data_list_view_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:gravity="start"
android:textStyle="bold"
android:textSize="18sp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:textColor="#android:color/primary_text_light"
android:text="#string/placeholder_header_listview"
android:maxLines="1"
android:ellipsize="end" />
<ImageView
android:id="#+id/fragment_data_list_view_category_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:contentDescription="#string/content_description_list_view_header"
android:src="#drawable/ic_remove_black_24dp"
android:tag="maximized"/>
</RelativeLayout>
The property android:descendantFocusability="blocksDescendants" fixed a bug when I tried setting an onItemClickListener. If you have that problem, try using RelativeLayout's for your child layout if you're not already. It fixed it for me, the onClickItemListener did not execute with a LinearLayout.
And here is my layout file for the child items:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:descendantFocusability="blocksDescendants" >
<TextView
android:id="#+id/fragment_data_list_view_carrier_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/placeholder_item_listview"
android:textSize="18sp"
android:textStyle="normal"
android:textColor="#android:color/primary_text_light"
android:maxLines="1"
android:ellipsize="end" />
</RelativeLayout>
The following code is from my fragment class, which handles all the logic for the ExpandableListView:
public class Fragment_Data extends Fragment {
private Context mContext;
private ExpandableListView expandableListView;
private List<String> categories_list;
private HashMap<String, List<Carrier>> carriers_list;
private DataExpandableListAdapter adapter;
private DatabaseHelper dbHelper;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle(R.string.nav_item_data);
}
This first part shows the declaration of needed variables and the necessary method onViewCreated. The Carrier class is a custom object with properties like name, category and so on. The DatabaseHelper is also a custom class which handley my database and gets all the data for me, which is casted into Carrier objects. You can of course use anything you like as data types.
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_data_layout, container, false);
mContext = getContext();
expandableListView = (ExpandableListView) view.findViewById(R.id.fragment_data_expandable_list_view);
dbHelper = new DatabaseHelper(mContext, null, null, 1);
adapter = new DataExpandableListAdapter(mContext, categories_list, carriers_list);
displayList();
expandAllGroups();
EditText searchEditText = (EditText) view.findViewById(R.id.fragment_data_search);
searchEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.filterData(s.toString());
expandAllGroups();
}
#Override
public void afterTextChanged(Editable s) {
}
});
expandableListView.setOnItemLongClickListener(deleteSelectedItem);
expandableListView.setOnChildClickListener(editSelectedItem);
return view;
}
The onCreate method deals with all the important stuff like setting the adapter, inflating the layout and setting onClick events for the items and a onTextChange event for the search field.
private void expandAllGroups() {
for(int i = 0; i < adapter.getGroupCount(); i++) {
expandableListView.expandGroup(i);
}
}
private void displayList() {
prepareListData();
adapter = new DataExpandableListAdapter(mContext, categories_list, carriers_list);
expandableListView.setAdapter(adapter);
expandAllGroups();
}
private void prepareListData() {
categories_list = new ArrayList<>();
carriers_list = new HashMap<>();
categories_list = dbHelper.getCategoryList();
for(int i = 0; i < categories_list.size(); i++) {
List<Carrier> carrierList = dbHelper.getCarriersWithCategory(categories_list.get(i));
carriers_list.put(categories_list.get(i), carrierList);
}
}
With expandAllGroups() you can simply expand all groups, because they are collapsed by default. The displayList() simply sets the Adapter for the ExpandableListView and calls prepareListData(), which fills both the category (group) list and the carrier (child) list. Note that the child List is a hashmap with the key being the category and the value a Carrier List by itself, so the Adapter knows which child items belong to which parent.
Here is the code for the Adapter:
class DataExpandableListAdapter extends BaseExpandableListAdapter {
private Context mContext;
private List<String> list_categories = new ArrayList<>();
private List<String> list_categories_original = new ArrayList<>();
private HashMap<String, List<Carrier>> list_carriers = new HashMap<>();
private HashMap<String, List<Carrier>> list_carriers_original = new HashMap<>();
DataExpandableListAdapter(Context context, List<String> categories, HashMap<String, List<Carrier>> carriers) {
this.mContext = context;
this.list_categories = categories;
this.list_categories_original = categories;
this.list_carriers = carriers;
this.list_carriers_original = carriers;
}
You need to have a copy of both of your original lists, if you want to use filtering. This is used for restoring all data when the search query is empty or again or simply different. The filter deletes all items that do not match from the original list.
#Override
public int getGroupCount() {
return this.list_categories.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return this.list_carriers.get(this.list_categories.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return this.list_categories.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return this.list_carriers.get(this.list_categories.get(groupPosition)).get(childPosition);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
Those methods need to be overwritten when you expand the BaseExpandableListAdapter. You can replace all the return null; statements with something similar like this, depending on your data.
#SuppressLint("InflateParams")
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_header_data_layout, null);
}
TextView lblListHeader = (TextView) convertView.findViewById(R.id.fragment_data_list_view_category);
lblListHeader.setText(headerTitle);
ImageView expandIcon = (ImageView) convertView.findViewById(R.id.fragment_data_list_view_category_icon);
if(isExpanded) {
expandIcon.setImageResource(R.drawable.ic_remove_black_24dp);
} else {
expandIcon.setImageResource(R.drawable.ic_add_black_24dp);
}
return convertView;
}
This overriden method simply inflates the layout for each header/group/category item and sets it text and image depending on the state of the group, if it's collapsed or expanded.
#SuppressLint("InflateParams")
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final String carrierName = ((Carrier)getChild(groupPosition, childPosition)).get_name();
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_item_data_layout, null);
}
TextView txtListChild = (TextView) convertView.findViewById(R.id.fragment_data_list_view_carrier_name);
txtListChild.setText(carrierName);
return convertView;
}
Same thing with the child items.
Now finally to the filtering:
I use this custom method to filter out all items that I need matching the search query. Remember that this method is called each time the text of the EditText changes.
void filterData(String query) {
query = query.toLowerCase();
list_categories = new ArrayList<>();
list_carriers = new HashMap<>();
DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, null, 1);
if(query.trim().isEmpty()) {
list_categories = new ArrayList<>(list_categories_original);
list_carriers = new HashMap<>(list_carriers_original);
notifyDataSetInvalidated();
}
else {
//Filter all data with the given search query. Yes, it's complicated
List<String> new_categories_list = new ArrayList<>();
HashMap<String, List<Carrier>> new_carriers_list = new HashMap<>();
List<String> all_categories_list = dbHelper.getCategoryList();
for(int i = 0; i < all_categories_list.size(); i++) {
List<Carrier> carriersWithCategoryList = dbHelper.getCarriersWithCategory(all_categories_list.get(i));
List<Carrier> matchingCarriersInCategory = new ArrayList<>();
for(Carrier carrierInCategory : carriersWithCategoryList) {
if(carrierInCategory.get_name().toLowerCase().contains(query)) {
matchingCarriersInCategory.add(carrierInCategory);
if(!new_categories_list.contains(all_categories_list.get(i))) {
new_categories_list.add(all_categories_list.get(i));
}
}
}
new_carriers_list.put(all_categories_list.get(i), matchingCarriersInCategory);
}
if(new_categories_list.size() > 0 && new_carriers_list.size() > 0) {
list_categories.clear();
list_categories.addAll(new_categories_list);
list_carriers.clear();
list_carriers.putAll(new_carriers_list);
}
notifyDataSetChanged();
}
}`
This might be very confusing, but it needs to be that complicated in my case because of my data structure. It might be easier in your case.
What this basically does is, that it first checks if the search query is empty. And if it is empty it resets both lists to the "backup" lists which I assigned in the constructor. I then call notifyDataSetInvalidated(); to tell the Adapter that it's content will be refilled. It might work aswell with notifyDataSetChanged();, I didn't test that, but it should since we set the original lists back to their old state.
Now, if the search query is not empty I go through every category and see if that specific category has any items that match the search query. If that is the case, that item is added to a new child list and it's category/parent will also be added to a new parent list, if it's not already in there.
And last but not least, the method checks if both lists are not empty. If they are not empty, the original lists are emptied and the new, filtered data, is put in and the Adapter is notified by calling notifyDataSetChanged();
I hope this will help anyone.
in my android project,
i am getting a list of data in arraylist
ArrayList<Items> item = db.getAllMenu();
but now i want to add this data into listview,
i tried as,
ListView lv=(ListView)findViewById(R.id.list_view_inside_nav);
String[] lv_arr = {};
lv_arr = (String[]) item.toArray();
lv.setAdapter(new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1, lv_arr));
but its giving error.because i am trying to convert arratlist to string..
anyone plz help me, how to convert the arraylist to string[]
here are my some files...
items.java (getter and setter methods)
public class Items {
//private variables
String _name;
// Empty constructor
public Items(){
}
// constructor
public Items(String name){
this._name = name;
}
// getting name
public String getName(){
return this._name;
}
// setting name
public void setName(String name){
this._name = name;
}
}
and i am using this code to get data from database
public ArrayList<Items> getAllMenu() {
ArrayList<Items> passList = new ArrayList<Items>();
// Select All Query
String selectQuery = "SELECT * FROM " + CATEGOTY_TABLE_NAME;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Items menu = new Items();
menu.setName(cursor.getString(0));
// Adding category to list
passList.add(menu);
} while (cursor.moveToNext());
}
// return category list
return passList;
}
Your problem here is that you are trying to convert a List into an Array, this can't be done with a cast but methods exist.
The easiest would be to convert the list into an Array using the methods List.toArray(E[]).
ArrayList<Items> items = db.getAllMenu();
Items[] itemsArray = new Items[items.size()]; //Create the array to the correct size,
itemsArray = items.toArray(itemsArray); //Fill the array with the list data
//you could cast into Item[] directly but this is cleaner
Help to use here : Convert ArrayList<String> to String[] array
The array need to be an array of Items
Then, if you have override the toString methods of your Item class to return the String like you want.
public class Items {
...
#Override
public String toString(){
this.getName() //Just an example ;)
}
...
}
This will work like a charm. The adapter use this method to get the String to print.
EDIT :
After some research, you don't even need to create an array. ArrayAdapter accept an List so you only need to override Items.toString()
https://developer.android.com/reference/android/widget/ArrayAdapter.html
You can see here the need to override the toString
However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.
And here is the constructor to use
ArrayAdapter (Context context,
int resource,
List objects)
So just create your adapter like this :
new ArrayAdapter<Items>(MainActivity.this,
android.R.layout.simple_list_item_1, item);
You have to make arraylist of object to do such thing here is a piece of my code that i use
My ArrayList
private ArrayList<Mediafileinfo> songList = new ArrayList<Mediafileinfo>();
Adding data in the arraylist object.
Mediafileinfo info = new Mediafileinfo();
info.setFile_uri(Uri.parse(audioCursor.getString(audiodata)));
info.setName(audioCursor.getString(audioTitle));
info.setDuration(audioCursor.getLong(audioduration));
info.setAlbum(audioCursor.getString(audioalbum));
info.setAlbum_Art_uri(ContentUris.withAppendedId(albumArtUri, audioCursor.getLong(audioalbumid)));
songList.add(info);
Make a class with getter and setter
public class Mediafileinfo {
private String name,album,artist;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
}
And call in your arraylist adapter like this
Mediafileinfo mediafileinfo = (Mediafileinfo) getItem(position);
TextView textView = (TextView) view.findViewById(R.id.textView);
textView.setText(mediafileinfo.getAlbum());
and rest will be the same
you can set the arraylist in your adapter like this
new CustomAdapter(this,songlist)
Hope this will help you.For more info
Wrong.
Items class cannot convert to a String class.
You need to convert each Items to String object.
Example :
Say your class Item
class Items{
public String itemName;
}
In your code change
String[] lv_arr = new String[items.size()];
for(int i=0;i<items.size();i++){
lv_arr[i]=item.get(i);
}
lv.setAdapter(new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1, lv_arr));
let listobj be a list of object you want toset for your listView and Lv be your listview
use following code:
LV.setAdapter(new ArrayAdapter<>(getContext(),android.R.layout.simple_list_item_1 ,sensors));
update
if you want each item of your LisView represent a specific object you could also populate it with a custom adaptor like this :
first in your java files define new javaclass that extends BaseAdaptor
public class SensorAdaptor extends BaseAdapter{
private final Context context;
private final List<Sensor> sensors;
public SensorAdaptor(Context context , List<Sensor> sensors){
this.context = context;
this.sensors = sensors;
}
#Override
public int getCount() {
return sensors.size();
}
#Override
public Object getItem(int position) {
return sensors.get(position);
}
#Override
public long getItemId(int position) {
return sensors.get(position).getType();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_sensors, null);
} else {
view = convertView;
}
TextView listName = view.findViewById(R.id.txtSensorList);
listName.setText(sensors.get(position).getName());
return view;
}
}
attention in my case i want each item of listView represent a Sensor object
then in layout file in res/layout define a layout for this adaptor to use
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/**txtSensorList**"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
and then in yor activity
List<Sensor> sensors = mgr.getSensorList(Sensor.TYPE_ALL);
LV.setAdapter(new SensorAdaptor(getContext(),sensors));
attention
in my case i want to show a list of sensor Object
I have 2 tables, Logs and Price. Content from table logs is displayed into textviews for each item. Now I would like to display some content form table Price into the same base adapter.
Is it possible and how should I done that?
This is my activity with base adapter in which i displayed content form table logs. How should I display here content form table Price?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.display_logs_listview);
boolean sort = getIntent().getBooleanExtra("sort", false);
mainListView = (ListView) findViewById(R.id.ListViewItem);
final String place = (String) getIntent().getExtras().get("keyPlace");
dbHandler = new LogsDBHandler(this);
ArrayList<Logs> logsList = sort ? dbHandler.getAllLogsByPlace() : dbHandler.getAllLogs(place);
TextView result = (TextView) findViewById(R.id.LogMassResult);
double sum = 0.0;
for( int i=0; i<logsList.size(); i++) {
sum += logsList.get(i).getResult();
}
result.setText(String.format("%.2f", sum));
listAdapter = new LogsArrayAdapter(logsList);
mainListView.setAdapter(listAdapter);
}
private class LogsArrayAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List<Logs> logsList;
private List<Price> priceList;
public LogsArrayAdapter(List<Logs> logsList) {
inflater = LayoutInflater.from(DisplayLogs.this);
this.logsList = logsList;
}
#Override
public int getCount() {
return logsList.size();
}
#Override
public Object getItem(int position) {
return logsList.get(position);
}
#Override
public long getItemId(int position) {
return logsList.get(position).getId();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.activity_display_logs, parent, false);
}
Logs log = logsList.get(position);
((TextView) convertView.findViewById(R.id.textPlace)).setText(log.getPlace());
((TextView) convertView.findViewById(R.id.textNumber)).setText(log.getPlate_number());
((TextView) convertView.findViewById(R.id.textSort)).setText(log.getSort_id());
((TextView) convertView.findViewById(R.id.textGrade)).setText(log.getGrade());
((TextView) convertView.findViewById(R.id.textDiameter)).setText(log.getDiameter());
((TextView) convertView.findViewById(R.id.textLength)).setText(log.getLength());
Log.d("Value", log.getCreatedAt());
try {
Date dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(log.getCreatedAt());
((TextView) convertView.findViewById(R.id.textDate)).setText(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(dt));
} catch (ParseException e) {
e.printStackTrace();
}
Log.d("Masa Trupca", String.format("%.2f", log.getResult()));
String final_result = String.format("%.2f", log.getResult());
((TextView) convertView.findViewById(R.id.textAmount)).setText(final_result);
return convertView;
}
}
and this is my dbQuery for getting price. I created this in my Logs class. Here I'm displaying price based on parameters in string.
public Cursor getPrice() {
Cursor cursor = db.query("Price", new String[]{"price_stump_kn", "price_stump_eur", "road_price_kn", "road_price_eur"}, "sort = ? AND grade = ? AND length = ? BETWEEN diameter_dg = ? AND diameter_gg = ?",
new String[]{getSort_id(), getGrade(), getLength(), getDiameter(), getDiameter()}, null, null, null);
if (cursor.moveToFirst()) {
do {
Price price = new Price();
price.setStumpPrice_kn(cursor.getString(0));
price.setStumpPrice_eur(cursor.getString(1));
price.setRoadPrice_kn(cursor.getString(2));
price.setRoadPrice_eur(cursor.getString(3));
} while (cursor.moveToNext());
}
return cursor;
}
So how should I display content from two tables inside one base adapter (listview)?
It depends on how the records in those two tables are related. Your remark that you included a DB query in the Logs class (which I suppose is a domain class, not a DAO), I suspect that your class structure is somewhat confusing. Therefore, I try to sketch a class structure for each of the two ways of mixing your logs and prices.
Solution A: Each log is connected to a price, and data of both are to be displayed in one item.
class LogDAO extends SQLiteOpenHelper {
...
public Log getLogs(some selection parameters) {
Get logs according to selection parameters, and for each log
call getPrice(selection parameter according to log just found)
log.setPrice(price just found)
...
Now, in your adapter, the items are Logs, and with log.getPrice() you can get the price attributes and are free to mix log and price attributes in your adapter to display them in your view item.
Solution B: There is a mixed list -- some items are logs, others are prices
The key to this is that you can dynamically decide, for each item, which layout to use in your adapter. So the structure will be:
class LogPriceDAO extends SQLiteOpenHelper {
...
public Object getLogsAndPrices(some selection parameters)
Get logs and prices in some sequence, according to your business
logic and the selection parameters (If logs and prices have some
common superclass, use that instead of Object)
...
class LogsAndPricesAdapter extends BaseAdapter {
...
#Override
public View getView (int i, View view, ViewGroup viewGroup) {
...
Object currObject = this.getItem(i); // or common superclass
...
View v;
if (currObject instanceOf Log) {
v = layoutInflater.inflate(R.layout.log_layout, null)
now fill fields of your log layout
...
} else {
if (currObject instanceOf Price) {
v = layoutInflater.inflate(R.layout.price_layout, null)
now fill fields of your price layout
...
return v
The instanceOf operator is considered bad style by some people. So the immaculate way is to define a common superclass for Log and Price that offers an operation public Boolean isLog() from which the caller can decide which type of object it got.
This is a follow on from an earlier question: ImageButton within row of ListView android not working
But after suggestions from SO gurus it has been suggested I post a new question.
The issue is that I have a custom adapter that is not showing any data. I have looked into other questions, but it didn't provide a solution.
In my Main Activity I have a couple of buttons, one of them: ToDo, should create a row that displays data from a SQLite database, and depending on some factors (dates mainly), it shows a type of traffic light that is stored as a drawable.
Part of the Items in this Row is an Image Button that I want the user to be able to click and the image should change. The user should be able also to click on the actual row and a new activity starts.
The issue I have is that NO DATA is being displayed.
So, here is my code:
public class MainActivity extends Activity {
// definitions etc ...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// definitions etc ...
}
public void ToDo(View v){ // the user has clicked in the ToDo button
IgroDatabaseHelper helper = new IgroDatabaseHelper(getBaseContext()); // create instance of SQLIte database
numRows = helper.NumEntries("ToDo"); // Get the number of rows in table
int i = 1;
ArrayList<RowItem> rowItems = new ArrayList<>();
RowItem myItem1;
while (i <= numRows){
// get items from database
// depending on value select different drawable
// put data into List Array of RowItem
myItem1 = new RowItem(TheWhat, R.drawable.teamworka, R.drawable.redtrafficlight, R.drawable.checkbox, TheWhenBy);
rowItems.add(myItem1);
//
i = i+ 1;
}
ListView yourListView = (ListView) findViewById(R.id.list);
CustomListViewAdapter customAdapter = new CustomListViewAdapter(this, R.layout.todo_row, rowItems);
yourListView.setAdapter(customAdapter);
}
The CustomListViewAdapter looks like this:
public class CustomListViewAdapter extends ArrayAdapter<RowItem> {
Context context;
ArrayList<RowItem> _rowItems;
public CustomListViewAdapter(Context context, int resourceId,
ArrayList<RowItem> rowItems) {
super(context, resourceId);
this.context = context;
_rowItems = rowItems;
System.out.println("I am in the custom Adapter class "+ _rowItems);
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
System.out.println("This is the get view");
View row = convertView;
RowItem item = _rowItems.get(position);
// you can now get your string and drawable from the item
// which you can use however you want in your list
String columnName = item.getColumnName();
int drawable = item.getDrawable();
if (row == null) {
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = mInflater.inflate(R.layout.todo_row, parent, false);
}
ImageButton chkDone = (ImageButton) row.findViewById(R.id.chkDone);
chkDone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
View parentRow = (View) v.getParent();
ListView listView = (ListView) parentRow.getParent();
final int position = listView.getPositionForView(parentRow);
System.out.println("I am in position "+ position);
}
});
return row;
}
}
The RowItem Class looks like:
public class RowItem {
private String _heading;
private int _icon;
private int _lights;
private int _chkdone;
private String _date;
public RowItem(String heading, int icon, int lights, int chkDone, String date) {
_heading = heading;
_icon = icon;
_lights = lights;
_chkdone = chkDone;
_date = date;
System.out.println("adding stuff to my rows");
System.out.println("my column Name is " + heading);
System.out.println("My drawable int is "+ icon);
}
public String getColumnName() {
System.out.println("column Names is "+ _heading);
return _heading;
}
public int getDrawable() {
return _icon;
}
public int getLights(){
return _lights;
}
public int getchkDone(){
return _chkdone;
}
public String getDate(){
return _date;
}
}
I am obviously missing something, as I mentioned earlier, no data gets shown. I know that there are 2 row items that get passed to the CustomListViewAdapter. But I also know that the View getView inside the CustomListViewAdapter does not actually get called.
I hope I have put enough information/code, but if you feel I need to explain something further, please say.
Thanking all very much in advance!
I don't see a getCount() method. You should be overriding it like this:
#Override
public int getCount() {
return _rowItems.getCount();
}
Alternatively, calling super(context, resourceId, rowItems); should also fix it.
Your ListView thinks there are no items to display. If you are using your own array, you must override the getCount() method to indicate the number of items you want to display.
I'm new to android, i've spent the last 2 days trying previous examples and online solutions but I just can't seem to get my head around it :(
I'm able to display a list view, parse some json from online and store a book title, book description and book ID and display this data in the listview. I want to be able to put a 'download' button in each row for the ListView, each button will correspond to its book ID on Click() and the action listener will download the book by appending that ID to a url.
e.g www.books.com/download_book1 or /download_book2....
Here is my code. Catalogue.java class
public class Catalogue extends ListActivity {
private JSONObject json;
private ListView lv;
private ArrayList<Integer> alKey = new ArrayList<Integer>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //icicle
setContentView(R.layout.shelflist);
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
....
try{
JSONArray entries = json.getJSONArray("entries");
for(int i=0;i<entries.length();i++){
HashMap<String, String> map = new HashMap<String, String>();
JSONObject e = entries.getJSONObject(i);
alKey.add(e.getInt("key"));
map.put("id", String.valueOf(i));
map.put("title", "Title:" + e.getString("title"));
map.put("description", "Description: " + e.getString("description"));
mylist.add(map);
}
}catch(JSONException e) {
Log.e("log_tag", "Error parsing data "+e.toString());
}
ListAdapter adapter = new SimpleAdapter(this, mylist , R.layout.shelfrow,
new String[] { "title", "description" },
new int[] { R.id.item_title, R.id.item_subtitle });
setListAdapter(adapter);
lv = getListView();
lv.setTextFilterEnabled(true);
.....
This is as far as I get. I don't know how to add 1 button per row in the List and assign an action listener to each button.
I also have a shelfrow.xml file (textView, textView for item_title and item_subtitle) and a shelflist.xml file (ListView).
I have a shelf.xml file with
Basically you need to learn the concept of ListAdapter.
Here's the short story: picture an object that holds the data to be displayed inside a list, along with the way to display each line individually. That's your ListAdapter. Now take each individual line: it's a book with a title and an OnClickListener. It's rendered inside a View with a TextView (for the title) and a Button (for the OnClickListener). All you need to do is give one View to the adapter that will be used for each line, and a List of the books you want to be inside the list.
Here's some sample code. I hope it clears things up a bit
private class MyItemModel{ //that's our book
String title; // the book's title
String description;
long id;
OnClickListener listener = new OnClickListener(){ // the book's action
#Override
public void onClick(View v) {
// the default action for all lines
doSomethingWithTheBookTitleOrUniqueId(this);
}
};
}
private class MyListAdapter extends BaseAdapter{
View renderer;
List<MyItemModel> items;
// call this one and pass it layoutInflater.inflate(R.layout.my_list_item)
public MyListAdapter(View renderer) {
this.renderer = renderer;
}
// whenever you need to set the list of items just use this method.
// call it when you have the data ready and want to display it
public void setModel(List<MyItemModel> items){
this.items = items;
notifyDataSetChanged();
}
#Override
public int getCount() {
return items!=null?items.size():0;
}
#Override
public Object getItem(int position) {
return items!=null?items.get(position):null;
}
#Override
public long getItemId(int position) {
return items!=null?items.get(position).id:-1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
convertView = renderer;
}
MyItemModel item = items.get(position);
// replace those R.ids by the ones inside your custom list_item layout.
TextView label = (TextView)convertView.findViewById(R.id.item_title);
label.setText(item.label);
Button button = (Button)convertView.findViewById(R.id.item_button);
button.setOnClickListener(item.listener);
return convertView;
}
}
In order to pass the List, instead of putting the data inside your list of hashmaps you can do this for instance (be careful, I also updated the MyItemModel and MyListAdapter to your need, added the id and description properties):
List<MyItemModel> myListModel = new ArrayList<MyItemModel>();
try{
JSONArray entries = json.getJSONArray("entries");
for(int i=0;i<entries.length();i++){
MyItemModel item = new MyItemModel();
JSONObject e = entries.getJSONObject(i);
alKey.add(e.getInt("key"));
item.id = i;
item.title = e.getString("title");
item.description = e.getString("description");
// you can change the button action at this point:
// item.onClickListener = new OnClickListener(){...};
myListModel.add(item);
}
}catch(JSONException e) {
Log.e("log_tag", "Error parsing data "+e.toString());
}
ListAdapter adapter = new MyListAdapter(getLayoutInflater().inflate(R.layout.shelfrow, this));
adapter.setModel(myListModel);
setListAdapter(adapter);
lv = getListView();
lv.setTextFilterEnabled(true);
You can create your own class extending ArrayAdapter that will hold your list and set onClickListener to the Button in each row.
But in getView method of your ArrayAdapter you have to create a new view every time.
for example - row layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="110dp"
android:background="#FFF"
android:layout_width="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:background="#FFF"
android:orientation="vertical"
android:padding="2dp"
android:layout_height="110dp">
<TextView android:id="#+id/list_item_title"
android:background="#FFF"
android:layout_width="fill_parent"
android:layout_height="40dp"/>
<Button android:id="#+id/download_button"
android:gravity="center"
android:text="Download"
android:layout_height="35dp"/>
</LinearLayout>
</RelativeLayout>
and getView method in ArrayAdapter
private List<Map<String, String>> jsonMapList;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.list_item, null);
// here you set textview values (title and description)
// TextView title = (TextView) v.findViewById(R.id.list_item_title);
// title.setText('bla');
// and set OnClickListener
Button button = (Button) v.findViewById(R.id.download_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
downloadFile(getUrl(position));
}
});
return v;
}
// method that downloads file
private void downloadFile(String url) {}
// get url from your list by index
private String getUrl(int index) {
return jsonMapList.get(index).get("url");
}
Usage of Map is unnecessary, you could use any object you prefer.
In activity class
CustomAdapter listAdapter = new CustomAdapter(this, android.R.layout.simple_list_item_single_choice, jsonMapList);
setListAdapter(listAdapter);