In my application there is a spinner to provide the users to select units so that the data from that particular unit should be randomly displayed.My spinner looks like this
Unit-1
Unit-2
.
.
.
Unit-25
if user selects unit-2 from the spinner there are 12 words in the unit-2 so that the words from that unit should be displayed in random.
I have created a table and stored in the database the columns are unit,word
i have stored in the following way in the table
unit|word
1 bank
1 stack
1 over
1 flow
. .
. .
. .
2 google
2 facebook
2 gmail
so on upto 25 units there are 12 words per each unit.
Now i should retrieve them and display them randomly
How to write logic for this if user clicks unit-12 that particular units words only should be displayed.please help me to solve this
Thanks in advance
Here is a sample that i use to populate the data from Sqlite to
Spinner, You can customize this to your needs, remove the SQLite
part if you don't need it - instead pass an array
In onActivityCreated call this method
setDataForCity();
FunctionDefinition::
private void setDataForCity() {
DatabaseHandler mHelper;
SQLiteDatabase db = null;
Cursor mCursor = null;
ArrayList<LinkedHashMap<String,String>> listCollection=new ArrayList<LinkedHashMap<String,String>>();
LinkedHashMap<String, String> mapCollection;
try {
mHelper = new DatabaseHandler(getActivity());
db = mHelper.getReadableDatabase();
//QUERY:- select city_id,city_name,no_of_buffets,downloaded from city_mas
mCursor = db.rawQuery("select "
+""+city_mas.COLUMN_CITY_ID+","
+""+city_mas.COLUMN_CITY_NAME+","
+""+city_mas.COLUMN_DOWNLOADED+" "
+"from "
+""+city_mas.TABLE_NAME_CITY_MAS+"", null);
if(mCursor.moveToFirst()){
do{
mapCollection=new LinkedHashMap<String,String>();
mapCollection.put(city_mas.COLUMN_CITY_ID, mCursor.getString(mCursor.getColumnIndexOrThrow(city_mas.COLUMN_CITY_ID)));
mapCollection.put(city_mas.COLUMN_CITY_NAME, mCursor.getString(mCursor.getColumnIndexOrThrow(city_mas.COLUMN_CITY_NAME)));
mapCollection.put(city_mas.COLUMN_DOWNLOADED, mCursor.getString(mCursor.getColumnIndexOrThrow(city_mas.COLUMN_DOWNLOADED)));
listCollection.add(mapCollection);
}while(mCursor.moveToNext());
}
AdpSearchCitySpinner adapter=new AdpSearchCitySpinner(getActivity(),listCollection);
spnSearchByCity.setAdapter(adapter);
} catch (Exception e) {
e.printStackTrace();
}finally{
if(db!=null){
if(db.isOpen()) db.close();
}
if(mCursor!=null){
if(!mCursor.isClosed())mCursor.close();
}
}
}
AdpSearchCitySpinner.java
public class AdpSearchCitySpinner extends BaseAdapter {
Context mContext;
ArrayList<LinkedHashMap<String, String>> city;
public AdpSearchCitySpinner(Context context, ArrayList<LinkedHashMap<String, String>> _listCollection) {
super();
this.mContext = context;
city=_listCollection;
}
#Override
public int getCount() {
return city.size();
}
#Override
public Object getItem(int position) {
return city.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
LinkedHashMap<String, String> mapCollection=city.get(position);
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
View row = inflater.inflate(R.layout.adp_search_city_spinner, parent, false);
TextView city_id = (TextView) row.findViewById(R.id.city_id);
TextView city_name = (TextView) row.findViewById(R.id.city_name);
TextView downloaded_id = (TextView) row.findViewById(R.id.downloaded_id);
city_id.setText(mapCollection.get(city_mas.COLUMN_CITY_ID));
city_name.setText(mapCollection.get(city_mas.COLUMN_CITY_NAME));
downloaded_id.setText(mapCollection.get(city_mas.COLUMN_DOWNLOADED));
return row;
}
}
Hope this helps !
Related
I have created SQL database in my Android project and managed to populate ListView with data that I inserted. Next part of the project is to enable CheckBoxes for every item (from SQL database) in my ListView. I have found a way how to do it with String values, but I am not sure how to do it with values from SQL database.
Is it somehow possible to put SQL values into String ? Or I need to use different data values to populate my ListView ?
I am still nooby with SQL in Android, so every advice would be helpfull.
Here is code:
public class ModelBreakfast {
public String name; //This String need to be filled with SQL datas. If it's possible.
public boolean checked;
public ModelBreakfast(String name, boolean checked){
this.name = name;
this.checked = checked;
}
}
Just need to say that I tried to replace public String name; with my ContractClass
public FoodContract.FoodEntry entry; where I defined all String values for my database rows.
(_ID, NAME, etc). (I only saw that way to solve my problem). So, code is now looking like this:
public ModelBreakfast(FoodContract.FoodEntry entry, boolean checked){
this.entry = entry;
this.checked = checked;
}
Next class is CustomAdapter
public class CustomAdapterBreakfast extends ArrayAdapter<ModelBreakfast> {
private ArrayList<ModelBreakfast> dataSet;
Context mContext;
private static class ViewHolder {
TextView txtName;
CheckBox checkBox;
}
public CustomAdapterBreakfast(ArrayList<ModelBreakfast> data, Context context){
super(context, R.layout.activity_breakfast_checkbox, data);
this.dataSet = data;
this.mContext = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
final View result;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_breakfast_checkbox, parent, false);
viewHolder.txtName = (TextView) convertView.findViewById(R.id.txtName);
viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkBox);
result=convertView;
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
result=convertView;
}
ModelBreakfast item = getItem(position);
viewHolder.txtName.setText(item.name); //Need to replace or modify this part
viewHolder.checkBox.setChecked(item.checked);
return result;
}}
Last part is the MainActivity
public class BreakfastActivity extends AppCompatActivity {
ArrayList<ModelBreakfast> modelBreakfastArrayList;
private CustomAdapterBreakfast customAdapterBreakfast;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_breakfast);
ListView listView = (ListView) findViewById(R.id.listBreakfast);
modelBreakfastArrayList = new ArrayList<>();
modelBreakfastArrayList.add(new ModelBreakfast("This string will show in ListView. So I need to somehow replace that String with SQL datas.", false));
customAdapterBreakfast = new CustomAdapterBreakfast(modelBreakfastArrayList, getApplicationContext());
listView.setAdapter(customAdapterBreakfast);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ModelBreakfast modelBreakfast= modelBreakfastArrayList.get(position);
modelBreakfast.checked = !modelBreakfast.checked;
customAdapterBreakfast.notifyDataSetChanged();
}
});
}}
After I replaced public String name; with my ContractClass public FoodContract.FoodEntry entry; I understand that I can't use
modelBreakfastArrayList.add(new ModelBreakfast("This string will show in ListView", false));. But than what do I need to set, so my ListView with CheckBoxes will displaying my SQL database values ?
Should I use ArrayList instead String? And how?
Again as I said before in the last question. Look at the for loops. So within your SQLDB Activity and in the function that is taking the values out of the database, you need to populate an array list that you will call in the MainActivity.
public ArrayList<String> getAirportRegion(String code)
Cursor cursor = db.rawQuery("SELECT "+ AIRPORT_NAME +
" FROM " + AIRPORT_TABLE + " WHERE " + AIRPORT_CODE + " = " + code, null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
arrayList.add(cursor.getString(cursor.getColumnIndex(AIRPORT_NAME)));
cursor.moveToNext();
}
}
cursor.close();
return arrayList;
}
Now in the Main Activity get a reference to the database and set it to modelBreakfastArrayList like so
airportArrayList = mdb.getAirportRegion();
Voila it is done
Do you see how I am extracting the data? For the most part, this is the best way to extract lists from the local database. Keep these Activities separate, also I hope you have the Database activity as a singleton, otherwise, you will have multiple databases and that will guzzle up resources. Look below for how I start these database activities.
private DBHelper(Context context) {
super(context, "db", null, DATABASE_VERSION);
}
private static DBHelper INSTANCE;
public static DBHelper getInstance(Context context) {
if (INSTANCE == null) {
INSTANCE = new DBHelper(context);
}
return INSTANCE;
}
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 question already has answers here:
Custom Adapter getView() method is not called
(6 answers)
Closed 7 years ago.
I am trying to develop an android application that can display values from multiple tables.
I have used a Base Adapter to display the values since i just need to display the queried values in a list. But when I try to display the values in the list view it is blank.
I am not sure what I have done wrong.
I am Using the below method to query the data from the database to display only the required values.
public Cursor getAssetInStore()
{
SQLiteDatabase db_database = getReadableDatabase();
Cursor c = db_database.rawQuery("SELECT asset_name,warrenty,AssetImage,asset_status FROM `Assets`,`AseetIssued` WHERE Assets.Assetid = AseetIssued.Assetissuedid AND asset_status =?" ,
new String [] {"In Storage"}, null);
return c;
}
The below methods are used to populate the values onto the list view.
private void populateAssetListView()
{
Cursor c = db_database.getAssetInStore();
AssetListView.setAdapter(new AssetListAdapter(this, c));
}
public class AssetListAdapter extends BaseAdapter
{
private Context mContext;
Cursor cursor;
public AssetListAdapter(Context context, Cursor c) {
super();
mContext = context;
cursor =c ;
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//The layout is assigned to the custome created created in this case it is customeassetview the cales will be displayed as per this list
view = inflater.inflate(R.layout.assetsinstore_placeholder, null);
cursor.moveToPosition(position);
TextView Assetsstatus = (TextView) view.findViewById(R.id.Assetssatutsstore_view);
int status = cursor.getInt(cursor.getColumnIndex("asset_status"));
Assetsstatus .setText(String.valueOf(status));
TextView Assetsname = (TextView) view.findViewById(R.id.Assetstore_name_view);
String Assetname = cursor.getString(cursor.getColumnIndex("asset_name"));
Assetsname.setText(Assetname);
TextView Warrenty = (TextView) view.findViewById(R.id.Assetstore_Warrenty_view);
String CustDesignation = cursor.getString(cursor.getColumnIndex("warrenty"));
Warrenty .setText(CustDesignation);
ImageView AssetImage = (ImageView) view.findViewById(R.id.list_image);
byte[] bb = cursor.getBlob(cursor.getColumnIndex("AssetImage"));
AssetImage.setImageBitmap(BitmapConver.getPhoto(bb));
return view;
}
}
Try to use a cursor adapter in place of a base adapter. Moreover, beware that the position you're passing to the cursor may not be what you think.
I want to make a dynamic ListView with numbered items. Here I have retrieved values from SQLite database into the ListView and actually it is numbered according to their id's which are stored in database. But I'm using a dynamic list view, so I want to show numbered items starting from 1 in each time I load the ListView. For example people booking flight tickets for different dates and flight authorities will display a final ListView for the current date including persons who booked for that date.
consider today is 10-12-2014
person A booked ticket for the date 12-12-2014, so his "id" might be "1" in database.
person B booked ticket for the date 13-12-2014,so his "id" might be "2" in database.
person c booked ticket for the date 13-12-2014,so his "id" might be "3" in database.
but when the day "13-12-2014" comes person B's id should be "1"(no need to have any connection with database, just enough a numberd representation to show today's list is this.
like
1.person B
2.person C
thats all.
This is my displayadapter class:
public class DisplayAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<String> id;
private ArrayList<String>name;
private ArrayList<String>phone;
public DisplayAdapter(Context c, ArrayList<String> id,ArrayList<String> name, ArrayList<String> phone) {
this.mContext = c;
this.id = id;
this.name = name;
this.phone = phone;
}
public int getCount() {
// TODO Auto-generated method stub
return id.size();
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
public View getView(int pos, View child, ViewGroup parent) {
Holder mHolder;
LayoutInflater layoutInflater;
if (child == null) {
layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
child = layoutInflater.inflate(R.layout.viewthem, null);
mHolder = new Holder();
mHolder.txt_id = (TextView) child.findViewById(R.id.d);
mHolder.txt_name = (TextView) child.findViewById(R.id.nm);
mHolder.txt_phone = (TextView) child.findViewById(R.id.ph);
child.setTag(mHolder);
} else {
mHolder = (Holder) child.getTag();
}
mHolder.txt_id.setText(id.get(pos));
mHolder.txt_name.setText(name.get(pos));
mHolder.txt_phone.setText(phone.get(pos));
return child;
}
public class Holder {
TextView txt_id;
TextView txt_name;
TextView txt_phone;
}
}
This is my dbhelper class:
mydb = new DBhelper(this);
SQLiteDatabase database = mydb.getWritableDatabase();
Cursor mCursor=database.rawQuery("SELECT * FROM contacts WHERE dt='"+d+"'", null);
userId.clear();
user_name.clear();
user_phone.clear();
if (mCursor.moveToFirst()) {
do {
userId.add(mCursor.getString(mCursor.getColumnIndex(DBhelper.CONTACTS_COLUMN_ID)));
user_name.add(mCursor.getString(mCursor.getColumnIndex(DBhelper.CONTACTS_COLUMN_NAME)));
user_phone.add(mCursor.getString(mCursor.getColumnIndex(DBhelper.CONTACTS_COLUMN_PHONE)));
} while (mCursor.moveToNext());
}
DisplayAdapter disadpt = new DisplayAdapter(token.this,userId, user_name, user_phone);
obj.setAdapter(disadpt);
disadpt.notifyDataSetChanged();
mCursor.close();
If you want the list to simply be numbered (as you said, without regard to the actual IDs in the database) you simply need to use the pos parameter you receive in getView(). And you'd probably want to use pos + 1 so the list will be 1-based (more user friendly).
Assuming mHolder.txtId is the TextView you want to use to display the numbers, as I said in my comment, this should work:
mHolder.txt_id.setText(String.valueOf(pos + 1));
If you get an error when trying this please explain exactly what error.
I have data in an SQLite table in the following format:
id|datetime|col1|col2
1|2013-10-30 23:59:59|aaa|aab
2|2013-10-30 23:59:59|abb|aba
3|2013-10-30 23:59:59|abb|aba
4|2013-10-31 23:59:59|abb|aba
5|2013-10-31 23:59:59|abb|aba
I would like to implement an ExpandableListView so that the data would grouped by datetime and shown like that:
> 2013-10-30 23:59:59 // Group 1
1|aaa|aab
2|abb|aba
3|abb|aba
> 2013-10-31 23:59:59 // Group 2
4|abb|aba
5|abb|aba
I have a custom CursorAdapter that I can easily use to populate ListView, showing date for every single item but I don't know how to "group" the data and populate it on an ExpandableListView - could you please give me any hints?
I have a custom CursorAdapter that I can easily use to populate
ListView, showing date for every single item but I don't know how to
"group" the data and populate it on an ExpandableListView - could you
please give me any hints?
Here is solution that currently i'm using in my projects:
You cannot (shouldn't) use CursorAdapter because it's not suitable for your solution. You need to create and implement own Adapter by extending from BaseExpandableListAdapter
Then since you want to create "your own grouping" you need to change your current application logic:
You need to create collection of objects returned from database (for
demonstrating i will use name Foo)
Solution:
So your Foo object should looks like (due to your requirements, name of variables is only created to explain idea of solution) this:
public class Foo {
private String title;
private List<Data> children;
public void setChildren(List<Data> children) {
this.children = children;
}
}
Where title will be date column from your database and children will be columns for specific (unique) date.
Due to your example:
id|datetime|col1|col2
1|2013-10-30 23:59:59|aaa|aab
2|2013-10-30 23:59:59|abb|aba
3|2013-10-30 23:59:59|abb|aba
4|2013-10-31 23:59:59|abb|aba
5|2013-10-31 23:59:59|abb|aba
One specific date (title property of Object Foo) have more associated rows so this will be simulated with defined collection of children in Foo object.
So now you need in your getAll() method (method that returns data from database usually called similarly like this) of your DAO object (object that comunicates with database, it's only terminology) create Foo objects in this logic.
Since you need to properly initialise collection of children for each unique date, you need to use two select queries. Your first select will return distinct dates - so if you have in database 40 rows with 10 different (unique) dates so your select will contain 10 rows with these unique dates.
OK. Now you have "groups" for your ListView.
Now you need to create for each created "group" its children. So here is comming second select that will select all rows and with correct condition you'll assign for each "group" Foo object own collection of children.
Here is pseudo-code #1:
String query = "select * from YourTable";
Cursor c = db.rawQuery(query, null);
List<Data> childen = new ArrayList<Data>();
if (c != null && c.moveToFirst()) {
for (Foo item: collection) {
// search proper child for current item
do {
// if current row date value equals with current item datetime
if (item.getTitle().equals(c.getString(2))) {
children.add(new Data(column3, column4)); // fetch data from columns
}
} while (c.moveToNext());
// assign created children into current item
item.setChildren(children);
// reset List that will be used for next item
children = null;
children = new ArrayList<Data>();
// reset Cursor and move it to first row again
c.moveToFirst();
}
}
// finally close Cursor and database
So now your collection is "grouped" and now the remaining work is on your implemented ListAdapter - it's not tricky.
All what you need is to properly implement getGroupView() and getChildView() methods.
In "group method" you will inflate and initialise rows with titles from collection of Foo objects. These rows will become groups in ListView.
In "child method" you'll do same things but you won't inflate titles from collection but children of current Foo object from collection. These rows will become childs of one specific group.
Notes:
Due to #1. I simplified source code for demostrating purposes. But "in action" you can change a few things:
Instead of c.getString(2) for getting second column is generally
recommended to use column name so you should use
c.getColumnIndex("columnName") instead.
Is good practise to wrap source-code to try-finally block and in
finnaly block close and release used sources like cursors and
databases.
Instead of "reusing" same collection of children how in example,
you can create public method in Foo class that will add item into
collection directly (snippet of code #2).
Snippet of code #2:
public class Foo {
private String title;
private List<Data> children = new ArrayList<Data>();
public void addChild(Data child) {
this.children.add(child);
}
...
}
Summary:
Hope you understood me (i tried to to explain things in as simple way as possible, unfortunetly personal communication face to face is the best but this solution is not available for us) and also i hope that i helped you to solve your problem.
Your kind of data modeling and representation can be modeled in Java code as a LinkedHashMap<String, List<Data>>, where Data could look like:
public class Data {
private int id;
private String col1;
private String col2;
public Data(int id, String col1, String col2) {
this.id = id;
this.col1 = col1;
this.col2 = col2;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCol1() {
return col1;
}
public void setCol1(String col1) {
this.col1 = col1;
}
public String getCol2() {
return col2;
}
public void setCol2(String col2) {
this.col2 = col2;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(id).append(", ").append(col1).append(", ").append(col2);
return sb.toString();
}
}
Why LinkedHasMap? Because you need to preserve the order in which you insert the data. So your SQLite reading method could look like this:
public LinkedHashMap<String, List<Data>> readData(SQLiteDatabase db) {
LinkedHashMap<String, List<Data>> result = new LinkedHashMap<String, List<Data>>();
Cursor cursor = null;
try {
cursor = db.query("MY_TABLE", new String[] {
"datetime", "id", "col1", "col2"
}, null, null, null, null, "datetime, id ASC");
while (cursor.moveToNext()) {
String dateTime = cursor.getString(cursor.getColumnIndex("datetime"));
int id = cursor.getInt(cursor.getColumnIndex("id"));
String col1 = cursor.getString(cursor.getColumnIndex("col1"));
String col2 = cursor.getString(cursor.getColumnIndex("col2"));
List<Data> list = null;
if (result.containsKey(dateTime)) {
list = result.get(dateTime);
} else {
list = new ArrayList<Data>();
result.put(dateTime, list);
}
list.add(new Data(id, col1, col2));
}
} catch (Exception ex) {
Log.e("TAG", null, ex);
} finally {
if (cursor != null) {
cursor.close();
}
}
return result;
}
A basic adapter would look like this:
public class ExpAdapter extends BaseExpandableListAdapter {
private LinkedHashMap<String, List<Data>> input;
private LayoutInflater inflater;
public ExpAdapter(LayoutInflater inflater, LinkedHashMap<String, List<Data>> input) {
super();
this.input = input;
this.inflater = inflater;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return getChildData(groupPosition, childPosition);
}
private Data getChildData(int groupPosition, int childPosition) {
String key = getKey(groupPosition);
List<Data> list = input.get(key);
return list.get(childPosition);
}
private String getKey(int keyPosition) {
int counter = 0;
Iterator<String> keyIterator = input.keySet().iterator();
while (keyIterator.hasNext()) {
String key = keyIterator.next();
if (counter++ == keyPosition) {
return key;
}
}
// will not be the case ...
return null;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return getChildData(groupPosition, childPosition).getId();
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
TextView simpleTextView = null;
if (convertView == null) {
// inflate what you need, for testing purposes I am using android
// built-in layout
simpleTextView = (TextView) inflater.inflate(android.R.layout.simple_list_item_1,
parent, false);
} else {
simpleTextView = (TextView) convertView;
}
Data data = getChildData(groupPosition, childPosition);
simpleTextView.setText(data.toString());
return simpleTextView;
}
#Override
public int getChildrenCount(int groupPosition) {
String key = getKey(groupPosition);
return input.get(key).size();
}
#Override
public Object getGroup(int groupPosition) {
return getKey(groupPosition);
}
#Override
public int getGroupCount() {
return input.size();
}
#Override
public long getGroupId(int groupPosition) {
return 0;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
TextView simpleTextView = null;
if (convertView == null) {
// inflate what you need, for testing purposes I am using android
// built-in layout
simpleTextView = (TextView) inflater.inflate(android.R.layout.simple_list_item_1,
parent, false);
} else {
simpleTextView = (TextView) convertView;
}
simpleTextView.setText(getKey(groupPosition));
return simpleTextView;
}
#Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
While its simple use in a basic activity would be something like this:
public class MyExpandableActivity extends FragmentActivity {
private ExpandableListView expListView;
#Override
protected void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.expandable_layout);
expListView = (ExpandableListView) findViewById(R.id.exp_listview);
fillList();
}
private void fillList() {
LinkedHashMap<String, List<Data>> input = getMockList(); // get the collection here
ExpAdapter adapter = new ExpAdapter(LayoutInflater.from(this), input);
expListView.setAdapter(adapter);
}
}
Activity's simple layout:
<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/exp_listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Makes sense?