I am currently developing a fragment which contains lists of albums.
The structure is pretty simple:
Horizontal slider contains LinearLayour (horizontal). In order to add an album with songs list I have created a separate view which consists of cover image and a listview. The listview is custom as well where items are linearlayout with 3 textviews. Then I inflate it, populate list, and add to the Horizontal slider.
The issue occurs if I have more than 2 album lists. It takes some time to open a fragment.
Another thing is when I try to scroll (horizontally), sometimes it stops for a short moment, which makes bad user experience.
What I am trying to say is that I have seen similar views and they work quickly and with no lags. Is it possible somehow to optimize it? Or is it possible so that the fragment opens straight away and then the lists load afterwards (kind of lazyload).
LISTVIEW ITEM:
<?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="wrap_content"
android:orientation="horizontal"
android:background="#ccffffff"
android:padding="10dp" >
<TextView
android:id="#+id/album_list_item_number"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:text=""
android:gravity="center|center_vertical"
android:layout_gravity="center|center_vertical"
android:textColor="#333333"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/album_list_item_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:layout_weight="1"
android:gravity="left|center_vertical"
android:layout_gravity="left|center_vertical"
android:textColor="#333333"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/album_list_item_time"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:text=""
android:gravity="center|center_vertical"
android:layout_gravity="center|center_vertical"
android:textColor="#333333"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
POPULATING THE LIST AND ADDING VIEW TO THE HORIZONTAL SLIDER:
View albumView = inflater.inflate(R.layout.artist_album_col, container, false);
//setting cover
ImageView albumCover = (ImageView) albumView.findViewById(R.id.artistAlbumCover);
albumCover.setImageDrawable(getResources().getDrawable(R.drawable.albumcover)); //cover
ListView albumList = (ListView) albumView.findViewById(R.id.artistSongList);
// create the grid item mapping
String[] from = new String[] {"num", "title", "time"};
int[] to = new int[] { R.id.album_list_item_number, R.id.album_list_item_title, R.id.album_list_item_time};
// prepare the list of all records
List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for(int i = 0; i < 24; i++){
HashMap<String, String> map = new HashMap<String, String>();
map.put("num", "" + i);
map.put("title", "title title title title title title title title title " + i);
map.put("time", "time " + i);
fillMaps.add(map);
}
// fill in the grid_item layout
SimpleAdapter adapter = new SimpleAdapter(mContext, fillMaps, R.layout.album_list_item, from, to);
albumList.setAdapter(adapter);
albumContainer.addView(albumView);
You can use Async Task to perform the time-consuming tasks and take them off the UI thread. This will allow the fragment to load quickly and the list to populate "lazily".
Call with:
new LoadingTask().execute("");
And you can stick a class like this in your fragment class (warning! not tested):
private class LoadingTask extends AsyncTask<Void, Void, Void> {
SimpleAdapter adapter;
protected void doInBackground(Void... values) {
// do your work in background thread
// create the grid item mapping
String[] from = new String[] {"num", "title", "time"};
int[] to = new int[] { R.id.album_list_item_number, R.id.album_list_item_title, R.id.album_list_item_time};
// prepare the list of all records
List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for(int i = 0; i < 24; i++){
HashMap<String, String> map = new HashMap<String, String>();
map.put("num", "" + i);
map.put("title", "title title title title title title title title title " + i);
map.put("time", "time " + i);
fillMaps.add(map);
}
// fill in the grid_item layout
adapter = new SimpleAdapter(mContext, fillMaps, R.layout.album_list_item, from, to);
return;
}
protected void onPostExecute(Void value) {
// back in UI thread after task is done
ListView albumList = (ListView) getActivity().findViewById(R.id.artistSongList);
albumList.setAdapter(adapter);
}
}
Another example here.
Related
I have a horizontal Listview. It works fine. My ArrayList eList will show a ListView going across the screen. That's great. My problem is that eList has multiple rows meaning eList might be planes, cars, and boats, or an infinite number of objects. Currently this Horizontal ListView will show only all the kinds of planes OR cars OR boats in the Database. How do show multiple or an infinite number of hListViews going down the screen vertically based upon how many object types(planes,cars,boats,tacos,people).
IN ACTIVITY
HorizontalListView hListView = (HorizontalListView) findViewById(R.id.hlistview1);
hListView.setAdapter(new ItemAdapter());
ArrayList<HashMap<String, String>> eList = controller.getAllts();
ListAdapter adapter = new SimpleAdapter(Su.this,eList,R.layout.view_m_ts, images, ins);
hListView.setAdapter(adapter);
IN DATABASE
public ArrayList<HashMap<String, String>> getAllts() {
ArrayList<HashMap<String, String>> List3;
List3 = new ArrayList<HashMap<String, String>>();
String selectQuery3 = "SELECT DISTINCT * FROM INV where p2 IS NOT NULL ORDER BY p2 COLLATE NOCASE ASC";
SQLiteDatabase database = this.getWritableDatabase();
Cursor cursor3 = database.rawQuery(selectQuery3, null);
HashMap<String, String> map = new HashMap<String, String>();
if (cursor3.moveToFirst()) {
do {
map.put("iImageL", cursor3.getString(13));
map.put("p2", cursor3.getString(2));
map.put("se2", cursor3.getString(10));
map.put("te", cursor3.getString(17));
List3.add(map);
} while (cursor3.moveToNext());
}
close();
return List3;
}
IN XML
<LinearLayout
android:id="#+id/LinearViewa"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:orientation="vertical" >
<com.devsmart.android.ui.HorizontalListView
android:id="#+id/hlistview1"
android:layout_width="fill_parent"
android:layout_height="10dp"
android:layout_weight=".1"
android:background="#000000" />
</LinearLayout>
I'm going to assume that all objects of different types are in one SQLite table, with the type stored in one of the columns as a string, and you don't have a different table for each type.
Change your getAllts() function to return a HashMap of ArrayLists of HashMaps instead of an ArrayList of HashMaps, so that you can create multiple HorizontalListViews, one for each ArrayList of HashMaps, each one for a particular type. As you iterate through the rows returned in the cursor, get the type and check if there is already an ArrayList for it in your big HashMap, if not then create one and if so then add to the existing one:
public HashMap<String, ArrayList<HashMap<String, String>>> getAllts() {
HashMap<String, ArrayList<HashMap<String, String>>> hashMap = new HashMap<String, ArrayList<HashMap<String, String>>>();
String selectQuery3 = "SELECT DISTINCT * FROM INV where p2 IS NOT NULL ORDER BY p2 COLLATE NOCASE ASC";
SQLiteDatabase database = this.getWritableDatabase();
Cursor cursor3 = database.rawQuery(selectQuery3, null);
int typeColumnIndex = 18; // <- You need to set the correct column here, possibly using cursor3.getColumnIndexOrThrow()
if (cursor3.moveToFirst()) {
do {
// create this HashMap inside the loop because we need a new one each time:
HashMap<String, String> map = new HashMap<String, String>();
ArrayList<HashMap<String, String>> List3;
// get the type of this entry as a string
String typename = cursor3.getString(typeColumnIndex);
// check if there already is an ArrayList for this type:
if(hashMap.containsKey(typename))
{
// get existing ArrayList for this type:
List3 = hashMap.get(typename);
}
else
{
// create new ArrayList for this type:
List3 = new ArrayList<HashMap<String, String>>();
hashMap.put(typename, List3);
}
map.put("iImageL", cursor3.getString(13));
map.put("p2", cursor3.getString(2));
map.put("se2", cursor3.getString(10));
map.put("te", cursor3.getString(17));
List3.add(map);
} while (cursor3.moveToNext());
}
close();
return hashMap;
}
Change your XML so that you have an empty LinearLayout in your activity XML:
<LinearLayout
android:id="#+id/LinearViewa"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:orientation="vertical" >
</LinearLayout>
and create a separate XML for the horizontal list view that you can create multiple times and add to your LinearLayout dynamically, in horiz_listview.xml or something like that. You can set up your own custom layout with the type name as a TextView header etc:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- Add type name here if you like-->
<com.devsmart.android.ui.HorizontalListView
android:id="#+id/hlistview1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#000000" />
</LinearLayout>
Then in your activity, get the massive hash map containing all the ArrayLists and iterate through it creating a HorizontalListView for each one and add it to the LinearLayout:
LinearLayout layout = (LinearLayout)findViewById(R.id.LinearViewa);
HashMap<String, ArrayList<HashMap<String, String>>> eHash = controller.getAllts();
LayoutInflater inflater = getLayoutInflater();
for(Map.Entry<String, ArrayList<HashMap<String, String>>> entry : eHash.entrySet())
{
// get the type name and ArrayList of Hashmaps for this type:
String typename = entry.getKey();
ArrayList<HashMap<String, String>> eList = entry.getValue();
// inflate a horizonal list view and add it to the layout:
View view = inflater.inflate(R.layout.horiz_listview, null, false);
layout.addView(view);
// set up the horizontal list view like before:
HorizontalListView hListView = (HorizontalListView) view.findViewById(R.id.hlistview1);
ListAdapter adapter = new SimpleAdapter(Su.this,eList,R.layout.view_m_ts, images, ins);
hListView.setAdapter(adapter);
}
If you have more HorizontalListViews than you can fit on screen then you might need to wrap your main LinearLayout in a ScrollView, however be warned that you might run into trouble with that, see this question.
In the following code I intend to produce both an ouput on the item line and the subitem line but the code is just bringing me up an empty listview. How can I rectify this?
The game is a multiplication times tables game with the intention that when the user enters answers (on prev activity) the answer they entered are shown in the item (i.e. 12 items) and the correct answer for each is shown in each sub-item.
.Java code:
public class Results extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.results);
ListView itemList = (ListView) findViewById(R.id.lvresults);
//gets array from prev act
int[] results = getIntent().getIntArrayExtra("results");
int numberPassed = getIntent().getIntExtra("numberPassed", 0);
ArrayList < HashMap <String, String> > list = new ArrayList < HashMap <String, String> > ();
// loop to give list view
for (int i = 1; i <= 12; ++i)
{
int userAnswer = results[i - 1];
int expectedAnswer = numberPassed * i;
String userString = numberPassed + "x" + i + "=" + userAnswer;
String expectedString = "" + expectedAnswer;
HashMap <String, String> map = new HashMap <String, String> ();
map.put("user", userString);
map.put("expected", expectedString);
list.add(map);
}
String[] keys = {"user", "expected"};
int[] ids = {R.id.user_answer, R.id.expected_answer};
SimpleAdapter adapter = new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, keys, ids);
itemList.setAdapter(adapter);
}
}
XML code:
<?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" >
<ListView
android:id="#+id/lvresults"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</ListView>
<TextView
android:id="#+id/user_answer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp" />
<TextView
android:id="#+id/expected_answer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp" />
</LinearLayout>
int[] ids={android.R.id.text1,android.R.id.text2}
and remove the two TextView from the layout
In my application i am parsing data from XML.And mapping them into a hashmap and finally setting into an "ArrayList".
Below is my code:
ArrayList<HashMap<String, String>> menuItems = new ArrayList<HashMap<String, String>>();
TaplistingParser parser = new TaplistingParser();
String xml= parser.getXmlFromUrl(URL);
Document doc=parser.getDomElement(xml);
// System.out.println("sssss="+doc);
NodeList nl=doc.getElementsByTagName("article");
final String[] url= new String[nl.getLength()];
for(int i=0; i < nl.getLength(); i++ )
{
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
map.put("Title", parser.getValue(e, "title")); -------->
map.put("Date", parser.getValue(e, "create_date")); -------->Here is the array
url[i]=parser.getValue(e, "url");
// map.put("URL", parser.getValue(e, "url"));
menuItems.add(map);
// System.out.println("items="+menuItems);
}
// System.out.println("items="+menuItems);
ListView l1= (ListView)findViewById(R.id.list);
ListAdapter adapter = new SimpleAdapter(this, menuItems,
R.layout.homelistrow,
new String[] {"Title"}, new int[]
{
R.id.name_label});
l1.setAdapter(adapter);
Now in the above code i have Date and Title.
I have to display the list like this:
2012-11-09
qqqqqqqqqqqqqqqq
------------------
2012-11-09
ddddddddddddddd
-----------------
How can i show the 2 array in 2 textview in a list..I am new to this please help me.Thanks in advance.
You should implement your own Adapter which will extend ArrayAdapter.
Then in it, your getView() method should look like this
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
if (row == null)
{
// ROW INFLATION
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.buddy_list_item, parent, false);
}
// Get item
Buddy buddy = getItem(position);
buddy.refresh();
buddyName = (TextView) row.findViewById(R.id.buddy_name);
buddyName.setText(buddy.toString()); //set the first line somehow
buddyStatus = (TextView) row.findViewById(R.id.buddy_mood);
buddyStatus.setText(buddy.getMood()); //set the second line
return row;
}
Then you need an buddy_list_item.XML file which will containt the two TextViews - buddy_name and buddy_mood. You can use simple_list_2 i think, but I do it this way.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<CheckedTextView
android:id="#+id/buddy_name"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:checkMark="?android:attr/textCheckMark"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:text="#string/buddy_name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/buddy_mood"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/empty_string"
android:layout_marginLeft="-350dp"
android:layout_marginTop="16dp"
android:gravity="center_vertical|bottom"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
Just figure out how to put this to good use now :)
EDIT:
P.S. You know you can give the adapter anything it needs right? so you can even do ths
public YourArrayAdapter(Context context, int textViewResourceId, HashMap yourMap)
{
super(context, textViewResourceId, objects);
this.context = context;
this.buddies = objects;
//do something with the map or delegate demapping to the adapter
}
and then later in getView() you actually do what you need to get the data out of the map instead of getting the data out of the map and making an ArrayAdapter out of that.
I have a file manager that uses a ListView (icon + text) .. and only for the photos(jpg) I want to show the preview instead of a default icon .. like es file explorer or similar...
and i would like to switch form single_selection listview.. to multiple_selection by long pressing a row on listview.. like happens on android messages system app... by highlightes on selected row... no checbox..
my actual scenario:
my ListView uses a RelativeLayout for each row
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60dip"
android:padding="5dip">
<ImageView
android:id="#+id/fd_Icon"
android:layout_width="50dip"
android:layout_height="50dip"
>
</ImageView>
<TextView
android:text="Nome"
android:layout_marginLeft="5dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="#+id/fd_Text"
android:layout_toRightOf="#+id/fd_Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
</RelativeLayout>
I have the class FileDirRow
public class FileDirRow {
private String file_dir_text;
private int file_dir_icon;
public FileDirRow( int file_dir_icon , String file_dir_text ) {
super();
this.file_dir_icon = file_dir_icon;
this.file_dir_text = file_dir_text;
}
public String getFileDirText() {
return file_dir_text;
}
public int getFileDirIcon() {
return file_dir_icon;
}
}
and I fill the listview like this
..........
//arrayItemT contains all files and directories of the current path
ArrayList<FileDirRow> lista_file_dir =new ArrayList<FileDirRow>();
for(int i=0;i<arrayItemT.size();i++){
if (arrayItemT.get(i).endsWith("/"))
lista_file_dir.add(new FileDirRow(R.drawable.folder, arrayItemT.get(i)));
else
-----------------------------------------------------------------------------
//if it's a photo add thumbnails or if it's a generic file...
lista_file_dir.add(new FileDirRow(R.drawable.file, arrayItemT.get(i)));
-----------------------------------------------------------------------------
}
//popolate list
ArrayList<HashMap<String, Object>> data=new ArrayList<HashMap<String,Object>>();
for(int i=0;i<arrayItemT.size();i++){
FileDirRow p= lista_file_dir.get(i);
HashMap<String,Object> rowMap=new HashMap<String, Object>();//create value map
rowMap.put("image", p.getFileDirIcon()); //for image key,image res
rowMap.put("name", p.getFileDirText()); //for name key,l'informazine sul nome
data.add(rowMap); //add value map to data source
}
String[] from={"image","name"}; //from value under this key
int[] to={R.id.fd_Icon,R.id.fd_Text};//to views id
//create adapter
SimpleAdapter adapter=new SimpleAdapter(
getApplicationContext(),
data,//sorgente dati
R.layout.icon_row, //layout
from,
to);
//use adapter
((ListView)findViewById(R.id.FileDirList)).setAdapter
I generated a ListView as seen below
I don't have enough rep to post images, you'll have to decipher my URL: image
The blue rows in the above image are populated using HashMap:
private void showListView(JSONArray rows, JSONArray totals){
final ListView list = (ListView) findViewById(R.id.historylist);
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map;
String[] titles = new String[]{"recordID","date","description","num1","num2"};
SimpleAdapter mSchedule = null;
try{
for(int i=0;i<rows.length();i++){
map = new HashMap<String, String>();
for(int n=0;n<allRows.getJSONArray(i).length();n++){
map.put(titles[n], allRows.getJSONArray(i).getString(n));
}
mylist.add(map);
}
mSchedule = new SimpleAdapter(
History.this,
mylist,
R.layout.history_row,
titles,
new int[] {R.id.textView0, R.id.textView1, R.id.textView2, R.id.textView3, R.id.textView4}
);
list.setAdapter(mSchedule);
}catch(Exception e){
Log.e("Creating ListView", e.toString());
}
}
<LinearLayout >
<LinearLayout >
<LinearLayout >
<TextView (recordID) />
<TextView (date) />
<TextView (num1) />
<TextView (num2) />
</LinearLayout>
<TextView (description) />
</LinearLayout>
<LinearLayout (When this one is clicked) >
<ImageView />
</LinearLayout>
When the green button in the above image is clicked, Id like to get the blue row information.
(date, description, num1, num2)
Also, if you think there's a better way to populate the ListView, please let me know.
You will need to implement your own custom adapter by extending BaseAdapter. In the getView method you'll need to bind to that Button's click event. I suggest having one instance of OnClickListener and using AdapterView#getPositionForView. Once you have the position for the view holding the button that was clicked then you can get to your data. Either via Adapter#getItem or directly from your data source.