Background:
I'm attempting to create a custom ArrayAdapter for a custom ListView. The list template I'm using to form each row contains a few TextView columns and one Button.
I'm using a SQLite table as the source of the list.
Problem:
I want the Button to capture the current time and write it to my SQLite table [Results] in the column corresponding to the row in which the Button appears. I'm at a loss for how I would do that.
Here is the class that contains the ArrayList
public class ResultsMenu extends ActionBarActivity {
private static final String LOGTAG = "Logtag: " + Thread.currentThread()
.getStackTrace()[2].getClassName(); // log tag for records
// sql elements for selecting boats
private String where = DBAdapter.KEY_RACE_ID + " = " + GlobalContent.activeRace.getId()
+ " AND " + DBAdapter.KEY_RESULTS_VISIBLE + " = 1";
private String orderBy = DBAdapter.KEY_BOAT_CLASS + " DESC ";
//instance of data source
RaceDataSource raceDataSource;
ResultDataSource resultDataSource;
// make a listview instance
ListView myList;
// make button instance for capturing finish time
Button buttonCaptureFinishTime;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_results_menu);
//wire data source and open
raceDataSource = new RaceDataSource(this);
resultDataSource = new ResultDataSource(this);
raceDataSource.open();
resultDataSource.open();
// wire list view
myList = (ListView) findViewById(R.id.lvResultList);
//wire button
buttonCaptureFinishTime = (Button) findViewById(R.id.btn_finish_time);
//set onclick listening for listview
myList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GlobalContent.setResultsRowID(id);
Intent intent = new Intent(view.getContext(), ResultsEditForm.class);
startActivity(intent);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_results_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onResume() {
super.onResume();
Log.i(LOGTAG, " onResume Now");
raceDataSource.open(); // reopen the db
resultDataSource.open(); // reopen the db
//populateListView(); // need to build this
}
#Override
protected void onPause() {
super.onPause();
Log.i(LOGTAG, " onPause NOW");
raceDataSource.close(); // close db to reduce data leak
resultDataSource.close(); // close db to reduce data leak
}
public void populateListView(){
}
}
ArrayAdapter so far
public class ResultsAdapter extends BaseAdapter {
Context mContext; // add context
LayoutInflater inflater; // instance of inflater
// lists of result
private ArrayList<Result> arraylist;
// instance constructor
public ResultsAdapter(Context context, ResultDataSource resultDataSource) {
mContext = context;
inflater = LayoutInflater.from(mContext);
this.arraylist = new ArrayList<Result>();
}
/**
* How many items are in the data set represented by this Adapter.
*
* #return Count of items.
*/
#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 index, View view, final ViewGroup parent) {
if (view == null) {
// build inflater to create a new row for each row in the Results table
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
view = inflater.inflate(R.layout.activity_list_template_results, parent, false);
}
final Result result = arraylist.get(index);
Button btn = (Button) view.findViewById(R.id.btn_finish_time); // instance of button
// wire text views and set the associated text to them.
TextView tv = (TextView) view.findViewById(R.id.txt_hd_results_ID);
tv.setText(result.getResultsId() + "");
tv = (TextView) view.findViewById(R.id.txt_hd_results_race_id);
tv.setText(result.getResultsRaceId() + "");
tv = (TextView) view.findViewById(R.id.txt_hd_results_boat_id);
tv.setText(result.getResultsBoatId() + "");
tv = (TextView) view.findViewById(R.id.txt_hd_results_Visible);
tv.setText(result.getResultsVisible() + "");
tv = (TextView) view.findViewById(R.id.txt_hd_results_Name);
tv.setText(result.getBoatName() + "");
tv = (TextView) view.findViewById(R.id.txt_hd_results_Class);
tv.setText(result.getBoatClass() + "");
tv = (TextView) view.findViewById(R.id.txt_hd_results_SailNum);
tv.setText(result.getBoatSailNum() + "");
// set the function of each finish button
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LocalTime localTime = new LocalTime();// capture the current time
// TODO: Add SQLite statement to insert local time into Results table
}
});
return view;
}
}
Inside the onClick method you can create an instance of your database, open it and update the data accordingly.
DatabaseConnection database = new DatabaseConnection(context);
database.getWritableDatabase();
Related
I know this question has been around, but trying solutions proposed in SO threads weren't helpful!
I Have an activity (Favorites) with 3 fragment (represent categories, Video/figures/other) ..in each fragment there is a list of favorites following the category ..
my problem is ..when i delete an item from list of favorite ..it get deleted from database but the listview don't get refresh instantely! ..i have to move between fragments for that to happen ..
i tried:
1. notifyDataSetChanged(); //do nothing
2. `refreshEvents(listfavorite);` // after the delete button onclick with refresh events=:
public void refreshEvents(final List<Data> events)
{
this.listfavorite.clear();
this.listfavorite.addAll(events);
notifyDataSetChanged();
The result of 2nd method: the list is cleared instantely but don't get repopulated again!
3.
//after on delete on click
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//listfavorite.addAll(events);
notifyDataSetChanged(); }
}, 1000);
This is my Fragment Adapter
public class FragmentAdapter extends BaseAdapter {
private List<Data> listfavorite;
Context context;
String name, packagename, id, section;
Long _id;
private DBManager dbManager;
boolean isFavourite;
private LayoutInflater mInflater;
public FragmentAdapter(Context FragmentOther,List<Data> resultsFavorite){
this.listfavorite = resultsFavorite;
this.context=FragmentOther;
mInflater = LayoutInflater.from(FragmentOther);
}
public void removeItemAtPosition(int position) {
if (listfavorite != null) {
listfavorite.remove(position);
notifyDataSetChanged();
}
}
public void clearAll() {
if (listfavorite != null) {
listfavorite.clear();
notifyDataSetChanged();
}
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return listfavorite.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return listfavorite.get(arg0);
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
public View getView(int position, View rowView, ViewGroup parent) {
// TODO Auto-generated method stub
final ViewHolder holder;
if(rowView == null){
rowView = mInflater.inflate(R.layout.activity_view_record, null);
holder = new ViewHolder();
//define those textsview that corresponds to the row views so later we'll retrieve the data from them
holder.idTextView = (TextView) rowView.findViewById(R.id.id);
holder.nameTextView = (TextView) rowView.findViewById(R.id.name);
holder.sectionTextView = (TextView) rowView.findViewById(R.id.section);
holder.packageTextView = (TextView) rowView.findViewById(R.id.packagename);
//retrieve to this strings
id = listfavorite.get(position).getIdFav();
name = listfavorite.get(position).getNameAct();
section = listfavorite.get(position).getSectionName();
packagename = listfavorite.get(position).getPackageAct();
//This will be used for deleting data, because delete data we'll need to pass a long type variable
_id = Long.parseLong(id);
// define the button/textview because the popmenu needs a header!
holder.viewoption=(TextView) rowView.findViewById(R.id.textViewOptions);
holder.viewoption.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// so we can use a custom pop menu we'll use this code, first define the contextwrapper
// and define the style of popmenu as second argument! , the style should have as parent
// Widget.AppCompat.PopupMenu ! then
//pass it in popmenu as firstargument
// the gravity.right serve to create margin from right side of the screen
Context wrapper = new ContextThemeWrapper(context, R.style.YOURSTYLE);
//creating a popup menu
PopupMenu popup = new PopupMenu(wrapper, holder.viewoption, Gravity.RIGHT);
//inflating menu from xml resource
popup.inflate(R.menu.options_menu);
// this is really important! to show icon you should use this function, because the icons in normal
// cases don't show up! (we pass the name of the popupmenu inside
setForceShowIcon(popup);
//adding click listener
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
//delete from database
//Open the database
dbManager = new DBManager(context);
dbManager.open();
dbManager.delete(_id);
//change value of isfav
isFavourite = false;
//save it to sharedprefrenece, the state will be read in other activities and
//show the correspondante state False or true
saveState(isFavourite);
refreshEvents(listfavorite);
notifyDataSetChanged();
//update activity so it'll delete it
// onResume();
break;
case R.id.gotoact:
Intent access_activity = new Intent();
//we use this type of intent because it allow us to use strins for intent
//after retrieving data from row, we'll pass it as second argument
access_activity.setClassName(context,packagename);
context.startActivity(access_activity);
break;
}
return false;
}
});
//displaying the popup
popup.show();
}
});
rowView.setTag(holder);
} else {
holder = (ViewHolder) rowView.getTag();
}
holder.nameTextView.setText(Html.fromHtml(listfavorite.get(position).getNameAct()));
holder.sectionTextView.setText(listfavorite.get(position).getSectionName());
return rowView;
}
public void refreshEvents(final List<Data> events)
{
this.listfavorite.clear();
this.listfavorite.addAll(events);
notifyDataSetChanged();
}
my fragment.java
public class FragmentVideosFav extends Fragment {
private static final String ARG_TITLE = "title";
private String mTitle;
//------Define Database
private DBManager dbManager;
//
List<Data> listContact;
//ListView
private ListView listView;
// Adapter
private FragmentAdapter adapter;
public FragmentVideosFav (){}
public static FragmentVideosFav getInstance(String title) {
FragmentVideosFav fra = new FragmentVideosFav();
Bundle bundle = new Bundle();
bundle.putString(ARG_TITLE, title);
fra.setArguments(bundle);
return fra;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
mTitle = bundle.getString(ARG_TITLE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_other, container, false);
listContact = Getlistfavorite();
//define the list
listView = (ListView) v.findViewById(R.id.list_view);
//if the list is empty! set the correspondante layout!
listView.setEmptyView(v.findViewById(R.id.empty));
// set list to the adapter
adapter= new FragmentAdapter(getActivity(),listContact);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
return v;
}
//refresh fragment when switch to ..
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(
isVisibleToUser);
if (getFragmentManager() != null) {
getFragmentManager()
.beginTransaction()
.detach(this)
.attach(this)
.commit();
}
}
// init Data of fragment
private List<Data> Getlistfavorite(){
List<Data> favoritelist = new ArrayList<Data>();
dbManager = new DBManager(getActivity());
dbManager.open();
Cursor c = dbManager.fetchvideo();
//startManagingCursor(c);
int ititle = c.getColumnIndex(_ID);
int idesc = c.getColumnIndex(ACTIVITY_NAME);
int isection = c.getColumnIndex(SECTION_NAME);
int ipath = c.getColumnIndex(PACKAGE_NAME);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()){
String title = c.getString(ititle);
String desc = c.getString(idesc);
String section = c.getString(isection);
String path = c.getString(ipath);
favoritelist.add(new Data(title, desc , section , path));}
return favoritelist;
}
}
Try this:
View getView(int position, View rowView, ViewGroup parent) {
Data favorite = listfavorite.get(position);
// Etc
case R.id.delete:
dbManager = new DBManager(context);
dbManager.open();
dbManager.delete(_id);
//change value of isfav
isFavourite = false;
//save it to sharedprefrenece, the state will be read in other activities and
//show the correspondante state False or true
saveState(isFavourite);
listfavorite.remove(favorite);
notifyDataSetChanged();
My expandable listview scroll very slow and take a while when I click on the parent category until I see the child view.
Group List Activity:
public class GroupsListActivity extends Activity {
String loggedUserId = Model.getInstance().getLoggedUserId();
List<String> groupsList;
static ExpandableListView expandableListView;
HashMap<String, List<Group>> groupCategories = new HashMap<String, List<Group>>();
static ProgressBar spinner;
static TextView textLoading;
ImageButton createCategoryButton;
static Adapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set layout for this activity
setContentView(R.layout.expandable_list);
// Set actionbar title
getActionBar().show();
getActionBar().setTitle(Html.fromHtml("<font color='#fffffff'>Groups</font>"));
if (loggedUserId != null)
Log.d("TAG", "My Groups for user ID: " + loggedUserId);
// Connect between buttons to layout id
expandableListView = (ExpandableListView) findViewById(R.id.exp_list);
spinner = (ProgressBar) findViewById(R.id.spinner);
createCategoryButton = (ImageButton) findViewById(R.id.createCategory);
textLoading = (TextView) findViewById(R.id.textLoading);
// Loading data to expandable group list asynchronously
AsyncTask<String, String, HashMap<String, List<Group>>> task = new AsyncTask<String, String, HashMap<String, List<Group>>>() {
#Override
protected HashMap<String, List<Group>> doInBackground(String... params) {
return DataProvider.getInfo();
}
#Override
protected void onPostExecute(HashMap<String, List<Group>> listHashMap) {
super.onPostExecute(listHashMap);
// Setting adapter and creating group list
groupCategories = listHashMap;
groupsList = new ArrayList<String>(groupCategories.keySet());
adapter = new Adapter(GroupsListActivity.this, groupCategories, groupsList, GroupsListActivity.this);
expandableListView.setAdapter(adapter);
// Hide spinner after loading
spinner.setVisibility(View.GONE);
textLoading.setVisibility(View.GONE);
}
};
task.execute();
// Setting listener for group click
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
#Override
public boolean onChildClick(ExpandableListView parent, View v, int parentPosition, int childPosition, long id) {
// After selecting a group on row - open contacts list for this group
expandableListView.setEnabled(false);
openContactListForGroup(groupCategories.get(groupsList.get(parentPosition)).get(childPosition).getGroupID());
return true;
}
});
// Setting listener for create group click
createCategoryButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
createCategoryButton.setEnabled(false);
onCategoryCreate(GroupsListActivity.this, createCategoryButton);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_actionbar_groups, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create:
onCreate();
return true;
case R.id.action_search:
onSearch();
return true;
case R.id.action_favorites:
onFavorites();
return true;
case R.id.action_settings:
onSettings();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
// Menu methods
private void onCreate() {
Log.d("TAG", "Create button was pressed");
Intent i = new
Intent(getApplicationContext(),
CreateGroupActivity.class);
startActivity(i);
overridePendingTransition(R.animator.slide_out_right, R.animator.slide_in_right);
}
private void onSearch() {
Log.d("TAG", "Search button was pressed");
Intent i = new
Intent(getApplicationContext(),
SearchActivity.class);
startActivity(i);
overridePendingTransition(R.animator.slide_out_right, R.animator.slide_in_right);
}
private void onFavorites() {
Log.d("TAG", "Favorites button was pressed");
Intent i = new
Intent(getApplicationContext(),
FavoritesListActivity.class);
startActivity(i);
overridePendingTransition(R.animator.slide_out_right, R.animator.slide_in_right);
}
private void onSettings() {
Log.d("TAG", "Settings button was pressed");
// Settings activity
Intent i = new
Intent(getApplicationContext(),
SettingsActivity.class);
startActivity(i);
overridePendingTransition(R.animator.slide_out_right, R.animator.slide_in_right);
}
// Methods to handle action buttons
private void onCategoryCreate(final Activity activity, final ImageButton createCategoryButton) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
createCategoryButton.setEnabled(true);
final String title = "Create a new category";
String message = "Type a name for your new category";
// Set dialog edit_text
final EditText categoryNameTextView = new EditText(activity);
categoryNameTextView.setHint("Type your category name");
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
categoryNameTextView.setLayoutParams(lp);
builder.setView(categoryNameTextView);
// Set dialog title and message
if (title != null)
builder.setTitle(Html.fromHtml("<font color='#dc1c1c'>" + title + "</font>")).setMessage(message);
// Set dialog buttons
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
final String newCategoryName = categoryNameTextView.getText().toString();
// Check if contains only spaces
if (!(newCategoryName.trim().length() > 0))
Toast.makeText(activity, "Type at least 1 letter to create the category", Toast.LENGTH_LONG).show();
// Check if category name already exists
else if (groupsList.contains(newCategoryName))
Toast.makeText(activity, newCategoryName + " already exist. Please type another category name", Toast.LENGTH_LONG).show();
else {
// Create a new category in server and add user to a sample group
adapter.getCategoriesList().add(newCategoryName);
adapter.getGroupsList().put(newCategoryName, Collections.<Group>emptyList());
// Update adapter and show toast to user
GroupsListActivity.updateAdapter();
Toast.makeText(activity, "You created " + newCategoryName + " category", Toast.LENGTH_LONG).show();
}
}
});
builder.setNegativeButton(
"Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.setIcon(R.mipmap.edit);
builder.show();
}
public void openContactListForGroup(String groupId) {
// Contacts List activity
Intent i = new
Intent(getApplicationContext(),
ContactsListActivity.class);
// Pass to details activity the logged group id and start activity
Bundle b = new Bundle();
b.putString("groupId", groupId);
i.putExtras(b);
startActivity(i);
overridePendingTransition(R.animator.slide_out_right, R.animator.slide_in_right);
}
// Static methods to use from other activities
public static void updateAdapter() {
spinner.setVisibility(View.VISIBLE);
adapter.notifyDataSetChanged();
// Hide spinner after adapter finish the update
expandableListView.post(new Runnable() {
#Override
public void run() {
spinner.setVisibility(View.GONE);
}
});
}
public static void addGroupToList(String groupId) {
Model.getInstance().getGroup(groupId, new Model.groupReturnedListener() {
#Override
public void addGroupToLocal(Group group) {
// Add group to category Others in Group List Activity
if (adapter.getGroupsList().get("Others").size() == 0) {
// Add group to empty list
List<Group> list = new LinkedList<Group>();
list.add(group);
adapter.getGroupsList().put("Others", list);
adapter.notifyDataSetChanged();
} else {
// Add group to an existing list
adapter.getGroupsList().get("Others").add(group);
adapter.notifyDataSetChanged();
}
}
});
}
public static void removeGroupFromList(String groupId) {
int position = -1;
// Get category position
String oldCategoryName = Model.getInstance().getCategoryNameByGroupId(groupId);
List<Group> data = adapter.getGroupsList().get(oldCategoryName);
// Search for group position
for (Group group : data) {
if (group.getGroupID().equals(groupId)) {
position = data.indexOf(group);
break;
}
}
// Groups was found
if (position != -1) {
data.remove(position);
adapter.notifyDataSetChanged();
}
}
public static void updateGroupFromList(Group group) {
int position = -1;
// Get category position
String oldCategoryName = Model.getInstance().getCategoryNameByGroupId(group.getGroupID());
List<Group> data = adapter.getGroupsList().get(oldCategoryName);
// Search for group position
for (Group groupIterator : data) {
if (groupIterator.getGroupID().equals(group.getGroupID())) {
position = data.indexOf(groupIterator);
break;
}
}
// Groups was found
if (position != -1) {
data.remove(position);
data.add(group);
adapter.notifyDataSetChanged();
}
}
// Other methods
#Override
protected void onResume() {
super.onResume();
expandableListView.setEnabled(true);
}
#Override
public void onBackPressed() {
ExitDialog exitDialog = new ExitDialog(GroupsListActivity.this);
exitDialog.show();
}
}
This is the activity of the Adapter where I load the expandable listview :
#Override
public View getGroupView(final int parent, boolean isExpanded, View convertView, ViewGroup parentView) {
final String categoryName = (String)getGroup(parent);
ParentViewHolder pHolder = null;
if(convertView == null) {
pHolder = new ParentViewHolder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.expandable_list_parent, parentView, false);
// Connect between buttons to layout id
pHolder.categoryNameTextView = (TextView) convertView.findViewById(R.id.categoryName);
pHolder.editCategory = (ImageButton) convertView.findViewById(R.id.editCategory);
pHolder.deleteCategory = (ImageButton) convertView.findViewById(R.id.deleteCategory);
convertView.setTag(pHolder);
}
else {
pHolder = (ParentViewHolder) convertView.getTag();
}
// Hide edit and delete button for category name Others
if(categoriesList.get(parent).equals("Others")){
pHolder.editCategory.setVisibility(View.GONE);
pHolder.deleteCategory.setVisibility(View.GONE);
}
else {
pHolder.editCategory.setVisibility(View.VISIBLE);
pHolder.deleteCategory.setVisibility(View.VISIBLE);
}
// Set category name on row
pHolder.categoryNameTextView.setTypeface(null, Typeface.BOLD);
pHolder.categoryNameTextView.setText(categoryName + ": " + getChildrenCount(parent));
// Set edit category button listener
final ParentViewHolder finalPHolder = pHolder;
pHolder.editCategory.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finalPHolder.editCategory.setEnabled(false);
editCategoryName(activity, finalPHolder.categoryNameTextView.getText().toString().toString().split(": ")[0], finalPHolder.editCategory, parent);
}
});
// Set delete category button listener
pHolder.deleteCategory.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finalPHolder.deleteCategory.setEnabled(false);
deleteCategory(activity, categoryName, finalPHolder.deleteCategory);
}
});
return convertView;
}
#Override
public View getChildView(final int parent, final int child, boolean lastChild, View convertView, ViewGroup parentView) {
final Group group = (Group)getChild(parent, child);
ChildViewHolder cHolder = null;
if(convertView == null){
cHolder = new ChildViewHolder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.expandable_list_child, parentView, false);
// Connect between buttons to layout id
cHolder.groupImage = (ImageView) convertView.findViewById(R.id.groupImage);
cHolder.groupName = (TextView) convertView.findViewById(R.id.groupName);
cHolder.moveCategory = (ImageButton) convertView.findViewById(R.id.moveCategory);
cHolder.groupFavoritesButton = (ImageButton) convertView.findViewById(R.id.groupFavorites);
cHolder.groupLeaveGroupButton = (Button) convertView.findViewById(R.id.groupLeave);
cHolder.groupImageProgressbar = (ProgressBar) convertView.findViewById(R.id.groupImageProgressBar);
convertView.setTag(cHolder);
} else {
cHolder = (ChildViewHolder) convertView.getTag();
}
// Set group name on row
cHolder.groupName.setText(group.getName());
// Load group image
cHolder.groupImageProgressbar.setVisibility(View.VISIBLE);
final ChildViewHolder finalHolder = cHolder;
Model.getInstance().getGroupImage(group.getImageName(), new Model.LoadImageListener() {
#Override
public void onResult(Bitmap imageBmp) {
finalHolder.groupImage.setImageBitmap(imageBmp);
finalHolder.groupImageProgressbar.setVisibility(View.GONE);
finalHolder.groupImage.setVisibility(View.VISIBLE);
}
});
// Set move category button listener
cHolder.moveCategory.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finalHolder.moveCategory.setEnabled(false);
showDialogMoveCategory(activity, group.getGroupID(), finalHolder.moveCategory);
}
});
// After click on group image - open profile for this group
cHolder.groupImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onGroupSelected(group.getGroupID());
}
});
// Setting favorite Button Image
boolean isFavorite = Model.getInstance().groupIsFavorite(loggedUserId, group.getGroupID());
if(isFavorite)
cHolder.groupFavoritesButton.setBackgroundResource(R.mipmap.favorites_on);
else
cHolder.groupFavoritesButton.setBackgroundResource(R.mipmap.favorites_off);
// Setting favorite Button Action
cHolder.groupFavoritesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Add group to favorites
if (!Model.getInstance().groupIsFavorite(loggedUserId, group.getGroupID())) {
finalHolder.groupFavoritesButton.setBackgroundResource(R.mipmap.favorites_on);
Toast.makeText(activity,
"The group " + group.getName() + " was added to favorites", Toast.LENGTH_SHORT).show();
Model.getInstance().changeFavoriteStatus(loggedUserId, group.getGroupID(), "true");
} else {
// Delete group from favorites
finalHolder.groupFavoritesButton.setBackgroundResource(R.mipmap.favorites_off);
Toast.makeText(activity,
"The group " + group.getName() + " was removed from favorites", Toast.LENGTH_SHORT).show();
Model.getInstance().changeFavoriteStatus(loggedUserId, group.getGroupID(), "false");
}
}
});
// After click on group action - leave group
cHolder.groupLeaveGroupButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finalHolder.groupLeaveGroupButton.setEnabled(false);
showDialogLeaveGroup(activity, "Are you sure ?", "This action will remove yourself from the group " + group.getName(), group.getGroupID(), parent, child);
finalHolder.groupLeaveGroupButton.setEnabled(true);
}
});
return convertView;
}
The loading image method:
public void getGroupImage(final String imageName, final LoadImageListener listener) {
AsyncTask<String, String, Bitmap> task = new AsyncTask<String, String, Bitmap>() {
#Override
protected Bitmap doInBackground(String... params) {
Bitmap bmp = loadImageFromFile(imageName); //first try to find the image on the device
// Bitmap bmp = null;
if (bmp == null) { //if image not found - try downloading it from parse
bmp = modelParse.getGroupImage(imageName);
if (bmp != null)
saveImageToFile(bmp, imageName); //save the image locally for next time *****
}
Bitmap scaledBitmap = scaleDown(bmp, 200, true);
return scaledBitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
listener.onResult(result);
}
};
task.execute();
}
private void saveImageToFile(Bitmap imageBitmap, String imageFileName) {
FileOutputStream fos;
OutputStream out = null;
try {
File dir = context.getExternalFilesDir(null);
out = new FileOutputStream(new File(dir, imageFileName + ".jpg"));
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private Bitmap loadImageFromFile(String fileName) {
Bitmap bitmap = null;
try {
File dir = context.getExternalFilesDir(null);
InputStream inputStream = new FileInputStream(new File(dir, fileName + ".jpg"));
bitmap = BitmapFactory.decodeStream(inputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bitmap;
}
I'll try to give the general (abstract) idea about listviews and adapters which should help you figure out the wrong parts yourself.
The whole purpose of the adapter is to display the correct data for the corresponding list item and do as little other job as possible. In this process, anything that is related to data manipulation is requiring cpu cycles that will cause lags and slow scrolling.
Specifically, android apps should run at a smooth 60 frames-per-second and each frame should take no longer then 16.6 milliseconds to render in order to achieve this 60FPS rate. So if you are creating extra load for the CPU it may come on the account of frame rendering and from here the path to lags in rendering is short.
What am I saying - there are probably some methods in your adapter that are manipulating data on the spot, synchronously and it's taxing the cpu. The adapter should take represent the data that is ALREADY prepared for display and just show it in the correct view. An example for performance issues might be as easy as using String.replace() method everytime for every view or another bad example will be loading images Synchronously instead of Asynchronously.
I see two major issues for performance.
First, your use of findViewById everywhere. You're walking the entire view tree doing that. That's why people use ViewHolder patterns or custom view patterns. IF you ever use findViewById more than once per view in the lifetime of your app, you're doing it wrong.
Second, you're allocating new objects every time the user scrolls. Don't. Use a ViewHolder or vustom view pattern so you can reuse the same OnClickListener's for all scroll events, creating them only once per row and updating the values as needed. If you ever create an object in your getView, other than when convertView is null, you're being really inefficient.
So essentially I have a listview that contains a custom adapter that deals with formatting the listview. The custom view used by the adapter contains a checkbox that I want to be checked with the check locked when the listview item is selected. After much searching and various attempts at accomplishing this I have not been successful. Any ideas as to how to accomplish this would be greatly appreciated.
Here is the code for my main class:
public class AbWorkout extends Activity {
Button back;
ListView workoutExerciseList;
WorkoutTracker tracker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ab_workout);
/**
* The database used to pull all exercises for this workout routine
*/
final DatabaseHandler db = new DatabaseHandler(this);
final SQLiteDatabase database = db.getReadableDatabase();
final Context context = this;
/**
* Get all exercises from Triceps and Chest workout and put in arraylist
*/
workoutExerciseList = (ListView)findViewById(R.id.listView10);
final List<String> arrayWorkoutExercises = new ArrayList<String>();
final ArrayAdapter<String> exListAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_multiple_choice, arrayWorkoutExercises);
workoutExerciseList.setAdapter(exListAdapter);
//Holds all the available exercises
final List<WorkoutTracker> exerciseList = db.getRepetitionWorkoutRoutine(context, database, "Abs");
/**
* Populates the listView with each exercise for this workout routine. This includes the
* each exercise name, the number of repetitions, the weight of the exercise, and any
* comments included.
*/
List<AbWorkout.RepListViewItem> repProgressList = new ArrayList<>();
for(int i = 0; i<exerciseList.size(); i++) {
final int j = i;
repProgressList.add(new AbWorkout.RepListViewItem()
{{
REPETITIONS = exerciseList.get(j).getReps();
WEIGHT = exerciseList.get(j).getWeight();
COMMENT = exerciseList.get(j).getComment();
EXERCISE_NAME = exerciseList.get(j).getExerciseName();
}});
}
final AbViewAdapter adapter = new AbViewAdapter(this, repProgressList);
workoutExerciseList.setAdapter(adapter);
CheckBox checkBox = (CheckBox)findViewById(R.id.CheckBox);
workoutExerciseList.setItemChecked(ListView.CHOICE_MODE_MULTIPLE, true);
/*
Upon selection of an exercise, it is highlighted and its name, date,
and number of reps is stored in repetition progress table
*/
workoutExerciseList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> myAdapter, View myView, int myItemInt, long mylng) {
CheckBox check = (CheckBox) findViewById(R.id.CheckBox);
//check.setChecked(true);
Calendar calendar = Calendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yy");
//Get today's date formatted like this: dd-MM-yy
String exDate = format.format(calendar.getTime());
//When exercise is selected, change the color and make it unselectable.
myAdapter.getChildAt(myItemInt).setBackgroundColor(Color.MAGENTA);
myAdapter.getChildAt(myItemInt).setEnabled(false);
myAdapter.getChildAt(myItemInt).setClickable(false);
myView.setClickable(true);
tracker = exerciseList.get(myItemInt);
db.addNewRepProgress(new WorkoutTracker(tracker.getExerciseName(), tracker.getReps(), tracker.getWeight(), tracker.getComment(), exDate), context, database);
Toast.makeText(context.getApplicationContext(), "Workout Progress was successfully saved.", Toast.LENGTH_LONG).show();
}
});
back = (Button)findViewById(R.id.back);
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_ab_workout, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public class RepListViewItem
{
public int REPETITIONS;
public double WEIGHT;
public String COMMENT;
public String EXERCISE_NAME;
public String DATE;
}
}
And here is the code for my adapter class:
public class AbViewAdapter extends BaseAdapter
{
LayoutInflater inflater;
List<AbWorkout.RepListViewItem> items;
int pos = 0;
public AbViewAdapter(Activity context, List<AbWorkout.RepListViewItem> items) {
super();
this.items = items;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return items.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
AbWorkout.RepListViewItem item = items.get(position);
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.rep_item_row, null);
TextView exerciseName = (TextView)vi.findViewById(R.id.FullProgress);
TextView exerciseReps = (TextView)vi.findViewById(R.id.Time);
TextView exerciseComment = (TextView)vi.findViewById(R.id.Comment);
TextView exerciseWeight = (TextView)vi.findViewById(R.id.Distance);
CheckBox check = (CheckBox)vi.findViewById(R.id.CheckBox);
exerciseName.setText(item.EXERCISE_NAME);
exerciseReps.setText(String.valueOf(item.REPETITIONS));
exerciseComment.setText(item.COMMENT);
exerciseWeight.setText(String.valueOf(item.WEIGHT));
pos = position;
return vi;
}
}
because when you scroll your listview, the item in A will be destroyed. When scroll up, the item in A will be re-created.
So the CheckBox is re-create too, you need to store item when to restore this current state when scroll up. Let see ViewHolder
In your AbViewAdapter.getView(), add an OnClickListener
Then, in the OnClickListener, toggle the checkbox state with:
check.setChecked(!isChecked())
Full answer here: Android listview with check boxes?
Full tutorial here: http://www.mysamplecode.com/2012/07/android-listview-checkbox-example.html
I'm trying to get data from column ITEMS in my Database to appear in the Items listView when you click the add button. At the moment when you click the add button it just saves a item in a column of the database. I would appreciate an answer!
The main Java class (New_Recipe)
public class New_Recipe extends AppCompatActivity {
Button add,done,display;
EditText Recipe_Name,Recipe_Item,Recipe_Steps;
String search;
WebView webView;
DatabaseHelper databaseHelper;
ListView Items;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new__recipe);
databaseHelper = new DatabaseHelper(this);
setTitle("New Recipe");
add = (Button) findViewById(R.id.button2);
done = (Button) findViewById(R.id.button);
Recipe_Name = (EditText) findViewById(R.id.editText);
Recipe_Item = (EditText) findViewById(R.id.editText2);
Recipe_Steps = (EditText) findViewById(R.id.editText3);
webView = (WebView) findViewById(R.id.webView);
display = (Button) findViewById(R.id.button3);
Items = (ListView) findViewById(R.id.listView);
AddData();
viewAll();
}
public void AddData() {
done.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean inserted = databaseHelper.insertData1(Recipe_Name.getText().toString(),
Recipe_Steps.getText().toString());
if (inserted == true)
Log.d("Database", "Data successfully inserted!");
else Log.d("Database","Data did not insert!");
}
});
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean inserted = databaseHelper.insertData2(Recipe_Item.getText().toString());
if (inserted == true)
Log.d("Database", "Data successfully inserted!");
else Log.d("Database","Data did not insert!");
}
});
}
public void viewAll() {
display.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Cursor res = databaseHelper.getAllData();
if (res.getCount() == 0) {
showMessage("Error","No Data found!");
return;
}
StringBuffer stringBuffer = new StringBuffer();
while (res.moveToNext()) {
stringBuffer.append("Names :"+res.getString(0)+"\n");
stringBuffer.append("Items :"+res.getString(1)+"\n");
stringBuffer.append("Steps :"+res.getString(2)+"\n\n");
}
showMessage("Success!",stringBuffer.toString());
}
});
}
public void showMessage(String title,String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(true);
builder.setTitle(title);
builder.setMessage(message);
builder.show();
}
public void onSearch(View v) {
search = "Recipes";
webView.loadUrl("https://www.google.com/search?q="+search);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_new__recipe, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
The Database Java class (DatabaseHelper)
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "Recipes.db";
public static final String TABLE_NAME = " Recipe_Table";
public static final String COL1 = "NAME";
public static final String COL2 = "ITEMS";
public static final String COL3 = "STEPS";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
Log.d("Database", "Database should be made!");
}
#Override
public void onCreate (SQLiteDatabase db){
db.execSQL("create table " + TABLE_NAME + " (NAME TEXT PRIMARY KEY,ITEMS TEXT,STEPS TEXT)");
Log.d("Database", "Database should be made!, Again");
}
#Override
public void onUpgrade (SQLiteDatabase db,int oldVersion, int newVersion){
db.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME);
Log.d("Database", "Table exists");
onCreate(db);
}
public boolean insertData1(String name,String steps) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL1, name);
contentValues.put(COL3, steps);
long result = db.insert(TABLE_NAME,null,contentValues);
if (result == -1)
return false;
else
return true;
}
public boolean insertData2(String items) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL2, items);
long result = db.insert(TABLE_NAME,null,contentValues);
if (result == -1)
return false;
else
return true;
}
public Cursor getAllData() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.rawQuery("select * from "+TABLE_NAME,null);
return res;
}
public Cursor getItemData() {
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select"+COL2+"from"+TABLE_NAME,null);
return res;
}
}
The real Android way to do this would be to use a combination of ContentProvider and CursorAdapter.
Android already has a way to take a Cursor from a query and put the data in a ListView: The CursorAdapter class. You just override getView() to create the item view for your list.
Here's what a custom ContentProvider will get you: When you create a content provider URI and query it to get a Cursor, a DataObserver is set up, so that when you insert/delete/update data through the ContentProvider using that URI, the Cursor will get a notification that the data has changed and will re-query the data. When that Cursor has been set on a CursorAdapter, the adapter will also see that the cursor data has changed and call notifyDataSetChanged().
So the net result is that when you add a record, your ListView is automatically refreshed with current data.
For an introduction to Content Providers, refer to this article: Content Providers | Android Developers.
You need to create an adapter that the list view can draw its data from. You will pass the data from your getAllData() call to the adapter, which the list view will then display.
If you haven't already, you can create a custom class which extends base adapter, implement the methods correctly, then all you have to worry about it the data.
First off, I always like to build a class that can store my data retrieved from the database. Something simple, like:
public class ItemObject {
// Instance variables.
private String mName, mItem, mStep;
// Constructor.
public ItemObject(String name, String item, String step) {
mName = name;
mItem = item;
mStep = step;
}
// Create getters for each item.
public String getName() { /*...*/ }
public String getItem() { /*...*/ }
public String getStep() { /*...*/ }
}
Now you have an object that can store the items retrieved from the database table. In your while loop after calling getAllData() you create your ItemObject there.
For example:
List<ItemObject> itemObjectList = new ArrayList<>();
while (res.moveToNext()) {
// Extract values from the cursor.
String name = res.getString(0);
String item = res.getString(1);
String step = res.getString(2);
// Create the ItemObject and add it to the list.
ItemObject item = new ItemObject(name, item, step);
// Add it to the list.
itemObjectList.add(item);
}
Now, you'll have a list of items you can pass directly to your adapter.
public class ItemsListAdapter extends BaseAdapter {
// Instance variables.
private Context mContext;
private List<ItemObject> mItemObjectList;
// Constructor.
public ItemsListAdapter(Context context, List<itemObjectList> itemObjectList) {
mContext = context;
mItemObjectList = itemObjectList;
}
#Override
public int getCount() {
return mItemObjectList.size();
}
#Override
public Object getItem(int position) {
return mItemObjectList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// Inflate your layout for each row here. I wont include list view
// optimization here, as you should look it up, its documentation
// is readily available.
LayoutInflater inflater = LayoutInflater.from(mContext);
// Inflate the layout.
View layout = inflater.inflate(R.layout.<your_list_view_row_layout>, null);
// Reference the views inside the layout that will display each value. (Name, Item, Step);
TextView nameView = (TextView) layout.findViewById(R.id.<your_text_view_id>);
// Do this for each view.
// Now retrieve your data from the array list.
ItemObject item = (ItemObject) getItem(position);
// Now you have your item and the 3 values associated with it.
// Set the values in the UI.
nameView.setText(item.getName());
// Return the view.
return layout;
}
// Use this method to modify the data in the list view.
// It's an ArrayList so simply add or remove elements, clear it, etc.
public List<ItemObject> getAdapterList() {
return mItemObjectList;
}
}
To update the items in the list view, call getAdapterList() and modify the items in the ArrayList that is returned. After modification, you must invalidate the list by calling notifyDataSetChanged() on the adapter itself.
Hope this points you in the right direction.
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.