I want to make my expandable list smooth.
After looking a lot in the internet,
I added a viewHolder and changed my method where I load the data to be asynchronously. But my list is still slow!!!.
Can you take a look? I added the activity where I load asynchronously the data with my DataProvider and then I init my adapter. This help me to see my activity and a spinner until the data is loaded and then updated on my view.
But I dont have a fluid list when I scroll or when I try to expand a category. Can you help and tell me what to change ? I think that it can be the images but I save them locally to make it faster (I added my methods) and it can be something else....
MyActivity:
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();
My adapter:
#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) {
// Creates a ViewHolder and store references to layouts we want to bind data to.
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);
//Save holder
convertView.setTag(pHolder);
} else {
// Get the ViewHolder back
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) {
// Creates a ViewHolder and store references to layouts we want to bind data to.
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);
//Save holder
convertView.setTag(cHolder);
} else {
// Get the ViewHolder back
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) {
if (imageBmp != null) {
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;
}
Images methods:
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;
}
Related
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.
I am facing problem with listview in android. I've a custom adapter with 3 textviews and a button whose text changes as per response from server. Actually I've a feature of search friend in my app,so the list appears with each user and its status on button text. Like if already friend then button text is Friend and button is disabled.Else Add Friend, and button enabled. After clicking Add Friend text of button changes to Request Sent. But the problem is that when i click on a button text of some other buttons also changes on scrolling. Please help me. If needed I'll put the code.
Here is my adapter class:
class ListViewCustomAdapter extends BaseAdapter {
private static final String REQUEST = "Request";
private static final String ACCEPT = "Accepted";
private static final String RECEIVE = "Receive";
private Activity context;
private ArrayList<FriendList> friendList;
private SessionManager sessionManager;
private String authToken;
private ProgressDialog progressDialog;
ViewHolder mViewHolder;
private HashMap<Integer, String> buttonTextMap;
public ListViewCustomAdapter(Activity activity,
ArrayList<FriendList> _friendList) {
this.context = activity;
this.friendList = _friendList;
sessionManager = new SessionManager(context);
authToken = sessionManager.getAuthorizationKey();
buttonTextMap = new HashMap<Integer, String>();
}
public int getCount() {
// TODO Auto-generated method stub
return friendList.size();
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return friendList.get(position);
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = layoutInflater.inflate(
R.layout.friend_list_view_item, null);
mViewHolder = new ViewHolder();
mViewHolder.profilePicture = (ImageView) convertView
.findViewById(R.id.friendPicureImageView);
mViewHolder.friendName = (TextView) convertView
.findViewById(R.id.firstNameTextView);
mViewHolder.email = (TextView) convertView
.findViewById(R.id.emailTextView);
mViewHolder.gender = (TextView) convertView
.findViewById(R.id.genderTextView);
mViewHolder.addButton = (Button) convertView
.findViewById(R.id.addFriendButton);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
byte[] imageByteArray = Base64.decode(friendList.get(position)
.getFriendProfilePic(), Base64.DEFAULT);
mViewHolder.profilePicture.setImageBitmap(BitmapFactory
.decodeByteArray(imageByteArray, 0, imageByteArray.length));
if (friendList.get(position).getFriendFirstName()
.equalsIgnoreCase("null")) {
mViewHolder.friendName.setText(friendList.get(position)
.getFriendLastName());
} else if (friendList.get(position).getFriendLastName()
.equalsIgnoreCase("null")) {
mViewHolder.friendName.setText(friendList.get(position)
.getFriendFirstName());
} else if (friendList.get(position).getFriendLastName()
.equalsIgnoreCase("null")
&& friendList.get(position).getFriendFirstName()
.equalsIgnoreCase("null")) {
mViewHolder.friendName.setText("No Name");
} else {
mViewHolder.friendName.setText(friendList.get(position)
.getFriendFirstName()
+ " "
+ friendList.get(position).getFriendLastName());
}
if (!friendList.get(position).getFriendEmail().equalsIgnoreCase("null")) {
mViewHolder.email
.setText(friendList.get(position).getFriendEmail());
}
if (!friendList.get(position).getFriendGender()
.equalsIgnoreCase("null")) {
if (friendList.get(position).getFriendGender()
.equalsIgnoreCase(Constants.MALE))
mViewHolder.gender.setText(Constants.SET_MALE);
else if (friendList.get(position).getFriendGender()
.equalsIgnoreCase(Constants.FEMALE)) {
mViewHolder.gender.setText(Constants.SET_FEMALE);
}
}
if (friendList.get(position).getFriendRequestStatus()
.equalsIgnoreCase(REQUEST)) {
/*
* buttonTextMap.put(position, "Request sent");
* buttonActiveStateMap.put(position, false);
*/
mViewHolder.addButton.setText("Request Sent");
mViewHolder.addButton.setEnabled(false);
} else if (friendList.get(position).getFriendRequestStatus()
.equalsIgnoreCase(ACCEPT)) {
/*
* buttonTextMap.put(position, "Add friend");
* buttonActiveStateMap.put(position, true);
*/
mViewHolder.addButton.setText("Friend");
mViewHolder.addButton.setEnabled(false);
} else if (friendList.get(position).getFriendRequestStatus()
.equalsIgnoreCase(RECEIVE)) {
/*
* buttonTextMap.put(position, "Add friend");
* buttonActiveStateMap.put(position, true);
*/
mViewHolder.addButton.setText("Accept");
mViewHolder.addButton.setEnabled(true);
}
buttonTextMap.put(position, mViewHolder.addButton.getText().toString());
Log.d("FriendList", "position in getview===== " + position);
mViewHolder.addButton.setTag(position);
mViewHolder.addButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
int which = -1;
Object obj = v.getTag();
if(obj instanceof Integer){
which = ((Integer)obj).intValue();
Log.e("FriendListActivity", "position button 1 ======= "+which);
}
if(which >-1){
Log.e("FriendListActivity", "position button 2======= "+which);
}
Button button = (Button) FriendListActivity.listView.getChildAt(which).findViewById(R.id.addFriendButton);
//Button button = (Button) v;
if (button.getText().toString().equalsIgnoreCase("Accept")) {
Intent intent = new Intent(context,
NotificationsActivity.class);
context.startActivity(intent);
context.finish();
} else {
int id = button.getId();
addFriend(button, friendList.get(position)
.getFriendUserId(),which);
}
}
});
return convertView;
}
static class ViewHolder {
TextView friendName;
TextView email;
TextView gender;
ImageView profilePicture;
Button addButton;
}
private void addFriend(final Button _button, final String userId,
final int _position) {
final JSONObject jsonObject = new JSONObject();
Log.e("FriendListActivity", "position in addFriend=== " + _position);
try {
jsonObject.put("authToken", authToken);
jsonObject.put("targetFriendId", userId);
jsonObject.put("requestType", "FriendRequest");
jsonObject.put("status", "Requested");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
progressDialog.dismiss();
if (msg.what == 1) {
_button.setText("Request sent");
_button.setEnabled(false);
Toast.makeText(context, "Request sent successfully.",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Request unsuccessfull.",
Toast.LENGTH_LONG).show();
}
}
};
progressDialog = ProgressDialog.show(context, "", "Loading...");
new Thread() {
#Override
public void run() {
String response = DoFriendRequest
.makeHttpPostRequest(jsonObject);
Message message = new Message();
if (response != null) {
message.what = 1;
handler.sendEmptyMessage(message.what);
} else {
handler.sendEmptyMessage(0);
}
}
}.start();
}
So finally I found the solution after a long research and completely understanding listview's recycling and use of convertview. As I am getting the status for each button from server, so in my addFriend() method I was just updating the text of the button(of the view only) which is pressed, but not in the list from where I am getting the data for the listview(each row of listview). So what I did, whenever I update the label-status of the button for a row, I've to update my datalist(in my case friendList by setting friendList.get(position).setFriendStatus("null")) and call adapter.notifyDatasetChanged() after that. I also forgot to add a check-filter for the "null" status of button. If anyone has any confusion please ask me.
This is the link which I referred for understanding listview getView() method-
How ListView's recycling mechanism works
I have a bug that I think is due to the way that lists reuse objects. I have a list of download buttons that get a progress readout when downloading. The update code is in a background thread.
When I scroll the list, the buttons that are showing progress jump into other list elements. How can I stop this? It's difficult to visualize, so I made a video of it:
http://www.youtube.com/watch?v=EiT2YWb2Prs&feature=youtu.be
BTW, the video was made by my client, so disregard the "samsung bug" bit. I'm the developer...
Here is the code:
public class VideosActivity extends Activity {
ListView video_list;
CustomList2 adapter;
File storage_dir;
String s3_bucket = "xx";
String s3_dir = "android/vol1/"; //the directory after the boucket that the files are stored in (do not add first slash)
Handler handler = new Handler(); //'tunnel' through whci other threads communicate with main thread
ArrayList<String> arr_videos = new ArrayList<String>();
ArrayList<String> arr_sdcardvideos = new ArrayList<String>();
int images[] = {R.drawable.kr115,R.drawable.kr200,R.drawable.kr201,R.drawable.kr202,R.drawable.kr203,R.drawable.kr205,R.drawable.kr206,R.drawable.kr207,R.drawable.kr208,R.drawable.kr209,R.drawable.kr210,R.drawable.kr211,R.drawable.kr212,R.drawable.kr213,R.drawable.kr213,R.drawable.kr214,R.drawable.kr215,R.drawable.kr216,R.drawable.kr210,R.drawable.kr211,R.drawable.kr212,R.drawable.kr213};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
storage_dir = getApplicationContext().getExternalFilesDir(null); //private to app, removed with uninstall
adapter = new CustomList2(this, R.layout.customlist, arr_videos);
video_list = (ListView)findViewById(R.id.list);
video_list.setAdapter(adapter); //set adapter that specifies list contents
ensureStorageDirExists( storage_dir ); //make sure storage dir exists
set_sdcard_video_data(); //store vids arleady on card
set_video_data(); //store vid dat in array
if(!have_connection())
{
Toast.makeText(this, "No Internet connection", Toast.LENGTH_LONG).show();
return;
}
}
protected void ensureStorageDirExists( File dir )
{
if (!dir.exists())
{
dir.mkdirs();
}
}
public void set_sdcard_video_data()
{
arr_sdcardvideos.clear();
for(File f:storage_dir.listFiles())
{
arr_sdcardvideos.add( f.getName() );
}
}
public void set_video_data()
{
arr_videos.add("02Posture_and_Walk.m4v");
arr_videos.add("03Embrace_Connection_and_Musicality.m4v");
arr_videos.add("04Left_Turning_Check_Step.m4v");
arr_videos.add("05Basic_Right_Turn.m4v");
arr_videos.add("06Ocho_Cortado.m4v");
arr_videos.add("07Media_Vuelta.m4v");
arr_videos.add("08The_Cross.m4v");
arr_videos.add("09Front_Ochos.m4v");
arr_videos.add("10The_Cross_in_Cross_System.m4v");
arr_videos.add("11Back_Ochos.m4v");
arr_videos.add("12Molinete_Giro.m4v");
arr_videos.add("13Right_Turn.m4v");
arr_videos.add("14Combining_All_the_Elements_1.m4v");
arr_videos.add("15Combining_All_the_Elements_2.m4v");
arr_videos.add("16Combining_All_the_Elements_3.m4v");
arr_videos.add("17Combining_All_the_Elements_4.m4v");
arr_videos.add("18Combining_All_the_Elements_5.m4v");
arr_videos.add("19Combining_All_the_Elements_6.m4v");
arr_videos.add("20Demo_Using_All_the_Elements.m4v");
arr_videos.add("36Etiquette.m4v");
}
public SharedPreferences stored_vals()
{
return PreferenceManager.getDefaultSharedPreferences(this);
}
public boolean have_connection()
{
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm.getActiveNetworkInfo()!=null && cm.getActiveNetworkInfo().isConnected() && cm.getActiveNetworkInfo().isAvailable())
{
return true;
}
else
{
return false;
}
}
public void download_video(int position, View btn)
{
}
public class CustomList2 extends ArrayAdapter<String>
{
View view;
int position;
Button btn;
public CustomList2(Context context, int layout_id, ArrayList<String> objects)
{
super(context, layout_id, objects);
}
#Override
public View getView(final int position, View convertView, ViewGroup view_group)
{
set_view(convertView);
this.position = position;
TextView text_view = (TextView) view.findViewById(R.id.name);
ImageView image = (ImageView) view.findViewById(R.id.img);
btn = (Button) view.findViewById(R.id.play);
prepare_btn();
text_view.setText( list_text() );
image.setImageResource(images[position]);
return view;
}
public String list_text()
{
String s = arr_videos.get( position ).replace("_", " ").replace(".m4v", "");
s = s.substring(2, s.length());
return s;
}
public void set_view(View convertView)
{
if(convertView == null)
{
LayoutInflater inflater = getLayoutInflater();
view = inflater.inflate(R.layout.customlist, null);
}
else
{
view = convertView;
}
}
public Boolean is_downloaded()
{
return arr_sdcardvideos.contains(arr_videos.get(position));
}
public void prepare_btn()
{
btn.setTag((Integer) position);
if(is_downloaded() == true)
{
btn.setText("Play ");
btn.setEnabled(true);
btn.setOnClickListener( new OnClickListener()
{
public void onClick(View btn)
{
int position = (Integer) btn.getTag();
Intent i = new Intent(VideosActivity.this, PlayVideoActivity.class);
String video_path = storage_dir + "/" + arr_videos.get(position);
Log.v("video_path", video_path);
i.putExtra("video_path", video_path);
startActivity(i);
}
});
}
else
{
btn.setText("Download ");
btn.setOnClickListener( new OnClickListener()
{
public void onClick(View btn)
{
int position = (Integer) btn.getTag();
btn.setEnabled(false);
//download_video( position, btn );
Download d = new Download();
d.start(position, (Button) btn);
}
});
}
}
}
public class Download
{
File new_video_file;
Button btn; //the progress meter needs to know what button called this. set via setter method below.
int position;
com.amazonaws.services.s3.transfer.Download download;
protected void start(int position, Button btn)
{
this.btn = (Button) btn;
this.position = position;
this.new_video_file = new File(storage_dir, arr_videos.get(position)); //local file to be writtent to
AWSCredentials credentials = new BasicAWSCredentials("xx", "xx" );
TransferManager tx = new TransferManager(credentials);
this.download = tx.download(s3_bucket, s3_dir + arr_videos.get(position), new_video_file);
download.addProgressListener(new ProgressListener()
{
public void progressChanged(final ProgressEvent pe)
{
handler.post( new Runnable()
{
#Override
public void run()
{
if ( pe.getEventCode() == ProgressEvent.COMPLETED_EVENT_CODE )
{
Download.this.onComplete();
}
else
{
Download.this.onProgressUpdate();
}
}
});
}
});
}
//protected void onProgressUpdate(Double progress)
protected void onProgressUpdate()
{
Double progress = this.download.getProgress().getPercentTransfered();
String percent = progress.intValue() + "%";
Log.v("runnable", percent);
btn.setText(percent);
Log.v("dev", progress + "");
}
protected void onComplete()
{
Log.v("dev", "download complete!!!");
set_sdcard_video_data();
adapter.notifyDataSetChanged();
// this.download.abort();
}
}
}
Your Download Thread keeps a reference to the Button. The Buttons get reused though for different list elements when you scroll. You need to find a way to update the Button in the Thread somehow. The Button in the Thread can also be null, when the list element is not visible.
Edit:
It's really not that complicated. First of all: you should use a ViewHolder, that's gonna make your life much easier. Then you could do something like that
#Override
public View getView(final int position, View convertView, ViewGroup view_group) {
View view = null;
ViewHolder holder = null;
if(convertView == null){
view = {inflate view}
view.setTag(holder = new ViewHolder());
holder.view1 = view.findViewById(...);
{get rest of the views}
}else{
view = convertView;
holder = (ViewHolder)view.getTag();
}
if(holder.getDownloadThread() != null){
holder.getDownloadThread().setButton(null);
}
...
}
You get the idea.
I am using a listview in my Android program.
I have row. 1) i have custom row in button and i want to when click button then open the alert box and this row clicked then open the new activity but Only one button clicked not row clicked . how to possible in this case. my code in below.
Thank you.
public class AlMessagesAdapter extends ArrayAdapter<DtoAllMessages> {
private LayoutInflater inflator;
private ArrayList<DtoAllMessages> userlist;
public AlMessagesAdapter(Activity context, ArrayList<DtoAllMessages> list) {
super(context, R.layout.custom_list, list);
this.userlist = list;
inflator = context.getLayoutInflater();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = inflator.inflate(R.layout.custom_list, null);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.tvName);
holder.date_cr = (TextView) convertView.findViewById(R.id.tvDate);
holder.img = (ImageView)convertView.findViewById(R.id.ivIcon);
holder.tokenBtn = (Button)convertView.findViewById(R.id.tokenBtn);
convertView.setTag(holder);
convertView.setTag(R.id.tvName, holder.title);
convertView.setTag(R.id.tvDate, holder.date_cr);
convertView.setTag(R.id.ivIcon,holder.img);
convertView.setTag(R.id.tokenBtn,holder.tokenBtn);
} else {
holder = (ViewHolder) convertView.getTag();
}
String token = userlist.get(position).getToken();
Log.v("MessageList", "token:" + token);
token = token.substring(0,token.length()-3);
holder.title.setText(userlist.get(position).getName()+"("+token+")");
String type_data = userlist.get(position).getType().toString();
if((type_data.equals("text")) || (type_data.equals("photo")))
{
Log.v("log", " if text photo ");
holder.date_cr.setText(userlist.get(position).getType()+":Received "+userlist.get(position).getCreated_date());
holder.tokenBtn.setVisibility(View.VISIBLE);
list.setItemsCanFocus(true);
}
else if(type_data.equals("out"))
{
Log.v("log", " else out ");
holder.date_cr.setText(userlist.get(position).getType()+":Sent "+userlist.get(position).getCreated_date());
holder.tokenBtn.setVisibility(View.GONE);
}
if(type_data.equals("text"))
{
Log.v("log", " if text ");
holder.img.setBackgroundResource(R.drawable.chatmessage);
}
else if(type_data.equals("photo"))
{
Log.v("log", " ese if photo ");
holder.img.setBackgroundResource(R.drawable.photomessage);
}
else if(type_data.equals("out"))
{
Log.v("log", " ese if out ");
holder.img.setBackgroundResource(R.drawable.outmessafe);
}
if(position%2==0)
{
convertView.setBackgroundResource(R.drawable.whitebackground);
}
else
{
convertView.setBackgroundResource(R.drawable.greybackground);
}
holder.tokenBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v("log_tag"," token button clicked");
}
});
return convertView;
}
class ViewHolder {
protected ImageView img;
protected TextView date_cr;
protected TextView title;
protected Button tokenBtn;
}
}
and list click event in below::
list.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
// TODO Auto-generated method stub
msg = userLIstArray.get(position).getMessage();
token = userLIstArray.get(position).getToken();
type = userLIstArray.get(position).getType();
int msgId = userLIstArray.get(position).getMessageid();
token = token.substring(0,token.length()-3);
int token_value = Integer.parseInt(token) * 1000;
if(type.equals("text"))
{
Log.v("log", " if in text to Display " + msg + " token "+token);
Intent i = new Intent(MessagesList.this,DisplayPopupActivity.class);
i.putExtra("msg", msg);
i.putExtra("token", token);
i.putExtra("msgid", msgId);
startActivity(i);
}
else if(type.equals("photo"))
{
Log.v("log", " else in IMage to Display " + msg + " token "+token);
Log.v("log","token "+token+" type "+type + " position "+position + "msgId "+ msgId);
Intent i = new Intent(MessagesList.this,DisplayImageActivity.class);
i.putExtra("imgData", msg);
i.putExtra("token", token);
i.putExtra("msgid", msgId);
startActivity(i);
//Log.v("log"," Message" +message);
//Toast.makeText(AllMessageActivity.this, "Message "+message, Toast.LENGTH_LONG).show();
}
return false;
}
});
}
Try this,
Instead of button use TextView. and the write onclickListerner to TextView. i had face same issue in ListView Button click using textview now its working fine. just try it.
You can add the row click event using:
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, long id) {
//go to new activity
});
And the button event, as you are doing..
holder.tokenBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v("log_tag"," token button clicked");
//show alert
}
});
call your clickevent inside if condition
if (convertView == null) {
convertView = inflator.inflate(R.layout.custom_list, null);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.tvName);
holder.date_cr = (TextView) convertView.findViewById(R.id.tvDate);
holder.img = (ImageView)convertView.findViewById(R.id.ivIcon);
holder.tokenBtn = (Button)convertView.findViewById(R.id.tokenBtn);
holder.tokenBtn.setOnClickListener(click);
}
create clicklistner outside.
private OnClickListener click = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// do your stuff here
}
};
In your Adapter class set an OnclickListner
private LayoutInflater inflator;
private ArrayList<DtoAllMessages> userlist;
private Context context; //added
public AlMessagesAdapter(Activity context, ArrayList<DtoAllMessages> list) {
super(context, R.layout.custom_list, list);
this.context=context; //added
this.userlist = list;
inflator = context.getLayoutInflater();
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = inflator.inflate(R.layout.custom_list, null);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.tvName);
holder.date_cr = (TextView) convertView.findViewById(R.id.tvDate);
holder.img = (ImageView)convertView.findViewById(R.id.ivIcon);
holder.tokenBtn = (Button)convertView.findViewById(R.id.tokenBtn);
holder.tokenBtn.setOnClickListener((OnClickListener)context); //added portion
convertView.setTag(holder);
convertView.setTag(R.id.tvName, holder.title);
convertView.setTag(R.id.tvDate, holder.date_cr);
convertView.setTag(R.id.ivIcon,holder.img);
convertView.setTag(R.id.tokenBtn,holder.tokenBtn);
} else {
holder = (ViewHolder) convertView.getTag();
}
String token = userlist.get(position).getToken();
Log.v("MessageList", "token:" + token);
token = token.substring(0,token.length()-3);
holder.title.setText(userlist.get(position).getName()+"("+token+")");
String type_data = userlist.get(position).getType().toString();
if((type_data.equals("text")) || (type_data.equals("photo")))
{
Log.v("log", " if text photo ");
holder.date_cr.setText(userlist.get(position).getType()+":Received "+userlist.get(position).getCreated_date());
holder.tokenBtn.setVisibility(View.VISIBLE);
list.setItemsCanFocus(true);
}
else if(type_data.equals("out"))
{
Log.v("log", " else out ");
holder.date_cr.setText(userlist.get(position).getType()+":Sent "+userlist.get(position).getCreated_date());
holder.tokenBtn.setVisibility(View.GONE);
}
if(type_data.equals("text"))
{
Log.v("log", " if text ");
holder.img.setBackgroundResource(R.drawable.chatmessage);
}
else if(type_data.equals("photo"))
{
Log.v("log", " ese if photo ");
holder.img.setBackgroundResource(R.drawable.photomessage);
}
else if(type_data.equals("out"))
{
Log.v("log", " ese if out ");
holder.img.setBackgroundResource(R.drawable.outmessafe);
}
if(position%2==0)
{
convertView.setBackgroundResource(R.drawable.whitebackground);
}
else
{
convertView.setBackgroundResource(R.drawable.greybackground);
}
/*holder.tokenBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v("log_tag"," token button clicked");
}
});*/
return convertView;
}
class ViewHolder {
protected ImageView img;
protected TextView date_cr;
protected TextView title;
protected Button tokenBtn;
}
}
And into your Main class
public Main extends Activity implements OnClickListener{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.casual_layout);
Button tokenBtn=(Button)findViewById(R.id.tokenBtn);
tokenBtn.setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.tokenBtn:
//Write a code here to execute alertdialog
Log.d("ALERT HERE","ALERT HERE");
break;
}
}
If you want to use a Button instead of a TextView set
android:focusable="false"
to your Button
I have a ListView inside an Activity and each of its item is customized to have some TextViews along with a DropDownList item and an ImageView. Inside an OnScrollListener() implementation each item of a listView gets populated using an ArrayAdapter populating text views with values taken from an arrayList and ImageView with the .jpeg file stored on SD card. Following is the screenSHot of listView Item
The problem arises when the .jpeg file from sdCard is converted to a bitmap (i.e. BitmapFactory.decodeFile(fileName) ) and then gets assigned to an image View using setImageBitmap(Bitmap bmp). As the setting bitmap image to an image view is a lengthy process it cannot keep pace with the scroll listener implementation and the ImageView of different ListView rows gets populated with the image it was assigned to any row above. Can anybody please suggest some workout to cater this issue specifically the assignment of images from SD Card to an imageView. Its not like my listView item is overLoaded with controls that is why i am facing this problem. I also have tried it with single ImageView item inside each row and it behaves the same way. Your suggestion to improvise this are welcome and surely will be of great help. Thank you :-)
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
AssetDetailHolder assetDetailholder = null;
try {
if (row == null) {
LayoutInflater inflator = ((Activity) context)
.getLayoutInflater();
row = inflator.inflate(layoutResourceID, parent, false);
assetDetailholder = new AssetDetailHolder();
assetDetailholder.itemPosition = position;
assetDetailholder.txtVwlineCOde = (TextView) row
.findViewById(R.id.lineCodeValue_ad);
assetDetailholder.txtvwLocation = (TextView) row
.findViewById(R.id.locationValue_ad);
assetDetailholder.txtvwLocationDetail = (TextView) row
.findViewById(R.id.detailLocationValue_ad);
assetDetailholder.txtvwInventoryNo = (TextView) row
.findViewById(R.id.InventoryNoValue_ad);
assetDetailholder.spnrconditionCode = (Spinner) row
.findViewById(R.id.spinner_ad);
assetDetailholder.txtvwAssetName = (TextView) row
.findViewById(R.id.AssetNameValue_ad);
assetDetailholder.subNoThumbnail = (ImageView) row
.findViewById(R.id.IV_subNoThumbnail);
row.setTag(assetDetailholder);
} else {
assetDetailholder = (AssetDetailHolder) row.getTag();
assetDetailholder.itemPosition = position;
}
AssetDetail assetDetail = assetsDetailList[position];
new ThumbnailTask(position, assetDetailholder, assetDetail, context)
.execute();
if (assetDetail.assetLineCodeDesc.equals("")) {
assetDetailholder.txtVwlineCOde
.setText(assetDetail.strLineCOde);
} else {
assetDetailholder.txtVwlineCOde.setText(assetDetail.strLineCOde
+ "(" + assetDetail.assetLineCodeDesc + ")");
}
if (assetDetail.assetLocationNameDesc.equals("")) {
assetDetailholder.txtvwLocation
.setText(assetDetail.strLocationName);
} else {
assetDetailholder.txtvwLocation
.setText(assetDetail.strLocationName + "("
+ assetDetail.assetLocationNameDesc + ")");
}
assetDetailholder.txtvwLocationDetail
.setText(assetDetail.strLocationDetail);
if (assetDetail.strInventoryNumber.contains("-")) {
assetDetailholder.txtvwInventoryNo
.setText(assetDetail.strInventoryNumber.split("-")[0]);
} else {
assetDetailholder.txtvwInventoryNo
.setText(assetDetail.strInventoryNumber);
}
assetDetailholder.txtvwAssetName.setText(assetDetail.assetName);
String conditionCodeString = assetDetail.assetConditionCode;
if (conditionCodeString != "" || conditionCodeString != null) {
try {
int conditionCodeInteger = Integer
.parseInt(conditionCodeString);
assetDetailholder.spnrconditionCode
.setSelection(conditionCodeInteger);
} catch (Exception e) {
assetDetailholder.spnrconditionCode.setSelection(0);
}
} else {
assetDetailholder.spnrconditionCode.setSelection(0);
}
// String thumbnailDir = Common
// .getSubNoDirectory(context, assetDetail);
// if (new File(thumbnailDir).isDirectory()) {
//
// File thumbnailFile = new File(Common.getSubNoImgFilePath(
// thumbnailDir, assetDetail, SubNo_ImageSample.A));
//
// if (thumbnailFile.exists()) {
// assetDetailholder.subNoThumbnail
// .setImageBitmap(BitmapFactory
// .decodeFile(thumbnailFile.getAbsolutePath()));
// }
// }
} catch (Exception e) {
e.printStackTrace();
}
return row;
}
static class AssetDetailHolder {
TextView txtVwlineCOde;
TextView txtvwLocation;
TextView txtvwLocationDetail;
TextView txtvwInventoryNo;
TextView txtvwAssetName;
Spinner spnrconditionCode;
ImageView subNoThumbnail;
public int itemPosition;
}
private static class ThumbnailTask extends AsyncTask<Void, Void, Void> {
private int mPosition;
private AssetDetailHolder mHolder;
private Context cntxt;
private AssetDetail assetItem;
private Bitmap thumbnailBmp;
public ThumbnailTask(int position, AssetDetailHolder holder,
AssetDetail asset, Context context) {
mPosition = position;
mHolder = holder;
assetItem = asset;
cntxt = context;
}
#Override
protected Void doInBackground(Void... params) {
String thumbnailDir = Common.getSubNoDirectory(cntxt, assetItem);
if (new File(thumbnailDir).isDirectory()) {
File thumbnailFile = new File(Common.getSubNoImgFilePath(
thumbnailDir, assetItem, SubNo_ImageSample.A));
if (thumbnailFile.exists()) {
thumbnailBmp = BitmapFactory.decodeFile(thumbnailFile
.getAbsolutePath());
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (mHolder.itemPosition == mPosition && thumbnailBmp != null) {
mHolder.subNoThumbnail.setImageBitmap(thumbnailBmp);
}
// super.onPostExecute(result);
}
}
http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
This will be hopefull to you :P