I have created a gridview, which shows videos from server. GridItem has video thumb image, and video duration.for loading video's thumb I am using UniversalImageloader and loading video duration by creating lazyloading using asynctask.Lazyloading works fine. but if someone scrolls gridview freequently,then video duration shows at wrong position. for creating Lazyloading I am following bellow link
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final TextView durationTextView;
View view = null;
if (convertView == null) {
view = mInflater.inflate(R.layout.camera_roll_item, parent, false);
MediaItemViewHolder mediaItemViewHolder = new MediaItemViewHolder();
mediaItemViewHolder.highlightTagIcon = (ImageView) view.findViewById(R.id.iv_media_grid_item_highlight_tag);
mediaItemViewHolder.mediaTypeIcon = (ImageView) view.findViewById(R.id.iv_media_grid_item_type);
mediaItemViewHolder.mediaClipLength = (TextView) view.findViewById(R.id.tv_media_grid_item_length);
mediaItemViewHolder.mediaThumbnail = (ImageView) view.findViewById(R.id.iv_media_grid_item_thumbnail);
mediaItemViewHolder.cameraItemSelectedView = (RelativeLayout) view.findViewById(R.id.rl_item_selection_parent);
mediaItemViewHolder.progressContainer = (RelativeLayout) view.findViewById(R.id.rl_grid_loader_parent);
view.setTag(mediaItemViewHolder);
} else {
view = convertView;//(MediaItemViewHolder) convertView.getTag();
//mediaItemViewHolder.mediaClipLength.setText("");
Log.i(TAG, "set blank to ");
}
MediaItemViewHolder mediaItemViewHolder = (MediaItemViewHolder) convertView.getTag();
durationTextView = mediaItemViewHolder.mediaClipLength;
if (position >= mCameraMediaItems.size()) {
Log.d(TAG, "Index out of Bound, position:" + position + " - mCameraMediaItems.size():" + mCameraMediaItems.size());
return convertView;
}
MediaItemBean mediaItemBean = CameraMediaController.getInstance().getMediaItemByPosition(position);
mediaItemViewHolder.mediaClipLength.setVisibility(View.VISIBLE);
mediaItemViewHolder.highlightTagIcon.setVisibility(View.GONE);
if (mediaItemBean != null && mediaItemBean.getCameraMedia() != null) {
switch (mediaItemBean.getCameraMedia().getType()) {
case AppConstant.MEDIA_TYPE_VIDEO:
mediaItemViewHolder.mediaTypeIcon.setImageResource(R.drawable.icn_thumb_vid);
//VideoInfoAsyncTask loads data in this list
int videoDuration = mediaItemBean.getVideoDuration();
//mediaItemViewHolder.mediaClipLength.setTag(CameraMediaUtil.convertSecondsTimeToMinutesString(videoDuration));
Log.i(TAG, "VideoDuration " + videoDuration);
String resId = mediaItemBean.getCreatedId()+"video_media_duration_com.gopro.buckhorn";
Log.i(TAG, "RESID "+resId);
downloadDuration(resId, durationTextView, mediaItemViewHolder.highlightTagIcon, mediaItemBean);
break;
case MULTI_PHOTO:
String mulCount = String.valueOf(Controller.getInstance().getPhotoCountAtPosition(position));
Log.i("MULTI_SHOT_SECTION", "MultiShot "+mulCount);
mediaItemViewHolder.mediaTypeIcon.setImageResource(R.drawable.icn_thumb_burst);
mediaItemViewHolder.mediaClipLength.setText(mulCount);
break;
}
//Load image into image view from URL
String imageUri = mediaItemBean.getThumbnailUri().toString();
Log.i(TAG, "Thumb url :" + imageUri);
mediaItemViewHolder.progressContainer.setVisibility(View.VISIBLE);
DownloadImageUtil.getLoadImageInsatnce().downloadGridImage(imageUri,
mediaItemViewHolder.mediaThumbnail, R.drawable.thumb_load, mediaItemViewHolder.progressContainer);
}
return convertView;
}
private void downloadDuration(String resId, TextView textView, ImageView highlightTagIcon, MediaItemBean mediaItemBean) {
String duration = getVideoDurationFromCache(String.valueOf(resId));
Log.i(TAG, "downloadDuration " + duration);
if (duration == null) {
loadVideoDuration(resId, textView, highlightTagIcon, mediaItemBean);
textView.setText("");
} else {
cancelVideoDurationDownloaderTask(resId, textView);
if(mediaItemBean.getCameraMedia().getType() == AppConstant.MEDIA_TYPE_VIDEO){
textView.setText(duration);
if (mediaItemBean.isIsHighLightTags()) {
highlightTagIcon.setVisibility(View.VISIBLE);
}
}
}
}
private String getVideoDurationFromCache(String key) {
// First try the hard reference cache
synchronized (mMemoryCache) {
final String duration = mMemoryCache.get(key);
if (duration != null) {
// Bitmap found in hard cache
// Move element to first position, so that it is removed last
mMemoryCache.remove(key);
mMemoryCache.put(key, duration);
return duration;
}
}
return null;
}
private static class MediaItemViewHolder {
ImageView highlightTagIcon, mediaTypeIcon, mediaThumbnail;
TextView mediaClipLength;
RelativeLayout cameraItemSelectedView;
/* ProgressBar innerProgressBar;
ProgressBar outerProgressBar;*/
RelativeLayout progressContainer;
}
public class VideoDurationDownloaderTask extends AsyncTask<String, Void, String> {
private final WeakReference<TextView> videoDurationReference;
private final WeakReference<ImageView> hiliteTagImageViewWeakReference;
private String data = "";
private MediaItemBean mediaItemBean;
public VideoDurationDownloaderTask(TextView textView, ImageView hiliteTagIcon, MediaItemBean mediaItemBean) {
this.mediaItemBean = mediaItemBean;
videoDurationReference = new WeakReference<>(textView);
hiliteTagImageViewWeakReference = new WeakReference<>(hiliteTagIcon);
}
#Override
protected String doInBackground(String... params) {
data = params[0];
Log.i(TAG, "data in task "+data);
return downloadVideoDuration(mediaItemBean);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (isCancelled()) {
Log.i(TAG, "isCancelled " + result);
result = "";
}
addDurationToMemoryCache(data, result);
//noinspection ConstantConditions
if (videoDurationReference != null) {
TextView videoDuration = videoDurationReference.get();
Log.i(TAG, "videoDuration " + videoDuration);
VideoDurationDownloaderTask videoDurationDownloaderTask =
getTextViewDerationWorkerTask(videoDuration);
Log.i(TAG, "videoDurationDownloaderTask " + videoDurationDownloaderTask);
if (videoDuration != null) {
if (this == videoDurationDownloaderTask) {
if(mediaItemBean.getCameraMedia().getType() == AppConstant.MEDIA_TYPE_VIDEO) {
Log.i(TAG, "TAG VAL "+videoDuration.getTag());
videoDuration.setText(result);
videoDuration.setTag(new TextView(context));
if (mediaItemBean.isIsHighLightTags()) {
ImageView highlightTagIcon = hiliteTagImageViewWeakReference.get();
if (highlightTagIcon != null)
highlightTagIcon.setVisibility(View.VISIBLE);
}
}
}
}
}
}
}
private String downloadVideoDuration(MediaItemBean mediaItemBean) {
try {
if (media != null && mediaItemBean.getMedia() != null) {
int videoDuration = mediaItemBean.getVideoDuration();
Log.i(TAG, "Video has duration = " + videoDuration);
if (videoDuration == -1) {
CommandResult<Integer> duration =
media.getVideoDuration(mediaItemBean.getCameraMedia().getFilePath());
videoDuration = duration.getData();
mediaItemBean.setVideoDuration(videoDuration);
Log.i(TAG, "set Video Duration " + videoDuration);
}
return MediaUtil.convertSecondsTimeToMinutesString(videoDuration);
}
} catch (Exception e) {
Log.e(TAG, "Exception Occure while Getting video info:" + e.getMessage());
}
Log.i(TAG, "not fetch duration ");
return "";
}
public void loadVideoDuration(String resId, TextView textView, ImageView hiliteTagIcon, MediaItemBean mediaItemBean) {
if (cancelVideoDurationDownloaderTask(resId, textView)) {
final VideoDurationDownloaderTask task = new VideoDurationDownloaderTask(textView, hiliteTagIcon, mediaItemBean);
AsyncTextView asyncTextView = new AsyncTextView(context, task);
textView.setTag(asyncTextView);
task.execute(resId);
}
}
private boolean cancelVideoDurationDownloaderTask(String data, TextView textView) {
final VideoDurationDownloaderTask durationWorkerTask = getTextViewDerationWorkerTask(textView);
if (durationWorkerTask != null) {
final String textViewData = durationWorkerTask.data;
Log.i(TAG, textViewData + " textViewDataData, data " + data);
if (data != null && !textViewData.equalsIgnoreCase(data)) {
// Cancel previous task
Log.i(TAG, "Cancel previous task " + data);
durationWorkerTask.cancel(true);
} else {
// The same work is already in progress
Log.i(TAG, "same work is already in progress " + false);
return false;
}
}
// No task associated with the ImageView, or an existing task was
// cancelled
Log.i(TAG, "cancelVideoDurationDownloaderTask true");
return true;
}
static class AsyncTextView extends TextView {
private final WeakReference<VideoDurationDownloaderTask> textviewWorkerTaskReference;
public AsyncTextView(Context context, VideoDurationDownloaderTask textviewWorkerTask) {
super(context);
textviewWorkerTaskReference = new WeakReference<>(textviewWorkerTask);
}
public VideoDurationDownloaderTask getTextViewWorkerTask() {
return textviewWorkerTaskReference.get();
}
}
private static VideoDurationDownloaderTask getTextViewDerationWorkerTask(TextView textView) {
if(textView.getTag() != null){
Log.i(TAG, " textView.getTag() " + textView.getTag());
if (textView.getTag() instanceof AsyncTextView) {
Log.i(TAG, " Return Textview task");
final AsyncTextView asyncTextView = (AsyncTextView) textView.getTag();
return asyncTextView.getTextViewWorkerTask();
}
}
return null;
}
public void addDurationToMemoryCache(String key, String duration) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, duration);
}
}
Get rid of view and use convertView as you receive from method. Change to the following
//final is optional but if you need to use in thread
final MediaItemViewHolder mediaItemViewHolder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.camera_roll_item, parent, false);
mediaItemViewHolder = new MediaItemViewHolder();
mediaItemViewHolder.highlightTagIcon = (ImageView) convertView.findViewById(R.id.iv_media_grid_item_highlight_tag);
mediaItemViewHolder.mediaTypeIcon = (ImageView) convertView.findViewById(R.id.iv_media_grid_item_type);
mediaItemViewHolder.mediaClipLength = (TextView) convertView.findViewById(R.id.tv_media_grid_item_length);
mediaItemViewHolder.mediaThumbnail = (ImageView) convertView.findViewById(R.id.iv_media_grid_item_thumbnail);
mediaItemViewHolder.cameraItemSelectedView = (RelativeLayout) convertView.findViewById(R.id.rl_item_selection_parent);
mediaItemViewHolder.progressContainer = (RelativeLayout) convertView.findViewById(R.id.rl_grid_loader_parent);
convertView.setTag(mediaItemViewHolder);
} else {
mediaItemViewHolder = (MediaItemViewHolder)convertView.getTag();
Log.i(TAG, "set blank to ");
}
Now use mediaItemViewHolder.durationTextView.setText(....)
Update 1: I have figured out the problem. Why lazyloading update video duration at wrong gridview position. Discard the above if you want
downloadDuration(resId, durationTextView, mediaItemViewHolder.highlightTagIcon, mediaItemBean);
is the culprit. downloadDuration runs in async mode and it has the reference of durationTextView in before hand. Suppose the downloadDuration is not finished and user scrolls the ListView. After scrolling the ListView downloadDuration is finished, then this durationTextView will be updated with the value but for the wrong ListView item position and not for which position this was passed in downloadDuration. Making final TextView durationTextView;
it as final will also not solve the problem.
Solution could be to show some kind of empty indicatior for duration and let the downloadDuration finishes it's async job. Remove durationTextView as a parameter and add position as a parameter. After async job is done, you can update the bean list of type MediaItemBean for that position. Now notify the adapter that some value has been changed and the ListView will update itself accordingly. FYI RecyclerView item update is more optimised than ListView.
Update 2: You can fetch the items in advance and just map it to bean. Only one time async will run.
Update 3: In the meantime you can check bean for the particular ListView item if it is 0 or not. If it is 0 show in the durationTextView.setText("00:00:00") else call downloadDuration and let it finish and update the duration value in bean. But still you need to notify for updating item.
Related
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder helper = null;
Log.i("StaggeredGridView--Adapter:", "position:" + position);
if(convertView ==null){
helper = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_user_details_adapter, null);
helper.tv_content = (EmojiconTextView) convertView.findViewById(R.id.txt_content);
helper.tv_time = (TextView) convertView.findViewById(R.id.txt_time);
helper.tv_zannum = (TextView) convertView.findViewById(R.id.tv_zan_num);
helper.tv_plnum = (TextView) convertView.findViewById(R.id.tv_pl_num);
helper.iv_show = (DynamicHeightImageView) convertView.findViewById(R.id.img_content);// 展示的图片
helper.img_zan = (ImageView) convertView.findViewById(R.id.img_normal);// 已经赞过的改颜色。
helper.rel_photo = (RelativeLayout) convertView.findViewById(R.id.rel_photo);
convertView.setTag(helper);
} else {
helper = (ViewHolder) convertView.getTag();
}
double positionHeight = getPositionRatio(position);
Log.d(TAG, "getView position:" + position + " h:" + positionHeight);
helper.iv_show.setHeightRatio(positionHeight);
String imgeurl = "";
List<Map<String, String>> listget = mUserInfors.get(position).getmAttach();
if (listget != null && listget.size() > 0) {
for (int i = 0; i < listget.size(); i++) {
Map<String, String> map = listget.get(i);
if (map != null) {
if (map.get("attach_middle") != null) {
imgeurl = map.get("attach_middle");
if (!TextUtils.isEmpty(imgeurl)) {
break;
}
}
}
}
}
List<Map<String, String>> diggerlist = mUserInfors.get(position).getDigger_list();
if (diggerlist.size() > 0) {
helper.tv_zannum.setText(diggerlist.size() + "");
boolean state = getCheckstate(diggerlist);
if (state) {
helper.img_zan.setImageDrawable(mContext.getResources().getDrawable(R.drawable.zan));
} else {
helper.img_zan.setImageDrawable(mContext.getResources().getDrawable(R.drawable.normalzan));
}
} else {
helper.img_zan.setImageDrawable(mContext.getResources().getDrawable(R.drawable.normalzan));
}
if (!TextUtils.isEmpty(imgeurl)) {
ImageLoader.getInstance().displayImage(imgeurl, helper.iv_show, mDisplayOption);
} else {
helper.iv_show.setImageDrawable(mContext.getResources().getDrawable(R.drawable.empty_activity_icon));
}
String content = mUserInfors.get(position).getContent();
String time = mUserInfors.get(position).getCtime();
helper.tv_time.setText(time.substring(5));
helper.tv_zannum.setText(mUserInfors.get(position).getDigg_count());
helper.tv_plnum.setText(mUserInfors.get(position).getComment_count());
helper.tv_content.setText(content);
if (mUserInfors.get(position).getType().equals("post")) {
helper.rel_photo.setVisibility(View.GONE);
helper.tv_content.setVisibility(View.VISIBLE);
} else {
if (TextUtils.isEmpty(content)) {
helper.tv_content.setVisibility(View.GONE);
} else {
helper.tv_content.setVisibility(View.VISIBLE);
}
helper.rel_photo.setVisibility(View.VISIBLE);
}
return convertView;
}
Above is the code of getview, I was in the use of staggeredgridview Etsy ,when I scroll the screen,this problem is occurs, a time when the position is out of confusion, as if the location of the position did not be remembered.
The following is a screenshot of position getview:
This issue comes only if you are not controlling getCount() and getItem() methods. Make sure that you are returning your list size as in getCount() like this :
#Override
public int getCount() {
return list.size();
}
and getItem() as :
#Override
public SetterGetterClassName getItem(int position) {
return list.get(position);
}
This is my complete code :
enter code here
public class UserDetailsAdapter2 extends BaseAdapter {
//private HashMap<Integer, View> viewMap;
private DisplayImageOptions mDisplayOption = new DisplayImageOptions.Builder().cacheInMemory(true).cacheOnDisc(true)
.showStubImage(R.drawable.empty_activity_icon).showImageForEmptyUri(R.drawable.empty)
.showImageOnFail(R.drawable.empty_activity_icon).imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.RGB_565).displayer(new FadeInBitmapDisplayer(400)).considerExifParams(true)
.build();
private Context mContext;
private List<CellQzones> mUserInfors;
private UserInfor mUser;
private String TAG = "UserDetailsAdapter2";
private final Random mRandom;
private static final SparseArray<Double> sPositionHeightRatios = new SparseArray<Double>();
//private ImageLoader2 mImageLoader2;
public UserDetailsAdapter2(Context context, List<CellQzones> mDatas, UserInfor user) {
mContext = context;
mUserInfors = mDatas;
mUser = user;
mRandom = new Random();
//viewMap=new HashMap<Integer, View>();
}
#Override
public int getCount() {
return mUserInfors.size();
}
#Override
public Object getItem(int position) {
return mUserInfors.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder helper = null;
Log.i("StaggeredGridView--Adapter:", "position:" + position);
// if(!viewMap.containsKey(position) || viewMap.get(position) == null){
if(convertView ==null){
helper = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_user_details_adapter, null);
helper.tv_content = (EmojiconTextView) convertView.findViewById(R.id.txt_content);
helper.tv_time = (TextView) convertView.findViewById(R.id.txt_time);
helper.tv_zannum = (TextView) convertView.findViewById(R.id.tv_zan_num);
helper.tv_plnum = (TextView) convertView.findViewById(R.id.tv_pl_num);
helper.iv_show = (DynamicHeightImageView) convertView.findViewById(R.id.img_content);// 展示的图片
helper.img_zan = (ImageView) convertView.findViewById(R.id.img_normal);// 已经赞过的改颜色。
helper.rel_photo = (RelativeLayout) convertView.findViewById(R.id.rel_photo);
convertView.setTag(helper);
} else {
//convertView = viewMap.get(position);
helper = (ViewHolder) convertView.getTag();
}
double positionHeight = getPositionRatio(position);
Log.d(TAG, "getView position:" + position + " h:" + positionHeight);
helper.iv_show.setHeightRatio(positionHeight);
String imgeurl = "";
List<Map<String, String>> listget = mUserInfors.get(position).getmAttach();
if (listget != null && listget.size() > 0) {
for (int i = 0; i < listget.size(); i++) {
Map<String, String> map = listget.get(i);
if (map != null) {
if (map.get("attach_middle") != null) {
imgeurl = map.get("attach_middle");
if (!TextUtils.isEmpty(imgeurl)) {
break;
}
}
}
}
}
List<Map<String, String>> diggerlist = mUserInfors.get(position).getDigger_list();
if (diggerlist.size() > 0) {
helper.tv_zannum.setText(diggerlist.size() + "");
boolean state = getCheckstate(diggerlist);
if (state) {
helper.img_zan.setImageDrawable(mContext.getResources().getDrawable(R.drawable.zan));
} else {
helper.img_zan.setImageDrawable(mContext.getResources().getDrawable(R.drawable.normalzan));
}
} else {
helper.img_zan.setImageDrawable(mContext.getResources().getDrawable(R.drawable.normalzan));
}
if (!TextUtils.isEmpty(imgeurl)) {
//mImageLoader2.loadImage(imgeurl,helper.iv_show, true);
ImageLoader.getInstance().displayImage(imgeurl, helper.iv_show, mDisplayOption);
} else {
helper.iv_show.setImageDrawable(mContext.getResources().getDrawable(R.drawable.empty_activity_icon));
}
String content = mUserInfors.get(position).getContent();
String time = mUserInfors.get(position).getCtime();
helper.tv_time.setText(time.substring(5));
helper.tv_zannum.setText(mUserInfors.get(position).getDigg_count());
helper.tv_plnum.setText(mUserInfors.get(position).getComment_count());
helper.tv_content.setText(content);
if (mUserInfors.get(position).getType().equals("post")) {
helper.rel_photo.setVisibility(View.GONE);
helper.tv_content.setVisibility(View.VISIBLE);
} else {
if (TextUtils.isEmpty(content)) {
helper.tv_content.setVisibility(View.GONE);
} else {
helper.tv_content.setVisibility(View.VISIBLE);
}
helper.rel_photo.setVisibility(View.VISIBLE);
}
return convertView;
}
public class ViewHolder {
EmojiconTextView tv_content;
TextView tv_time;
TextView tv_zannum;
TextView tv_plnum;
DynamicHeightImageView iv_show;
ImageView img_zan;
RelativeLayout rel_photo;
}
private double getPositionRatio(final int position) {
double ratio = sPositionHeightRatios.get(position, 0.0);
// if not yet done generate and stash the columns height
// in our real world scenario this will be determined by
// some match based on the known height and width of the image
// and maybe a helpful way to get the column height!
if (ratio == 0) {
ratio = getRandomHeightRatio();
sPositionHeightRatios.append(position, ratio);
Log.d(TAG, "getPositionRatio:" + position + " ratio:" + ratio);
}
return ratio;
}
private double getRandomHeightRatio() {
return (mRandom.nextDouble() / 2.0) + 1.0; // height will be 1.0 - 1.5
// the width
}
/** 得到checkbox的赞的状态 **/
private boolean getCheckstate(List<Map<String, String>> diggerlist) {
for (int i = 0; i < diggerlist.size(); i++) {
Map<String, String> mp = diggerlist.get(i);
String uid = mUser.getUid();
String mUid = mp.get("uid");
// 如果有就设置true。
if (uid.equals(mUid)) {
return true;
}
}
return false;
}
}
I am trying to build a demo chatting App.I want to show the messages with section headers as Dates like "Today","Yesterday","May 21 2015" etc.I have managed to achieve this but since the new View method gets called whenever I scroll the list.The headers and messages get mixed up.
For simplicity, I have kept the header in the layouts itself and changing its visibility(gone and visible) if the date changes.
Can you help me out with this? Let me know if anyone needs any more info to be posted in the question.
public class ChatssAdapter extends CursorAdapter {
private Context mContext;
private LayoutInflater mInflater;
private Cursor mCursor;
private String mMyName, mMyColor, mMyImage, mMyPhone;
// private List<Contact> mContactsList;
private FragmentActivity mActivity;
private boolean mIsGroupChat;
public ChatssAdapter(Context context, Cursor c, boolean groupChat) {
super(context, c, false);
mContext = context;
mMyColor = Constants.getMyColor(context);
mMyName = Constants.getMyName(context);
mMyImage = Constants.getMyImageUrl(context);
mMyPhone = Constants.getMyPhone(context);
mIsGroupChat = groupChat;
mCursor = c;
// mActivity = fragmentActivity;
/*try {
mContactsList = PinchDb.getHelper(mContext).getContactDao().queryForAll();
} catch (SQLException e) {
e.printStackTrace();
}*/
}
#Override
public int getItemViewType(int position) {
Cursor cursor = (Cursor) getItem(position);
return getItemViewType(cursor);
}
private int getItemViewType(Cursor cursor) {
boolean type;
if (mIsGroupChat)
type = cursor.getString(cursor.getColumnIndex(Chat.COLMN_CHAT_USER)).compareTo(mMyPhone) == 0;
else type = cursor.getInt(cursor.getColumnIndex(Chat.COLMN_FROM_ME)) > 0;
if (type) {
return 0;
} else {
return 1;
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = null;
int itemViewType = getItemViewType(cursor);
if (v == null) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (itemViewType == 0) {
v = mInflater.inflate(R.layout.row_chat_outgoing, parent, false);
} else {
v = mInflater.inflate(R.layout.row_chat_incoming, parent, false);
}
}
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = new ViewHolder();
View v = view;
final Chat chat = new Chat(cursor);
boolean fromMe = mIsGroupChat ? chat.getUser().compareTo(mMyPhone) == 0 : chat.isFrom_me();
if (fromMe) {
// LOGGED IN USER'S DATA SETTING....
holder.chat_name = (StyleableTextView) v
.findViewById(R.id.chat_user_name);
holder.chat_time = (StyleableTextView) v
.findViewById(R.id.chat_time);
holder.chat_tag = (StyleableTextView) v
.findViewById(R.id.chat_tag);
int color = Color.parseColor("#FFFFFF");
v.setBackgroundColor(color);
holder.chat_name.setText("#You");
holder.chat_time.setText(AppUtil.getEventTime(chat.getTimestampLong()));
// header text setting and process..
holder.chat_header_text = (TextView) v.findViewById(R.id.header_text);
String str_date = AppUtil.covertToDate(chat.getTimestampLong());
String pref_date = SharePreferencesUtil.getSharedPreferencesString(mContext, Constants.CHAT_TIMESTAMP, "");
if (!str_date.equalsIgnoreCase(pref_date)) {
holder.chat_header_text.setVisibility(View.VISIBLE);
SharePreferencesUtil.putSharedPreferencesString(mContext, Constants.CHAT_TIMESTAMP, str_date);
holder.chat_header_text.setText(str_date);
} else {
holder.chat_header_text.setVisibility(View.GONE);
}
String firstWord, theRest;
String mystring = chat.getText();
String arr[] = mystring.split(" ", 2);
if (arr.length > 1) {
firstWord = arr[0]; // the word with hash..
theRest = arr[1]; // rest of the body..
holder.chat_tag.setText(Html.fromHtml("<font color=\"#999999\"><b>" + firstWord + "</b></font>" + " " + "<font color=\"#000000\">" + theRest + "</font>"));
// holder.chat_text.setText(theRest);
// holder.chat_text.setClickable(false);
} else {
String msg = arr[0]; // the word with hash..
holder.chat_tag.setText(Html.fromHtml("<font color=\"#999999\"><b>" + msg + "</b></font>"));
//holder.chat_text.setText("");
}
updateTimeTextColorAsPerStatus(holder.chat_time, chat.getStatus());
v.setTag(holder);
} else {
// OTHER USER'S DATA SETTING....
holder.chat_name = (StyleableTextView) v
.findViewById(R.id.chat_user_name);
holder.chat_time = (StyleableTextView) v
.findViewById(R.id.chat_time);
holder.chat_tag = (StyleableTextView) v
.findViewById(R.id.chat_tag);
holder.chat_image = (ImageView) v
.findViewById(R.id.chat_profile_image);
String image = cursor.getString(cursor.getColumnIndex("image"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String color = cursor.getString(cursor.getColumnIndex("color"));
// set the values...
if (holder.chat_image != null) {
MImageLoader.displayImage(context, image, holder.chat_image, R.drawable.round_user_place_holder);
}
int back_color = Color.parseColor("#FFFFFF");
v.setBackgroundColor(back_color);
holder.chat_name.setText(name);
holder.chat_time.setText(AppUtil.getEventTime(chat.getTimestampLong()));
// header text setting and process..
holder.chat_header_text = (TextView) v.findViewById(R.id.header_text);
String str_date = AppUtil.covertToDate(chat.getTimestampLong());
String pref_date = SharePreferencesUtil.getSharedPreferencesString(mContext, Constants.CHAT_TIMESTAMP, "");
Log.d("eywa", "str date is ::::: " + str_date + " pref date is :::::: " + pref_date);
/*if (!TextUtils.isEmpty(pref_date)) {
if (!pref_date.contains(str_date)) {
holder.chat_header_text.setVisibility(View.VISIBLE);
SharePreferencesUtil.putSharedPreferencesString(mContext, Constants.CHAT_TIMESTAMP, pref_date + str_date);
holder.chat_header_text.setText(str_date);
} else {
holder.chat_header_text.setVisibility(View.GONE);
}
} else {
holder.chat_header_text.setVisibility(View.VISIBLE);
SharePreferencesUtil.putSharedPreferencesString(mContext, Constants.CHAT_TIMESTAMP, pref_date + str_date);
holder.chat_header_text.setText(str_date);
}*/
if (!str_date.equalsIgnoreCase(pref_date)) {
holder.chat_header_text.setVisibility(View.VISIBLE);
SharePreferencesUtil.putSharedPreferencesString(mContext, Constants.CHAT_TIMESTAMP, str_date);
holder.chat_header_text.setText(str_date);
} else {
holder.chat_header_text.setVisibility(View.GONE);
}
String firstWord, theRest;
String mystring = chat.getText();
String arr[] = mystring.split(" ", 2);
if (arr.length > 1) {
firstWord = arr[0]; // the word with hash..
theRest = arr[1]; // rest of the body..
holder.chat_tag.setText(Html.fromHtml("<font color=\"#999999\"><b>" + firstWord + "</b></font>" + " " + "<font color=\"#000000\">" + theRest + "</font>"));
// holder.chat_text.setClickable(false);
} else {
String msg = arr[0]; // the word with hash..
holder.chat_tag.setText(Html.fromHtml("<font color=\"#999999\"><b>" + msg + "</b></font>"));
// holder.chat_text.setText("");
}
String phone = cursor.getString(cursor.getColumnIndex("user"));
final Contact contact = new Contact(name, phone, "", color, image);
if (holder.chat_image != null) {
holder.chat_image.setTag(contact);
// holder.chat_name.setTag(contact);
holder.chat_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Contact con = (Contact) v.getTag();
Intent intent = new Intent(mContext, OtherProfileActivity.class);
intent.putExtra(Constants.EXTRA_CONTACT, con);
mContext.startActivity(intent);
}
});
}
v.setTag(holder);
}
/*else
{
view=
}*/
}
private void updateTimeTextColorAsPerStatus(TextView chat_time, int status) {
if (status == 0) chat_time.setVisibility(View.INVISIBLE);
else {
chat_time.setVisibility(View.VISIBLE);
/* if (status == 1)
chat_time.setTextColor(mContext.getResources().getColor(android.R.color.white));*/
if (status == 2)
chat_time.setTextColor(mContext.getResources().getColor(android.R.color.darker_gray));
else if (status == 3)
chat_time.setTextColor(mContext.getResources().getColor(android.R.color.black));
}
}
#Override
public int getViewTypeCount() {
return 2;
}
public class ViewHolder {
public StyleableTextView chat_name;
public StyleableTextView chat_time;
public StyleableTextView chat_tag;
public ImageView chat_image;
public TextView chat_header_text;
}
#Override
public int getCount() {
if (getCursor() == null) {
return 0;
} else {
return getCursor().getCount();
}
}
}
I am using an extended BaseAdapter for my gridview in which I implement ViewHolder methods. also I pass my data with a Cursor to this adapter.
here is my getView()
public View getView(int position, View view, ViewGroup parent) { // inflate the layout for each item of listView
ViewHolder holder;
if (view == null) {
view = inflater.inflate(gridItemId, null);
Log.d("recyvleView", "inflating " + position);
holder = new ViewHolder();
holder.tvAttachment = (ImageView) view.findViewById(R.id.iv_inventory_products_griditems_attachment);
holder.imageCount = (TextView) view.findViewById(R.id.imagecount);
holder.tvItemCode = (TextView) view.findViewById(R.id.tv_inventory_products_griditems_ItemCode);
holder.tvProductName = (TextView) view.findViewById(R.id.tv_inventory_products_griditems_Title);
holder.tvPrice = (RialTextView) view.findViewById(R.id.tv_inventory_products_griditems_Price);
holder.tvRemain = (TextView) view.findViewById( R.id.tv_inventory_products_griditems_Remain);
holder.btnMore =(com.rey.material.widget.Button) view.findViewById(R.id.btn_inventory_products_griditems_More);
holder.btnPlus = (com.rey.material.widget.Button) view.findViewById(R.id.btn_inventory_products_griditems_addOne);
view.setTag(holder);
} else {
Log.d("recyvleView", "restoring " + position);
holder = (ViewHolder) view.getTag();
}
setupView(view, position,holder);
//setupGridView(view,holder);
return view;
}
I noticed that I have a huge memory leak in this so I tried to minimize everything to find the leak, so I commented most of the methods and here is what has been left from my setupView:
private void setupView(View view, int position, ViewHolder holder) {
// move the cursor to required position
cursor.moveToPosition(position);
Log.d("POSITION", String.valueOf(position));
//holder.itemId = cursor.getString(cursor.getColumnIndex(DatabaseColumnContent.COL_PRODUCT_ITEM_ID.toString()));
//TSimpleProduct tempProduct = productCatalog.getSimpleProductById(Integer.parseInt(holder.itemId));
//holder.itemGuId = cursor.getString(cursor.getColumnIndex(DatabaseColumnContent.COL_PRODUCT_GUID.toString()));
holder.tvItemCode.setText(cursor.getString(cursor.getColumnIndex(DatabaseColumnContent.COL_PRODUCT_ITEMCODE.toString())));
holder.tvProductName.setText(cursor.getString(cursor.getColumnIndex(DatabaseColumnContent.COL_PRODUCT_ITEMDESC.toString())));
/* //Remain
if (cyberSetting.getSettingValue(TCyberSettingKey.SHOWITEMREMAIN).equals("1")) {
textTemp = (mContext.getString(R.string.restrictedInfo));
} else {
if (tempProduct.getDefaultUnitValue() == 2 && tempProduct.isUnitDependent()) {
String titleRemain2 = DatabaseColumnContent.COL_PRODUCT_CURSOR_REMAIN2.toString();
textTemp = cursor.getString(cursor.getColumnIndex(titleRemain2));
}
if (cyberSetting.getSettingValue(TCyberSettingKey.SHOWITEMREMAIN).equals("2")) {
if (textTemp == null) {
textTemp = "0";
}
int t = Integer.parseInt(textTemp);
if (t > 0) {
textTemp = mContext.getString(R.string.productAvailable);
} else {
textTemp = mContext.getString(R.string.productUnAvailable);
}
}
}
holder.tvRemain.setText(textTemp);
//Price
String priceLevel = "0";
try {
Register register = Register.getInstance();
priceLevel = register.getPriceLevel();
} catch (NoDaoSetException e) {
e.printStackTrace();
}
if(!priceLevel.equals("0"))
textTemp = cursor.getString(cursor.getColumnIndex(priceLevel));
else
textTemp = "0.0";
if (tempProduct.getDefaultUnitValue() == 2 && tempProduct.isUnitDependent()) {
double price2;
price2 = TLineItem.convertPrice1ToPrice2(Double.parseDouble(textTemp), tempProduct.isUnit1Bigger(), tempProduct.getUnitCoef());
textTemp = TGeneralTools.ConvertDoubleToEnglishString(price2);
if (tempProduct.getUnitDesc2() != null && !tempProduct.getUnitDesc2().equals(""))
unitDesc = " (" + tempProduct.getCompleteUnitDesc2() + ")";
} else {
if (tempProduct.getUnitDesc1() != null && !tempProduct.getUnitDesc1().equals(""))
unitDesc = " (" + tempProduct.getCompleteUnitDesc1() + ")";
}
holder.priceDef = textTemp;
holder.tvPrice.setText(textTemp + unitDesc);
holder.tvRemain.setText(holder.tvRemain.getText() + unitDesc);
//image
pictureCatalog = TPictureCatalog.getInstance();
String defGuid = "";
if (tempProduct.getHasAttachContent() >= 1 && pictureCatalog.isDownloadedAlbumAvailable()) {
defGuid = pictureCatalog.getDefaultPictureGuid(holder.itemGuId);
if (tempProduct.getHasAttachContent() == 1) {
holder.imageCount.setVisibility(View.GONE);
} else {
holder.imageCount.setVisibility(View.VISIBLE);
holder.imageCount.setText(String.valueOf(tempProduct.getHasAttachContent()));
}
} else {
holder.imageCount.setVisibility(View.GONE);
}
String filename = Environment.getExternalStorageDirectory().getPath()
+ FileAddressContent.APPLICATION_HOME_DIRECTORY
+ FileAddressContent.PICTURES_ROOT_DIRECTORY
//+ FileAddressContent.PICTURES_THUMBS_DIRECTORY.toString()
+ defGuid + FileAddressContent.PICTURES_EXTENSION;
pic = new File(filename);
if (pic.exists())
Picasso.with(mContext)
.load(pic)
.error(R.drawable.noimage)
//.placeholder(R.drawable.loading)
.resize(thumbSize, thumbSize)
.centerInside()
.into(holder.tvAttachment);
else
Picasso.with(mContext)
.load(R.drawable.noimage)
.resize(thumbSize, thumbSize)
.centerInside()
.into(holder.tvAttachment);
holder.tvAttachment.setMinimumHeight(thumbSize);
view.setTag(holder);*/
}
even though almost all of it is commented, these two lines are still leaking, I know cause when I commented them out, no leak was there ... !
holder.tvItemCode.setText(cursor.getString(cursor.getColumnIndex(DatabaseColumnContent.COL_PRODUCT_ITEMCODE.toString())));
holder.tvProductName.setText(cursor.getString(cursor.getColumnIndex(DatabaseColumnContent.COL_PRODUCT_ITEMDESC.toString())));
also this is my holder class :
public class ViewHolder {
public ImageView tvAttachment;
public ImageView ivStatus;
public TextView imageCount;
public TextView tvItemCode;
public TextView tvProductName;
public TextView tvRemain;
public RialTextView tvPrice;
public String priceDef;
public String itemId;
public String itemGuId;
public Button btnMore;
public Button btnPlus;
}
any suggestion, please ?! how can I stop it from leaking ?!
thanks in advance!
EDIT:
I get same result using cursor adapter as well.
Why are you using BaseAdapter? Android API has CursorAdapter and CursorLoader which handles all the cursor stuff. Looks like you are doing something wrong with cursors and this causes memory leaks.
Here is how I set up the list view and how I get the image by downloading it.
Some variable explanation :
The PostItem is the model object that contain the data for a listview item
The ImageLoader is the async task class to download the image by getting the image url from PostItem
The problem are , the ordering of the image in the listview is incorrect , for example, the image should appear in 1st is appear in both 1st , 4th, and if I scroll , the display pattern change as well.
Also, I find the image are download again if I scroll, even I have check the imageView whether has drawable
Thanks for helping.
====================================================
Here is how I generate the listview:
static class ViewHolderItem {
TextView name;
TextView date;
ImageView img;
TextView msg;
TextView count;
ImageView likeBtn;
ImageView commentBtn;
ImageView shareBtn;
}
private class MyPostAdapter extends ArrayAdapter<PostItem> {
#Override
public boolean isEnabled(int position) {
return false;
}
public MyPostAdapter(Context context, int resource, List<PostItem> items) {
super(context, resource, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolderItem viewHolder;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.post_item, parent, false);
viewHolder = new ViewHolderItem();
viewHolder.name = (TextView) v.findViewById(R.id.postName);
viewHolder.date = (TextView) v.findViewById(R.id.postDate);
viewHolder.img = (ImageView) v.findViewById(R.id.postImg);
viewHolder.msg = (TextView) v.findViewById(R.id.postMsg);
viewHolder.count = (TextView) v.findViewById(R.id.count);
viewHolder.likeBtn = (ImageView) v.findViewById(R.id.likeBtn);
viewHolder.commentBtn = (ImageView) v.findViewById(R.id.commentBtn);
viewHolder.shareBtn = (ImageView) v.findViewById(R.id.shareBtn);
v.setTag(viewHolder);
} else {
viewHolder = (ViewHolderItem) convertView.getTag();
}
final PostItem post = getItem(position);
if (post != null) {
viewHolder.name.setText(post.name);
try {
c.setTime(sdf.parse(post.createDate));
} catch (ParseException e) {
e.printStackTrace();
}
relative_date = DateUtils.getRelativeDateTimeString (ctx, c.getTimeInMillis() , DateUtils.MINUTE_IN_MILLIS,DateUtils.WEEK_IN_MILLIS, 0).toString();
viewHolder.date.setText(relative_date);
viewHolder.msg.setText(post.txtMsg);
viewHolder.count.setText(post.likeCount + " " + getString(R.string.pro_like) + " " + post.commentCount + " " + getString(R.string.reply));
if (post.isLike) {
viewHolder.likeBtn.setImageResource(R.drawable.like);
} else {
viewHolder.likeBtn.setImageResource(R.drawable.before_like);
}
if (!post.imageURL.equals("null") && viewHolder.img.getDrawable() == null ) {
new ImageLoader(ctx).execute(viewHolder.img,Constant.comment_imageFolder + post.imageURL);
} else {
viewHolder.img.setImageDrawable(null);
}
viewHolder.likeBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new APIManager("like", ctx, Constant.likeAPI + "/"
+ post.commentID + "/" + userID, jsonListener,
getResources().getString(R.string.update_data));
}
});
viewHolder.commentBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<PostItem> filterReplyList = new ArrayList<PostItem>();
Intent i = new Intent(ctx, ReplyActivity.class);
i.putExtra("commentID", post.commentID);
// get reply list
for (PostItem reply : replyItemList) {
if (reply.postID.equals(post.commentID)
|| reply.commentID.equals(post.commentID)) {
filterReplyList.add(reply);
}
}
i.putExtra("replyItemList", filterReplyList);
startActivityForResult(i, 0);
}
});
viewHolder.shareBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
String data = "date: " + post.createDate + "\nmsg:" + post.txtMsg;
sendIntent.putExtra(Intent.EXTRA_TEXT, data);
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
});
}
return v;
}
}
And Here is the imageloader, take the imageview, url as input and put the bitmap in the imageview
public class ImageLoader extends AsyncTask<Object, Void, Bitmap> {
private static String TAG = "ImageLoader";
private InputStream input;
private ImageView view;
private ProgressBar loadingIcon;
private ListView myListView;
private String imageURL;
private Context ctx;
public ImageLoader(Context _ctx) {
ctx = _ctx;
}
#Override
protected Bitmap doInBackground(Object... params) {
try {
view = (ImageView) params[0];
// handle Chinese characters in file name
// String[] imgUrlArray = ((String) params[1]).split("/");
// String fileName = imgUrlArray[imgUrlArray.length - 1];
// String newfileName = URLEncoder.encode(fileName, "utf-8");
// imageURL = ((String) params[1]).replace(fileName, newfileName);
imageURL = ((String) params[1]);
if (params.length > 2 && (ProgressBar) params[2] != null)
loadingIcon = (ProgressBar) params[2];
URL url = new URL(imageURL);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
input = connection.getInputStream();
final BitmapFactory.Options options = new BitmapFactory.Options();
BufferedInputStream bis = new BufferedInputStream(input, 4*1024);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte)current);
}
byte[] imageData = baf.toByteArray();
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
options.inJustDecodeBounds = true;
options.inSampleSize = 2;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
if (input != null)
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
protected void onPostExecute(Bitmap result) {
if (result != null && view != null) {
if (loadingIcon != null)
loadingIcon.setVisibility(View.GONE);
view.setVisibility(View.VISIBLE);
view.setImageBitmap(result);
}
}
Updated code (implement volley library):
static class ViewHolderItem {
TextView name;
TextView date;
NetworkImageView img;
TextView msg;
TextView count;
ImageView likeBtn;
ImageView commentBtn;
ImageView shareBtn;
}
private class MyPostAdapter extends ArrayAdapter<PostItem> {
#Override
public boolean isEnabled(int position) {
return false;
}
public MyPostAdapter(Context context, int resource, List<PostItem> items) {
super(context, resource, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolderItem viewHolder;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.post_item, parent, false);
viewHolder = new ViewHolderItem();
viewHolder.name = (TextView) v.findViewById(R.id.postName);
viewHolder.date = (TextView) v.findViewById(R.id.postDate);
viewHolder.img = (NetworkImageView) v.findViewById(R.id.postImg);
viewHolder.msg = (TextView) v.findViewById(R.id.postMsg);
viewHolder.count = (TextView) v.findViewById(R.id.count);
viewHolder.likeBtn = (ImageView) v.findViewById(R.id.likeBtn);
viewHolder.commentBtn = (ImageView) v.findViewById(R.id.commentBtn);
viewHolder.shareBtn = (ImageView) v.findViewById(R.id.shareBtn);
v.setTag(viewHolder);
} else {
viewHolder = (ViewHolderItem) convertView.getTag();
}
final PostItem post = getItem(position);
if (post != null) {
viewHolder.name.setText(post.name);
try {
c.setTime(sdf.parse(post.createDate));
} catch (ParseException e) {
e.printStackTrace();
}
relative_date = DateUtils.getRelativeDateTimeString (ctx, c.getTimeInMillis() , DateUtils.MINUTE_IN_MILLIS,DateUtils.WEEK_IN_MILLIS, 0).toString();
viewHolder.date.setText(relative_date);
viewHolder.msg.setText(post.txtMsg);
viewHolder.count.setText(post.likeCount + " " + getString(R.string.pro_like) + " " + post.commentCount + " " + getString(R.string.reply));
if (post.isLike) {
viewHolder.likeBtn.setImageResource(R.drawable.like);
} else {
viewHolder.likeBtn.setImageResource(R.drawable.before_like);
}
if (!post.imageURL.equals("null")) {
viewHolder.img.setImageUrl(Constant.comment_imageFolder + post.imageURL, mImageLoader);
}
viewHolder.likeBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new APIManager("like", ctx, Constant.likeAPI + "/"
+ post.commentID + "/" + userID, jsonListener,
getResources().getString(R.string.update_data));
}
});
viewHolder.commentBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<PostItem> filterReplyList = new ArrayList<PostItem>();
Intent i = new Intent(ctx, ReplyActivity.class);
i.putExtra("commentID", post.commentID);
// get reply list
for (PostItem reply : replyItemList) {
if (reply.postID.equals(post.commentID)
|| reply.commentID.equals(post.commentID)) {
filterReplyList.add(reply);
}
}
i.putExtra("replyItemList", filterReplyList);
startActivityForResult(i, 0);
}
});
viewHolder.shareBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
String data = "date: " + post.createDate + "\nmsg:" + post.txtMsg;
sendIntent.putExtra(Intent.EXTRA_TEXT, data);
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
});
}
return v;
}
For the task you are trying to do I would strongly recommend you to use Volley library.
Read from here
All you need to do is as below
mRequestQueue = Volley.newRequestQueue(context);
mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());
mImageView.setImageUrl(BASE_URL + item.image_url, mImageLoader);
Where mImageView is com.android.volley.NetworkImageView instead of a regular ImageView.
Volley takes care of maintaining the cache and the ordering of the images.
if you scroll the listview you will get back recycled convertview, it is not null but it has incorrect imageview. convertView is a view thats created and recycled through scrolling the list. this view makes GC be called less and also save memory for you. it first assigned by your earliest items of list. after you scroll the list, for example item one of list disappears and you see item 15 the convertView of item one is passed again to you. in this time it is not null and it holdes the reference of last imageview, the imageview of item 1.
so this is your problem, you skipped assigning correct imageview to your viewHolder.img.
Ok, what should you do?
the best thing you can do is create in memory cache that holds your downloaded imageview by their URLs as keys of the cache. in getview you check the cache, if it has your URL of current imageview position read from it and set it to viewHolder.img else download the image from internet.
Golden rule is:
ALWAYS OVERWRITE VIEWHOLDER VALUES WITH VALUES OF YOUR ITEM AT INDEX POSITON THAT
GETVIEW PASSES TO YOU
how to create cache? look at Example LRU cache at
http://developer.android.com/training/volley/request.html
and if you want you can also use volley library instead.
if (!post.imageURL.equals("null") && viewHolder.img.getDrawable() == null ) {
new ImageLoader(ctx).execute(viewHolder.img,Constant.comment_imageFolder + post.imageURL);
}
I am guessing that the problem lies here. What happens when you get a recycled view which already has an image from the previous view it was used for? That explains why the image appears in both 1st and 4th position and the change in the display pattern when you scroll.
Get the point? Remove the viewHolder.img.getDrawable() == null and try. See if that helps.
HI all,im trying a develop a sms app from scratch(smsdroid as my reference) . Basically i have Viewpager which shows the conversation list in a a fragment. The fragment has a listview in it. The list view adapter has two different layouts to show sender's and receivers separately. My listview adapter extends Resource cursor adapter.Everything is working well when the app loads.Now in to the problem the image of the receiver is get replaced by the image of the sender on scrolling the listview. Can some one suggest me a way to overcome this problem?
After scrolling the list looks like this
I have read about listview view recyling and all but to be frank i did not understand it completly.
This is my message adapter for the listview
public class MessageAdapter extends ResourceCursorAdapter {
ViewHolder holder;
private static final String WHERE = "("
+ Message.PROJECTION_JOIN[Message.INDEX_TYPE] + " != "
+ Message.SMS_DRAFT + " OR "
+ Message.PROJECTION_JOIN[Message.INDEX_TYPE] + " IS NULL)";
/** WHERE clause for drafts. */
private static final String WHERE_DRAFT = "("
+ Message.PROJECTION_SMS[Message.INDEX_THREADID] + " = ? AND "
+ Message.PROJECTION_SMS[Message.INDEX_TYPE] + " = "
+ Message.SMS_DRAFT + ")";
// + " OR " + type + " = " + Message.SMS_PENDING;
String sssssss;
Contact globalcontact;
private int mLayout;
Uri uri;
public static AnimationDrawable AniFrame;
public static boolean enableHangoutAnimation=false;
public MessageAdapter(Activity _context, Uri uri) {
super(_context, R.layout.testmessage_classic_received, getCursor(
_context.getContentResolver(), uri), true);
this.defaultContactAvatar = _context.getResources().getDrawable(
R.drawable.default_avatar);
this.ownerAvatar = _context.getResources().getDrawable(
R.drawable.bubble_orange_right);
this.backgroundDrawableIn = PreferencesActivity.getBubblesIn(_context);
this.backgroundDrawableOut = PreferencesActivity
.getBubblesOut(_context);
this.textSize = PreferencesActivity.getTextsize(_context);
this.textColor = PreferencesActivity.getTextcolor(_context);
this.convertNCR = PreferencesActivity.decodeDecimalNCR(_context);
context = _context;
this.uri = uri;
if (uri == null || uri.getLastPathSegment() == null) {
this.threadId = -1;
} else {
this.threadId = Integer.parseInt(uri.getLastPathSegment());
}
Conversation conv = Conversation.getConversation(context,
this.threadId, false);
if (conv == null) {
this.address = null;
this.name = null;
this.displayName = null;
} else {
contact = conv.getContact();
this.address = contact.getNumber();
this.name = contact.getName();
this.displayName = contact.getDisplayName();
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowType = getItemViewType(cursor.getPosition());
if (rowType == 0) {
return mInflater.inflate(R.layout.testmessage_classic_sent, parent,
false);
} else if (rowType == 1) {
return mInflater.inflate(R.layout.testmessage_classic_received,
parent, false);
} else {
return null;
}
}
#Override
public int getItemViewType(int position) {
Cursor c = (Cursor) getItem(position);
Message m = Message.getMessage(context, c);
switch (m.getType()) {
case Message.MMS_IN: // 128
return 1;
case Message.MMS_OUT: // 132
return 0;
case Message.SMS_IN: // 2
return 1;
case Message.SMS_OUT: // 1
return 0;
default:
return 0;
}
}
public void setImageView(ImageView contactPhoto) {
mProjection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY,
Profile.LOOKUP_KEY, Profile.PHOTO_URI };
mProfileCursor = context.getContentResolver().query(
Profile.CONTENT_URI, mProjection, null, null, null);
if (mProfileCursor.moveToFirst()) {
do {
sssssss = mProfileCursor.getString(mProfileCursor
.getColumnIndex(Profile.PHOTO_URI));
if (sssssss != null) {
Uri photoUri = Uri.parse(sssssss);
contactPhoto.setImageURI(photoUri);
} else {
contactPhoto.setImageResource(R.drawable.ic_launcher);
}
} while (mProfileCursor.moveToNext());
}
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
/**
* checking starts here
*
*/
holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.tvBody = (TextView) view.findViewById(R.id.textBody);
holder.tvDate = (TextView) view.findViewById(R.id.textDate);
// holder.vRead= (View) view.findViewById(R.id.read);
Utilities.setCustomFont(context, holder.tvDate);
Utilities.setCustomFont(context, holder.tvBody);
// holder.tvDate = ( TextView ) view.findViewById( R.id.date );
holder.ivPhoto = (QuickContactBadge) view
.findViewById(R.id.imageContactPicture);
holder.btnDownload = (Button) view
.findViewById(R.id.downloadButton);
holder.media = (ImageView) view.findViewById(R.id.media);
holder.ellipse = (ImageView) view.findViewById(R.id.ellipsis);
AniFrame = (AnimationDrawable) holder.ellipse.getBackground();
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
if (MainActivity.showContactPhoto) {
holder.ivPhoto.setImageDrawable(contact.getAvatar(this.context,
this.defaultContactAvatar));
holder.ivPhoto.setVisibility(View.VISIBLE);
holder.ivPhoto.setOnClickListener(WRAPPER.getQuickContact(
context, holder.ivPhoto,
contact.getLookUpUri(context.getContentResolver()), 2,
null));
if (rowType == 0) {
setImageView(holder.ivPhoto);
} else if (rowType == 1) {
holder.ivPhoto.setImageDrawable(contact.getAvatar(
this.context, this.defaultContactAvatar));
}
} else {
holder.ivPhoto.setVisibility(View.GONE);
}
}
/** View holder. */
public static class ViewHolder {
public static ImageView ellipse;
TextView tvBody;
TextView tvPerson;
TextView tvDate;
ImageView media;
// View vRead;
public View vPending;
public View vLayout;
public ImageView ivInOut;
public Button btnDownload;
public Button btnImport;
QuickContactBadge ivPhoto;
}
/**
* Get the {#link Cursor}.
*
* #param cr
* {#link ContentResolver}
* #param u
* {#link Uri}
* #return {#link Cursor}
*/
private static Cursor getCursor(final ContentResolver cr, final Uri u) {
Log.d(TAG, "getCursor(" + u + ")");
final Cursor[] c = new Cursor[] { null, null };
int tid = -1;
try {
tid = Integer.parseInt(u.getLastPathSegment());
} catch (Exception e) {
Log.e(TAG, "error parsing uri: " + u, e);
}
try {
Log.d(TAG, "where: " + WHERE);
c[0] = cr.query(u, Message.PROJECTION_JOIN, WHERE, null, null);
} catch (NullPointerException e) {
Log.e(TAG, "error query: " + u + " / " + WHERE, e);
c[0] = null;
} catch (SQLiteException e) {
Log.e(TAG, "error getting messages", e);
}
final String[] sel = new String[] { String.valueOf(tid) };
try {
Log.d(TAG, "where: " + WHERE_DRAFT + " / sel: " + sel);
c[1] = cr.query(Uri.parse("content://sms/"),
Message.PROJECTION_SMS, WHERE_DRAFT, sel, Message.SORT_USD);
} catch (NullPointerException e) {
Log.e(TAG, "error query: " + u + " / " + WHERE_DRAFT + " sel: "
+ sel, e);
c[1] = null;
} catch (SQLiteException e) {
Log.e(TAG, "error getting drafts", e);
}
if (c[1] == null || c[1].getCount() == 0) {
return c[0];
}
if (c[0] == null || c[0].getCount() == 0) {
return c[1];
}
return new MergeCursor(c);
}
}
Can some one explain what is the root cause of this problem and a way to solve it
I solved the problem since there was two different layouts to inflate i had to use two different viewholders.
public class MessageAdapter extends ResourceCursorAdapter {
private static final ContactsWrapper WRAPPER = ContactsWrapper
.getInstance();
/** Cursor's sort. */
// static ViewHolder holder;
int rowType;
public static String SORT = Calls.DATE + " DESC";
private Activity context;
/** {#link BackgroundQueryHandler}. */
// private BackgroundQueryHandler queryHandler;
/** Token for {#link BackgroundQueryHandler}: message list query. */
/** Thread id. */
private int threadId = -1;
/** Address. */
private String address = null;
/** Name. */
private String name = null;
/** Display Name (name if !=null, else address). */
private String displayName = null;
/** Used background drawable for messages. */
private int backgroundDrawableIn, backgroundDrawableOut;
private Cursor origCursor;
private static String TAG = "MessageAdapter";
/** General WHERE clause. */
/** Used text size/color. */
Contact contact;
private int textSize, textColor;
/** Convert NCR. */
private Drawable defaultContactAvatar, ownerAvatar;
private boolean convertNCR;
private Bitmap globalBitmap;
private String contactid26;
private String[] mProjection;
private Cursor mProfileCursor;
String path;
ViewHolder holder,holder1;
private static final String WHERE = "("
+ Message.PROJECTION_JOIN[Message.INDEX_TYPE] + " != "
+ Message.SMS_DRAFT + " OR "
+ Message.PROJECTION_JOIN[Message.INDEX_TYPE] + " IS NULL)";
/** WHERE clause for drafts. */
private static final String WHERE_DRAFT = "("
+ Message.PROJECTION_SMS[Message.INDEX_THREADID] + " = ? AND "
+ Message.PROJECTION_SMS[Message.INDEX_TYPE] + " = "
+ Message.SMS_DRAFT + ")";
// + " OR " + type + " = " + Message.SMS_PENDING;
String sssssss;
Contact globalcontact;
private int mLayout;
Uri uri;
public static AnimationDrawable AniFrame;
public static boolean enableHangoutAnimation=false;
public MessageAdapter(Activity _context, Uri uri) {
super(_context, R.layout.testmessage_classic_received, getCursor(
_context.getContentResolver(), uri), true);
this.defaultContactAvatar = _context.getResources().getDrawable(
R.drawable.default_avatar);
this.ownerAvatar = _context.getResources().getDrawable(
R.drawable.bubble_orange_right);
this.backgroundDrawableIn = PreferencesActivity.getBubblesIn(_context);
this.backgroundDrawableOut = PreferencesActivity
.getBubblesOut(_context);
this.textSize = PreferencesActivity.getTextsize(_context);
this.textColor = PreferencesActivity.getTextcolor(_context);
this.convertNCR = PreferencesActivity.decodeDecimalNCR(_context);
context = _context;
this.uri = uri;
if (uri == null || uri.getLastPathSegment() == null) {
this.threadId = -1;
} else {
this.threadId = Integer.parseInt(uri.getLastPathSegment());
}
Conversation conv = Conversation.getConversation(context,
this.threadId, false);
if (conv == null) {
this.address = null;
this.name = null;
this.displayName = null;
} else {
contact = conv.getContact();
this.address = contact.getNumber();
this.name = contact.getName();
this.displayName = contact.getDisplayName();
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowType = getItemViewType(cursor.getPosition());
if (rowType == 0) {
return mInflater.inflate(R.layout.testmessage_classic_sent, parent,
false);
} else if (rowType == 1) {
return mInflater.inflate(R.layout.testmessage_classic_received,
parent, false);
} else {
return null;
}
}
#Override
public int getItemViewType(int position) {
Cursor c = (Cursor) getItem(position);
Message m = Message.getMessage(context, c);
switch (m.getType()) {
case Message.MMS_IN: // 128
return 1;
case Message.MMS_OUT: // 132
return 0;
case Message.SMS_IN: // 2
return 1;
case Message.SMS_OUT: // 1
return 0;
default:
return 0;
}
}
public void setImageView(ImageView contactPhoto) {
mProjection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY,
Profile.LOOKUP_KEY, Profile.PHOTO_URI };
mProfileCursor = context.getContentResolver().query(
Profile.CONTENT_URI, mProjection, null, null, null);
if (mProfileCursor.moveToFirst()) {
do {
sssssss = mProfileCursor.getString(mProfileCursor
.getColumnIndex(Profile.PHOTO_URI));
if (sssssss != null) {
Uri photoUri = Uri.parse(sssssss);
contactPhoto.setImageURI(photoUri);
} else {
contactPhoto.setImageResource(R.drawable.ic_launcher);
}
} while (mProfileCursor.moveToNext());
}
}
#Override
public void bindView(View view, final Context context, Cursor cursor) {
/**
* checking starts here
*
*/
int viewType = getItemViewType(cursor.getPosition());
switch(viewType)
{
case 0:
final Message m = Message.getMessage(context, cursor);
holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.tvBody = (TextView) view.findViewById(R.id.textBody);
holder.tvDate = (TextView) view.findViewById(R.id.textDate);
// holder.vRead= (View) view.findViewById(R.id.read);
Utilities.setCustomFont(context, holder.tvDate);
Utilities.setCustomFont(context, holder.tvBody);
// holder.tvDate = ( TextView ) view.findViewById( R.id.date );
holder.ivPhoto = (QuickContactBadge) view
.findViewById(R.id.imageContactPicture);
holder.btnDownload = (Button) view
.findViewById(R.id.downloadButton);
holder.media = (ImageView) view.findViewById(R.id.media);
holder.ellipse = (ImageView) view.findViewById(R.id.ellipsis);
AniFrame = (AnimationDrawable) holder.ellipse.getBackground();
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
/**
* New check starting here
*/
if (this.textSize > 0) {
holder.tvBody.setTextSize(this.textSize);
Utilities.setCustomFont(context, holder.tvBody);
}
final int col = this.textColor;
if (col != 0) {
// holder.tvPerson.setTextColor(col);
holder.tvBody.setTextColor(col);
holder.tvDate.setTextColor(col);
Utilities.setCustomFont(context, holder.tvDate);
}
int tt = PreferencesActivity
.getTextColorHackForMessageAdapter(context);
if (tt != 0) {
// holder.tvPerson.setTextColor(tt);
holder.tvBody.setTextColor(tt);
holder.tvDate.setTextColor(tt);
}
Conversation conv1 = Conversation.getConversation(context,
this.threadId, false);
if (conv1 == null) {
this.address = null;
this.name = null;
this.displayName = null;
} else {
contact = conv1.getContact();
this.address = contact.getNumber();
this.name = contact.getName();
this.displayName = contact.getDisplayName();
}
CharSequence text = m.getBody();
holder.tvBody.setText(text);
// unread / read
/*
* if ( m.getRead() == 0 ) { holder.vRead.setVisibility(
* View.VISIBLE ); } else { holder.vRead.setVisibility(
* View.INVISIBLE ); }
*/
int t = m.getType();
String subject = m.getSubject();
if (subject == null) {
subject = "";
} else {
subject = ": " + subject;
}
final long time = m.getDate();
holder.tvDate.setText(Utilities.getDate(context, time));
/**
* Adding codes for mms
*
*/
final Bitmap pic = m.getPicture();
if (pic != null) {
if (pic == Message.BITMAP_PLAY) {
holder.media.setImageResource(R.drawable.mms_play_btn);
} else {
holder.media.setImageBitmap(pic);
}
holder.media.setVisibility(View.VISIBLE);
final Intent i = m.getContentIntent();
holder.media.setOnClickListener(SMSdroid
.getOnClickStartActivity(context, i));
holder.media.setOnLongClickListener(m
.getSaveAttachmentListener(context));
} else {
holder.media.setVisibility(View.GONE);
holder.media.setOnClickListener(null);
}
// CharSequence text = m.getBody();
if (text == null && pic == null) {
final Button btn = holder.btnDownload;
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
try {
Intent i = new Intent();
i.setClassName("com.android.mms",
"com.android.mms.transaction.TransactionService");
i.putExtra("uri", m.getUri().toString());
i.putExtra("type", 1);
ComponentName cn = context.startService(i);
if (cn != null) {
btn.setEnabled(false);
btn.setText(R.string.downloading_);
} else {
i = new Intent(Intent.ACTION_VIEW, Uri
.parse(MainActivity.URI
+ m.getThreadId()));
context.startActivity(Intent.createChooser(i,
context.getString(R.string.view_mms)));
}
} catch (SecurityException e) {
Log.e(TAG, "unable to start mms download", e);
Toast.makeText(context,
R.string.error_start_mms_download,
Toast.LENGTH_LONG).show();
}
}
});
holder.btnDownload.setVisibility(View.VISIBLE);
holder.btnDownload.setEnabled(true);
} else {
// testing hiding this code
// holder.btnDownload.setVisibility(View.GONE);
}
/**
* New check Ends here
*/
if (MainActivity.showContactPhoto) {
holder.ivPhoto.setImageDrawable(contact.getAvatar(this.context,
this.defaultContactAvatar));
holder.ivPhoto.setVisibility(View.VISIBLE);
holder.ivPhoto.setOnClickListener(WRAPPER.getQuickContact(
context, holder.ivPhoto,
contact.getLookUpUri(context.getContentResolver()), 2,
null));
setImageView(holder.ivPhoto);
} else {
holder.ivPhoto.setVisibility(View.GONE);
}
break;
case 1:
final Message m1 = Message.getMessage(context, cursor);
holder1 = (ViewHolder) view.getTag();
if (holder1 == null) {
holder1 = new ViewHolder();
holder1.tvBody = (TextView) view.findViewById(R.id.textBody);
holder1.tvDate = (TextView) view.findViewById(R.id.textDate);
// holder.vRead= (View) view.findViewById(R.id.read);
Utilities.setCustomFont(context, holder1.tvDate);
Utilities.setCustomFont(context, holder1.tvBody);
// holder.tvDate = ( TextView ) view.findViewById( R.id.date );
holder1.ivPhoto = (QuickContactBadge) view
.findViewById(R.id.imageContactPicture);
holder1.btnDownload = (Button) view
.findViewById(R.id.downloadButton);
holder1.media = (ImageView) view.findViewById(R.id.media);
holder1.ellipse = (ImageView) view.findViewById(R.id.ellipsis);
view.setTag(holder1);
} else {
holder1 = (ViewHolder) view.getTag();
}
if (MainActivity.showContactPhoto) {
holder1.ivPhoto.setImageDrawable(contact.getAvatar(this.context,
this.defaultContactAvatar));
holder1.ivPhoto.setVisibility(View.VISIBLE);
holder1.ivPhoto.setOnClickListener(WRAPPER.getQuickContact(
context, holder1.ivPhoto,
contact.getLookUpUri(context.getContentResolver()), 2,
null));
holder1.ivPhoto.setImageDrawable(contact.getAvatar(
this.context, this.defaultContactAvatar));
} else {
holder1.ivPhoto.setVisibility(View.GONE);
}
/**
* New check starting here
*/
if (this.textSize > 0) {
holder1.tvBody.setTextSize(this.textSize);
Utilities.setCustomFont(context, holder1.tvBody);
}
final int col1 = this.textColor;
if (col1 != 0) {
// holder.tvPerson.setTextColor(col);
holder1.tvBody.setTextColor(col1);
holder1.tvDate.setTextColor(col1);
Utilities.setCustomFont(context, holder1.tvDate);
}
int tt1 = PreferencesActivity
.getTextColorHackForMessageAdapter(context);
if (tt1 != 0) {
// holder.tvPerson.setTextColor(tt);
holder1.tvBody.setTextColor(tt1);
holder1.tvDate.setTextColor(tt1);
}
Conversation conv11 = Conversation.getConversation(context,
this.threadId, false);
if (conv11 == null) {
this.address = null;
this.name = null;
this.displayName = null;
} else {
contact = conv11.getContact();
this.address = contact.getNumber();
this.name = contact.getName();
this.displayName = contact.getDisplayName();
}
CharSequence text1 = m1.getBody();
holder1.tvBody.setText(text1);
// unread / read
/*
* if ( m.getRead() == 0 ) { holder.vRead.setVisibility(
* View.VISIBLE ); } else { holder.vRead.setVisibility(
* View.INVISIBLE ); }
*/
int t1 = m1.getType();
String subject1 = m1.getSubject();
if (subject1 == null) {
subject1 = "";
} else {
subject1 = ": " + subject1;
}
final long time1= m1.getDate();
holder1.tvDate.setText(Utilities.getDate(context, time1));
/**
* Adding codes for mms
*
*/
final Bitmap pic1 = m1.getPicture();
if (pic1 != null) {
if (pic1 == Message.BITMAP_PLAY) {
holder1.media.setImageResource(R.drawable.mms_play_btn);
} else {
holder1.media.setImageBitmap(pic1);
}
holder1.media.setVisibility(View.VISIBLE);
final Intent i = m1.getContentIntent();
holder1.media.setOnClickListener(SMSdroid
.getOnClickStartActivity(context, i));
holder1.media.setOnLongClickListener(m1
.getSaveAttachmentListener(context));
} else {
holder1.media.setVisibility(View.GONE);
holder1.media.setOnClickListener(null);
}
// CharSequence text = m.getBody();
if (text1 == null && pic1 == null) {
final Button btn = holder1.btnDownload;
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
try {
Intent i = new Intent();
i.setClassName("com.android.mms",
"com.android.mms.transaction.TransactionService");
i.putExtra("uri", m1.getUri().toString());
i.putExtra("type", 1);
ComponentName cn = context.startService(i);
if (cn != null) {
btn.setEnabled(false);
btn.setText(R.string.downloading_);
} else {
i = new Intent(Intent.ACTION_VIEW, Uri
.parse(MainActivity.URI
+ m1.getThreadId()));
context.startActivity(Intent.createChooser(i,
context.getString(R.string.view_mms)));
}
} catch (SecurityException e) {
Log.e(TAG, "unable to start mms download", e);
Toast.makeText(context,
R.string.error_start_mms_download,
Toast.LENGTH_LONG).show();
}
}
});
holder1.btnDownload.setVisibility(View.VISIBLE);
holder1.btnDownload.setEnabled(true);
} else {
// testing hiding this code
// holder.btnDownload.setVisibility(View.GONE);
}
/**
* New check Ends here
*/
break;
}
}
/** View holder. */
public static class ViewHolder {
public static ImageView ellipse;
TextView tvBody;
TextView tvPerson;
TextView tvDate;
ImageView media;
// View vRead;
public View vPending;
public View vLayout;
public ImageView ivInOut;
public Button btnDownload;
public Button btnImport;
QuickContactBadge ivPhoto;
}
/** View holder. */
public static class ViewHolder1 {
public static ImageView ellipse;
TextView tvBody;
TextView tvPerson;
TextView tvDate;
ImageView media;
// View vRead;
public View vPending;
public View vLayout;
public ImageView ivInOut;
public Button btnDownload;
public Button btnImport;
QuickContactBadge ivPhoto;
}
/**
* Get the {#link Cursor}.
*
* #param cr
* {#link ContentResolver}
* #param u
* {#link Uri}
* #return {#link Cursor}
*/
private static Cursor getCursor(final ContentResolver cr, final Uri u) {
Log.d(TAG, "getCursor(" + u + ")");
final Cursor[] c = new Cursor[] { null, null };
int tid = -1;
try {
tid = Integer.parseInt(u.getLastPathSegment());
} catch (Exception e) {
Log.e(TAG, "error parsing uri: " + u, e);
}
try {
Log.d(TAG, "where: " + WHERE);
c[0] = cr.query(u, Message.PROJECTION_JOIN, WHERE, null, null);
} catch (NullPointerException e) {
Log.e(TAG, "error query: " + u + " / " + WHERE, e);
c[0] = null;
} catch (SQLiteException e) {
Log.e(TAG, "error getting messages", e);
}
final String[] sel = new String[] { String.valueOf(tid) };
try {
Log.d(TAG, "where: " + WHERE_DRAFT + " / sel: " + sel);
c[1] = cr.query(Uri.parse("content://sms/"),
Message.PROJECTION_SMS, WHERE_DRAFT, sel, Message.SORT_USD);
} catch (NullPointerException e) {
Log.e(TAG, "error query: " + u + " / " + WHERE_DRAFT + " sel: "
+ sel, e);
c[1] = null;
} catch (SQLiteException e) {
Log.e(TAG, "error getting drafts", e);
}
if (c[1] == null || c[1].getCount() == 0) {
return c[0];
}
if (c[0] == null || c[0].getCount() == 0) {
return c[1];
}
return new MergeCursor(c);
}
}