I'm having a trouble for using a 'baseAdapter' to fill a 'fragmentList'.
I'm trying to show a list with all the musics stored in my device using 'MediaStore.Audio.Media', but the problem is when the program calls the function setListAdapter. If the number of items into the baseAdapter is a little large, only a part of the list is correctly filled.
The baseAdapter code:
public class MListAdapter extends BaseAdapter {
public static final Integer KEY_LAYOUT_TITLE = 0;
public static final Integer KEY_LAYOUT_SUBTITLE = 1;
public static final Integer KEY_LAYOUT_OTHERS = 2;
public static final Integer KEY_LAYOUT_IMAGE_ID = 3;
public static final Integer KEY_LAYOUT_LIST = 4;
private ArrayList<String> arrayString;
private LayoutInflater lInflater = null;
private Context context;
public MListAdapter(Context ctx, ArrayList<String> arrString){
context = ctx;
arrayString = arrString;
lInflater = LayoutInflater.from(ctx);
}
public int getCount() {
return arrayString.size();
}
public String getItem(int position) {
return arrayString.get(position);
}
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View mView = convertView;
if (convertView == null) {
mView = lInflater.inflate(R.layout.frag_music_list, null);
TextView mTitle = (TextView) mView.findViewById(R.id.musicNameTextView);
//TextView mSubtitle = (TextView) mView.findViewById(R.id.musicArtistAlbumTextView);
//TextView mOthers = (TextView) mView.findViewById(R.id.musicDurationTextView);
//ImageView mImage = (ImageView) mView.findViewById(R.id.thumbImageView);
mTitle.setText(getItem(position));
Log.d("DEBUG",String.valueOf(position));
Log.d("DEBUG",String.valueOf(getCount()));
//mSubtitle.setText(hashItem.get(KEY_LAYOUT_SUBTITLE));
//mOthers.setText(hashItem.get(KEY_LAYOUT_OTHERS));
}
return mView;
}
The FragmentList:
public class MListFragment extends ListFragment {
MListFragmentListener mCallback;
InterfaceFragmentMusic typeMusicCallback;
// --- Global Variables
static ArrayList<HashMap<Integer, String>> mapString = null;
static ArrayList<HashMap<Integer, Long>> mapImage = null;
// ---The URIs used to get a group of music and its informations
Uri uriMedias = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
/**
* ---The following vectors of strings are used to choose what kind of
* information will be retrieved from the database in each case (the
* columns)
*/
final String[] columnsMedias = {
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.DURATION
};
// The container Activity must implement this interface so the frag can
// deliver messages
public interface MListFragmentListener {
/**
* Called by MListFragment when a list item is selected It has been
* implemented in the FragMusicActivity class!
**/
public void onMusicSelected(String musicName);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The system initially shows the list with all the musics
updateMList(MusicTypeFragment.KEY_POSITION_ALLSONGS);
}
#Override
public void onStart() {
super.onStart();
// When in two-pane layout, set the listview to highlight the selected
// list item
// (We do this during onStart because at the point the listview is
// available.)
//if (getFragmentManager().findFragmentById(R.id.music_fragment) != null) {
// getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
//}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception.
try {
mCallback = (MListFragmentListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement MListFragmentListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Set the item as checked to be highlighted when in two-pane layout
getListView().setItemChecked(position, true);
}
/**
* This fragment will be updated/refreshed whatever the user choose a music
* option on the menu (on the left side)
**/
/* It refreshes/updates the current list with a new type */
public void updateMList(int position) {
Cursor cursor;
MListAdapter mAdapter = null;
ContentResolver cr = getActivity().getContentResolver();
cursor = cr.query(uriMedias, columnsMedias, null, null, null);
ArrayList<String> arrString = new ArrayList<String>();
populateMap(cursor, arrString);
mAdapter = new MListAdapter(getActivity(),arrString);
int a = mAdapter.getCount();
for (int i = 0; i < a; i++) {
Log.d("MLISTFRAG", mAdapter.getItem(i));
}
this.setListAdapter(mAdapter);
cursor.close();
}
/*
* It populates an arrayList with the information about the musics using the
* data passed by a cursor
*/
private void populateMap(Cursor c, ArrayList<HashMap<Integer, String>> array, ArrayList<String> arrString) {
Cursor mCursor = c;
while (mCursor.moveToNext()) {
// creating new HashMap
HashMap<Integer, String> map = new HashMap<Integer, String>();
// Values by default
//map.put(MListAdapter.KEY_LAYOUT_TITLE,
// getString(R.string.inBlank));
//map.put(MListAdapter.KEY_LAYOUT_SUBTITLE,
// getString(R.string.inBlank));
//map.put(MListAdapter.KEY_LAYOUT_OTHERS,
// getString(R.string.inBlank));
// New values
map.put(MListAdapter.KEY_LAYOUT_TITLE,
mCursor.getString(MListAdapter.KEY_LAYOUT_TITLE));
arrString.add(mCursor.getString(MListAdapter.KEY_LAYOUT_TITLE));
array.add(map);
}
mCursor.close();
}
The results of these codes are that it's showed a list partially correct, I mean the first half of the list is okay, but the second half is the repetition of the first part.
I put a Log.d into the getView (in the baseAdapter) to verify if the the size of the array is correct and how many times the setListAdapter calls this method and the results (only to exemplify) are:
--> size = 30
--> how many times the method is called: 16
Thanks for your help!
You do not recycle the view properly.
In the getView method you only affect the TextView when the convertView is null. You need to update the TextView every time. Like this :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View mView = convertView;
if (mView == null) {
mView = lInflater.inflate(R.layout.frag_music_list, null);
}
TextView mTitle = (TextView) mView.findViewById(R.id.musicNameTextView);
mTitle.setText(getItem(position));
return mView;
}
Related
I have a working list view with images from the drawables folder, I have working code which takes an image and uploads it to my server etc, I have the url to fetch the image from the database and I now am stuck in how to add it into my already existing list View by automatically adding a new image from this link into the list view.
This is the 'timeline' list view which displays the pictures we already have
/**
* Method which creates the list view on screen and displays images
*/
public class Timeline extends Activity implements OnItemClickListener {
//global variables
String[] pic_names;
TypedArray profile_pics;
List<RowItem> rowItems;
ListView mylistview;
ImageView btnTakePic;
String[] uploaded_pic_name;
TypedArray pic_url;
//Overridden method to create the main layout
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timeline);
//set the global variables
//rowItems is now an arraylist
rowItems = new ArrayList<RowItem>();
//pic_names is set to the resource of pic_names
pic_names = getResources().getStringArray(R.array.pic_names);
uploaded_pic_name = getResources().getStringArray(R.array.uploaded_pic_name);
pic_url = getResources().obtainTypedArray(R.array.pic_url);
//profile_pics is now set to the resource of profile_pics
profile_pics = getResources().obtainTypedArray(R.array.profile_pics);
//gets the picture and name for each resource in the for loop array
for (int i = 0; i < pic_names.length; i++) {
RowItem item = new RowItem(pic_names[i], profile_pics.getResourceId(i, -1));
//adds items from the array
rowItems.add(item);
}
RowItem uploadedItem = new RowItem(uploaded_pic_name[0], pic_url.getResourceId(0, 0));
rowItems.add(uploadedItem);
//creates a new listview
mylistview = (ListView) findViewById(R.id.list);
CustomAdapter adapter = new CustomAdapter(this, rowItems);
mylistview.setAdapter(adapter);
//onclick listener on this main activity
mylistview.setOnItemClickListener(this);
btnTakePic = (ImageView) findViewById(R.id.btnTakePic);
// on click listener used to give function to the button when clicked.
btnTakePic.setOnClickListener(new View.OnClickListener() {
// onClick method defines what the function is
// Intent used to communicate to start
#Override
public void onClick(View v) {
Intent i = new Intent(Timeline.this, Camera.class);
startActivity(i);
}
});
}
//overridden method to show toast message on the picture
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String pic_name = rowItems.get(position).getPic_name();
Toast.makeText(getApplicationContext(), "" + pic_name,
Toast.LENGTH_SHORT).show();
}
}
This is the custom adapter class I had current for it
/**
* TODO
*/
public class CustomAdapter extends BaseAdapter {
//Instantiates getters for variables
Context context;
List<RowItem> rowItems;
//creates setters for variables
CustomAdapter(Context context, List<RowItem> rowItems) {
this.context = context;
this.rowItems = rowItems;
}
//Overridden method to get the size of the rows
#Override
public int getCount() {
return rowItems.size();
}
//Overridden method to get the item position from rowItems array returning the position
#Override
public Object getItem(int position) {
return rowItems.get(position);
}
//Overridden method to get the Item id return the position
#Override
public long getItemId(int position) {
return rowItems.indexOf(getItem(position));
}
/**
* private view holder class
*
*/
private class ViewHolder {
ImageView profile_pic;
TextView pic_name;
}
// Overriden method to insert image and its associated xml in the listview
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//Instantiating local variables
ViewHolder holder;
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
//If the View is null create the layout
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
//set the textview and image view to required parameters
holder.pic_name = (TextView) convertView.findViewById(R.id.pic_name);
holder.profile_pic = (ImageView) convertView.findViewById(profile_pic);
convertView.setTag(holder);
//create a new viewholder and get the tag from the view
} else {
holder = (ViewHolder) convertView.getTag();
}
//getter for the position of the row
RowItem row_pos = rowItems.get(position);
//sets the position of the row
holder.profile_pic.setImageResource(row_pos.getProfile_pic_id());
holder.pic_name.setText(row_pos.getPic_name());
//return the view
return convertView;
}
}
These are the getters and setter for the images
public class RowItem {
private String pic_name;
private int profile_pic_id;
public RowItem(String pic_name, int profile_pic_id) {
this.pic_name = pic_name;
this.profile_pic_id = profile_pic_id;
}
//getter for the pic name
public String getPic_name() {
return pic_name;
}
//setter for the pic name
public void setPic_name(String pic_name) {
this.pic_name = pic_name;
}
//getter for the profile pic
public int getProfile_pic_id() {
return profile_pic_id;
}
//setter for the profile pic
public void setProfile_pic_id(int profile_pic_id) {
this.profile_pic_id = profile_pic_id;
}
}
Any help is much appreciated
Kindly show the code which you want to implement.
I have working code which takes an image and uploads it to my server
etc, I have the url to fetch the image from the database and i now
and on which event to implement(onClick, onItemClick etc...)
I will edit this later
Do this in, RecyclerView. There implementation is not difficult.. Your mistake is in viewholder... Read Recycler view and there will not any questions.
I would like to ask some question about AdapterView.
In my application, there is an activity which retrieve data from database and display them in AdapterView.
However, when i install the application in different devices, I found that the part I have just mentioned could only function on some devices. The others cannot show the database results.
Here is my code:
private void showResults(String query) {
Cursor cursor = searchCustByInputText(query);
if (cursor == null) {
//
} else {
// Specify the columns we want to display in the result
String[] from = new String[] {
"cust_code",
"chinese_name"};
// Specify the Corresponding layout elements where we want the columns to go
int[] to = new int[] {
R.id.scust_code,
R.id.schinese_name};
// Create a simple cursor adapter for the definitions and apply them to the ListView
SimpleCursorAdapter customers = new SimpleCursorAdapter(this,R.layout.cust_list_item, cursor, from, to);
mListView.setAdapter(customers);
// Define the on-click listener for the list items
mListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Cursor c = (Cursor) mListView.getItemAtPosition(position);
String cust_code = c.getString(c.getColumnIndex("cust_code"));
if (callFromAct.equals("Main")) {
String pay_term = c.getString(c.getColumnIndex("pay_term"));
String chinese_name = c.getString(c.getColumnIndex("chinese_name"));
String english_name = c.getString(c.getColumnIndex("english_name"));
String address_1 = c.getString(c.getColumnIndex("address_1"));
String address_2 = c.getString(c.getColumnIndex("address_2"));
String address_3 = c.getString(c.getColumnIndex("address_3"));
String address_4 = c.getString(c.getColumnIndex("address_4"));
String contact = c.getString(c.getColumnIndex("contact"));
String telephone = c.getString(c.getColumnIndex("telephone"));
String last_order_date = c.getString(c.getColumnIndex("last_order_date"));
//Pass data to another Activity
Intent it = new Intent(CustEnqActivity.this, CustEnqDetailsActivity.class);
Bundle bundle = new Bundle();
bundle.putString("cust_code", cust_code);
bundle.putString("pay_term", pay_term);
bundle.putString("chinese_name", chinese_name);
bundle.putString("english_name", english_name);
bundle.putString("address_1", address_1);
bundle.putString("address_2", address_2);
bundle.putString("address_3", address_3);
bundle.putString("address_4", address_4);
bundle.putString("contact", contact);
bundle.putString("telephone", telephone);
bundle.putString("last_order_date", last_order_date);
it.putExtras(bundle);
startActivity(it);
}
else {
returnToCallingAct(cust_code);
}
//searchView.setQuery("",true);
}
});
}
}
Besides, I discovered there were two warnings in my logcat.
The constructor SimpleCursorAdapter(Context, int, Cursor, String[], int[]) is deprecated
AdapterView is a raw type. References to generic type AdapterView should be parameterized
Are they related to the problem?
Try to create a class that extends BaseAdapter and use ViewHolders for performance
eg:
public class MyBaseAdapter extends BaseAdapter {
ArrayList<ListData> myList = new ArrayList<ListData>();
LayoutInflater inflater;
Context context;
public MyBaseAdapter(Context context, ArrayList<ListData> myList) {
this.myList = myList;
this.context = context;
inflater = LayoutInflater.from(this.context); // only context can also be used
}
#Override
public int getCount() {
return myList.size();
}
#Override
public ListData getItem(int position) {
return myList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder mViewHolder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.layout_list_item, null);
mViewHolder = new MyViewHolder();
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
mViewHolder.tvTitle = detail(convertView, R.id.tvTitle, myList.get(position).getTitle());
mViewHolder.tvDesc = detail(convertView, R.id.tvDesc, myList.get(position).getDescription());
mViewHolder.ivIcon = detail(convertView, R.id.ivIcon, myList.get(position).getImgResId());
return convertView;
}
// or you can try better way
private TextView detail(View v, int resId, String text) {
TextView tv = (TextView) v.findViewById(resId);
tv.setText(text);
return tv;
}
private ImageView detail(View v, int resId, int icon) {
ImageView iv = (ImageView) v.findViewById(resId);
iv.setImageResource(icon); //
return iv;
}
private class MyViewHolder {
TextView tvTitle, tvDesc;
ImageView ivIcon;
}
}
More info/example:
http://www.pcsalt.com/android/listview-using-baseadapter-android/#sthash.lNGSCiyB.dpbs
Ok so I'm at my wit's end with this.
I've encapsulated the list data update functionality inside a function called 'refreshData' inside the adapter. I then call this function on the adapter inside of onActivityResult (the activity that was started for result sets a completion flag onStop. This completion flag is supposed to determine which styles (colors and text) are applied to a particular list item in the list view. Essentially, user selects "1" and goes to new activity, closes that activity, and "1" get's set to done onStop. Returning to the list activity, the listview should make available "2" while setting "1" to complete (visual cues).
The problem I'm having is, that the update only happens the SECOND time the user clicks the list item to go to the new activity and close to return. Without fail, the listview will update the SECOND time only. I have no clue why this is happening. Any help is appreciated.
Thanks.
public class SceneAdapter extends ArrayAdapter {
Context context;
int layoutResourceId;
ArrayList<SceneItem> data;
Typeface font;
UserDatabaseHelper uDatabase;
int chapter_number;
public SceneAdapter(Context context, int layoutResourceId, int chapter, String FONT) {
super(context, layoutResourceId);
this.context = context;
this.layoutResourceId = layoutResourceId;
this.chapter_number = chapter;
this.data = getData(chapter);
this.font = Typeface.createFromAsset(context.getAssets(), FONT);
}
public int getCount() {
return data.size();
}
#Override
public int getViewTypeCount() {
int typeCount = 2;
return typeCount;
}
private ArrayList<SceneItem> getData(int chapter) {
// bucket to return data
ArrayList<SceneItem> container = new ArrayList<SceneItem>();
// titles (need to replace with master database call eventually)
String[] scenesListJapanese = getSceneTitlesInJapanese(chapter);
String[] scenesListEnglish = getSceneTitlesInEnglish(chapter);
// ready database for data retrieval
initializeUserDatabaseForUse();
// query for data
Cursor query = uDatabase.getAllScenesForChapter(chapter + 1);
// testing line, take out when done
Log.v("query length: ", ""+ query.getCount());
// fill data
for (int i = 0; i < scenesListJapanese.length; i++) {
SceneItem item = new SceneItem(""+(i+1), scenesListEnglish[i], scenesListJapanese[i],
query.getInt(4), query.getInt(3));
container.add(item);
Log.v("status for chapter " + (chapter + 1) + ": ", "available: " + query.getInt(4)
+ ", completed: " + query.getInt(3));
query.moveToNext();
}
// close db connection
query.close();
return container;
}
public void refreshData() {
data.clear();
this.data = getData(chapter_number);
Log.v("refresh data called: ", "NOW!");
}
public boolean areAllItemsEnabled() {
return false;
}
public boolean isEnabled(int position) {
if(data.get(position).available == 1 || position == 0) {
return true;
} else {
return false;
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
SceneHolder holder = null;
if (row == null) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new SceneHolder();
holder.chapterNumber = (TextView)row.findViewById(R.id.scene_number);
holder.englishTitleBox = (TextView)row.findViewById(R.id.scene_title_english);
holder.japaneseTitleBox = (TextView)row.findViewById(R.id.scene_title_japanese);
holder.englishTitleBox.setTypeface(font);
holder.japaneseTitleBox.setTypeface(font);
row.setTag(holder);
} else {
holder = (SceneHolder)row.getTag();
}
Resources res = context.getResources();
if(isEnabled(position)) {
holder.englishTitleBox.setTextColor(res.getColor(R.color.gray_subtext));
holder.chapterNumber.setBackgroundResource(R.drawable.number_gray);
holder.japaneseTitleBox.setTextColor(res.getColor(R.color.gray_text));
holder.chapterNumber.setTextColor(res.getColor(R.color.white_text));
row.setBackgroundColor(res.getColor(R.color.transparent));
} else {
holder.englishTitleBox.setTextColor(res.getColor(R.color.standard_gray));
holder.chapterNumber.setBackgroundResource(R.drawable.number_transparent);
holder.japaneseTitleBox.setTextColor(res.getColor(R.color.standard_gray));
holder.chapterNumber.setTextColor(res.getColor(R.color.standard_gray));
row.setBackgroundColor(res.getColor(R.color.action_gray_end));
}
SceneItem item = data.get(position);
holder.chapterNumber.setText(item.scene);
holder.englishTitleBox.setText(item.titleEnglish);
holder.japaneseTitleBox.setText(item.titleJapanese);
return row;
}
static class SceneHolder
{
TextView englishTitleBox;
TextView japaneseTitleBox;
TextView chapterNumber;
}
// Get english scene titles based on chapter number
private String[] getSceneTitlesInEnglish(int position) {
// generate and return list
}
// Get japanese scene titles based on chapter number
private String[] getSceneTitlesInJapanese(int position) {
// generate and return list
}
public void initializeUserDatabaseForUse() {
// init database
}
}
Code for calling activity:
public class SceneSelectActivity extends Activity {
ListView mListView; // list view to display scene data
int chapterNumber; // chapter number to use for displaying scenes
Intent passedIntent; // passed intent containing data on which chapter was selected
UserDatabaseHelper uDatabase; // user database reference
SceneAdapter sceneAdapter; // adapter reference
static final int REQUEST_CODE = 1; // request code for activity result
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scene_select);
// Setup necessary variables and views for this activity
initializeUserDatabaseForUse();
handleSetup();
Button backButton = (Button)findViewById(R.id.scene_back_button);
backButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode,resultCode, data);
sceneAdapter.refreshData();
sceneAdapter.notifyDataSetChanged();
}
#Override
public void onResume() {
super.onResume();
}
// Handle set up of activity views and variables
private void handleSetup() {
// passed intent holding data on which chapter was selected
passedIntent = getIntent();
// chapter number to be used in deciding what data/views to set up
chapterNumber = getChapterNumber(passedIntent);
// setup list data, and views
setDataForThisScene(chapterNumber);
setMainImage(chapterNumber);
}
// Obtain chapter number from passed intent
private int getChapterNumber(Intent i) {
// ensure the data is a valid number for a chapter
return i.getIntExtra("chapter_number", 0);
}
// Set up data to be used for list view
private void setDataForThisScene(int position) {
// set chapter splash content
Resources res = getResources();
TextView splashJ = (TextView)findViewById(R.id.scene_splash_title_j);
TextView splashE = (TextView)findViewById(R.id.scene_splash_title_e);
final String title_english[] = res.getStringArray(R.array.chapters_english);
final String title_japanese[] = res.getStringArray(R.array.chapters_japanese);
splashJ.setText(title_japanese[chapterNumber]);
splashE.setText(title_english[chapterNumber]);
TextView completionView = (TextView) findViewById(R.id.scene_progress);
completionView.setText(getCompletionStatus(chapterNumber + 1));
// setup scene list
mListView = (ListView) findViewById(R.id.scene_list);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent i = new Intent(SceneSelectActivity.this, DialogueActivity.class);
i.putExtra("chapter_number", chapterNumber);
i.putExtra("scene_number", position);
startActivityForResult(i, REQUEST_CODE);
//startActivity(i);
// LIST ON CLICK ITEM EVENTS
}
});
//SceneAdapter sceneAdapter = new SceneAdapter(this, R.layout.scene_list_item, sceneData, "custom_font_regular.otf");
sceneAdapter = new SceneAdapter(this, R.layout.scene_list_item, chapterNumber, "custom_font_regular.otf");
mListView.setAdapter(sceneAdapter);
}
private String getCompletionStatus(int chapter) {
Cursor query = uDatabase.getAllScenesForChapter(chapter);
int completed = 0;
for(int i = 0; i < query.getCount(); i++) {
if(query.getInt(3) != 0) {
completed += 1;
}
query.moveToNext();
}
query.close();
return completed * 100 / query.getCount() + "%";
}
// fill in image for chapter bg
private void setMainImage(int chapterNumber) {
// generate image
}
// initialize database
public void initializeUserDatabaseForUse() {
// init database
}
}
The LOG.v inside the 'refreshData' function DOES get called each time the detail activity is closed and the user returns to this list view activity. Although it gets called every time, the list only updates the SECOND time the user repeats the action.
I have done the notepad tutorial from android webside. I added an own Module-Class. Now I also want to add a own baseadapter. But I have problems with the implementation.
My problem is the fillData() method. It is in the third code part. I am also not sure, if I will need a cursor?
I hope anybody can help me, to correct the fillData() method.
My Module-Class
public class Module {
private String title;
private String device_type;
private String home_code;
private String device_code;
public Module(String n, String m, String hc, String mc) {
title = n;
device_type = m;
home_code = hc;
device_code = mc;
}
public String getTitle() { return title; }
public String getDeviceType() { return device_type; }
public String getHomeCode() { return home_code; }
public String getDeviceCode() { return device_code; }
}
My Module Adapter:
public class ModuleAdapter extends BaseAdapter implements OnClickListener {
private Context context;
private List<Module> listModule;
public ModuleAdapter(Context context, List<Module> listModule) {
this.context = context;
this.listModule = listModule;
}
public int getCount() {
return listModule.size();
}
public Object getItem(int position) {
return listModule.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup viewGroup) {
Module entry = listModule.get(position);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.notes_row, null);
}
TextView tvTitle = (TextView) convertView.findViewById(R.id.text1);
tvTitle.setText(entry.getTitle());
TextView tvDeviceType = (TextView) convertView.findViewById(R.id.text2);
tvDeviceType.setText(entry.getDeviceType());
TextView tvHomeCode = (TextView) convertView.findViewById(R.id.text3);
tvHomeCode.setText(entry.getHomeCode());
TextView tvDeviceCode = (TextView) convertView.findViewById(R.id.text4);
tvDeviceCode.setText(entry.getDeviceCode());
return convertView;
}
#Override
public void onClick(View view) {
Module entry = (Module) view.getTag();
listModule.remove(entry);
// listModule.remove(view.getId());
notifyDataSetChanged();
}
private void showDialog(Module entry) {
// Create and show your dialog
// Depending on the Dialogs button clicks delete it or do nothing
}
}
The fillData() method from the main code:
private void fillData() {
//Cursor notesCursor = mDbHelper.fetchAllNotes();
//startManagingCursor(notesCursor);
final List<Module> from = new ArrayList<Module>();
from.add(new Module(NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_DEVICETYPE, NotesDbAdapter.KEY_HOMECODE, NotesDbAdapter.KEY_DEVICECODE));
// Now create a simple cursor adapter and set it to display
//SimpleCursorAdapter notes =
// new SimpleCursorAdapter(this, R.layout.notes_row, notesCursor, from, to);
//notes.setViewBinder(new ModuleViewBinder());
ModuleAdapter adapter = new ModuleAdapter(this, from);
setListAdapter(adapter);
}
Thanks a lot!
Felix
The problem is your data is in a database, so you should keep using the SimpleCursorAdapter as you were doing in the code you commented out.
Your new code puts a module filled in with the names of the database columns (and not the actual data) in the ArrayList:
from.add(new Module(NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_DEVICETYPE, NotesDbAdapter.KEY_HOMECODE, NotesDbAdapter.KEY_DEVICECODE));
Then your custom adapter works correctly, because it displays those values.
What probably got you confused is that you were passing the same strings to the SimpleCursorAdapter, but that adapter uses the column names to fetch data from the database. Your custom adapter instead simply shows what's in the list.
If you want to show the values from the database you should stick to SimpleCursorAdapter (or extend it if you need to do more).
I've got a ListActivity filled by an adapter extending SimpleCursorAdapter. Some category buttons can be clicked, which fills the listview with a list of articles in the corresponding category. When clicking on an item in the list a new activity is launched which shows the detail of the article.
Now, when pressing the back button in that article detail page, no data is shown. Does it have to reload the data from the DB? Isn't the data supposed to be cached?
Moreover, when going back to the myListActivity, onCreate is not called. Only onResume is called. Shall I do everything in onResume? In that case what's the best way to keep the value of the current category and retrieve it when going back to the ListActivity from the article detail?
Thanks
public class Home extends ListActivity implements OnItemClickListener{
private DBAdapter dbAdapter;
private HomeListAdapter adapter; //extends SimpleCursorAdapter
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
// open database
dbAdapter = new DBAdapter(this);
dbAdapter.open();
/* more stuff */
getArticlesbyCat(category);
/* more stuff */
}
private void getArticles(int category){
Cursor c = dbAdapter.fetchArtByCat(category);
c.moveToFirst();
startManagingCursor(c);
String[] from = new String[] {};
int[] to = new int[] {};
setListAdapter(new HomeListAdapter(this, R.layout.article_row, c, from, to));
adapter.notifyDataSetChanged();
c.close();
}
#Override
public void onItemClick(AdapterView arg0, View v, int position, long arg3) {
/* Go to article page */
}
#Override
protected void onPause() {
super.onPause();
// close database
dbAdapter.close();
}
}
EDIT
public class HomeListAdapter extends SimpleCursorAdapter {
private int mLayout;
private Cursor mCursor;
private Resources mResources;
// Column index
private int mCatInd;
private int mURLPicInd;
private int mIntroInd;
private int mTitleInd;
private LayoutInflater mLayoutInflater;
private final ImageDownloader mImageLoader;
private final class ViewHolder {
public TextView category;
public ImageView image;
public TextView intro;
public TextView title;
}
public HomeListAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.mLayout = layout;
this.mCursor = c;
this.mCatInd = mCursor.getColumnIndex(DBAdapter.KEY_CATEGORY_NAME);
this.mURLPicInd = mCursor.getColumnIndex(DBAdapter.KEY_URL_PIC);
this.mIntroInd = mCursor.getColumnIndex(DBAdapter.KEY_INTRO);
this.mTitleInd = mCursor.getColumnIndex(DBAdapter.KEY_TITLE);
this.mLayoutInflater = LayoutInflater.from(context);
mResources = context.getResources();
mImageLoader = new ImageDownloader(mResources,
((BitmapDrawable)mResources.getDrawable(R.drawable.default_row_pic)).getBitmap(), 1);
}
public View getView(int position, View convertView, ViewGroup parent) {
if (mCursor.moveToPosition(position)) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = mLayoutInflater.inflate(mLayout, null);
viewHolder = new ViewHolder();
viewHolder.category = (TextView) convertView.findViewById(R.id.cat);
viewHolder.image = (ImageView) convertView.findViewById(R.id.picture);
viewHolder.title = (TextView) convertView.findViewById(R.id.title);
viewHolder.intro = (TextView) convertView.findViewById(R.id.intro);
viewHolder.intro.setMaxLines(3);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
String category = mCursor.getString(mCatInd);
String title = mCursor.getString(mTitleInd);
String intro = mCursor.getString(mIntroInd);
String url_pic = mCursor.getString(mURLPicInd);
viewHolder.category.setText(category);
viewHolder.title.setText(title);
viewHolder.intro.setText(intro);
if(!url_pic.equals("")){
mImageLoader.download(url_pic, (ImageView) viewHolder.image);
}
else {
viewHolder.image.setImageResource(R.drawable.default_row_pic);
}
}
return convertView;
}
}