android - ArrayAdapter notifyDataSetChanged() called from Handler.post randomly does not call GetView - android

I have searched between many notifyDataSetChanged() issue questions without finding my specific case, so here it is:
Problem
I have a root thread (started by the UI thread) that listen for something.
Everytime it receives a message, it starts a new thread (let's call them children threads) that does some operations and, at the end of its life, notifies to the UI adapter that an object has been added.
This procedure works 99.99% of the time (I have stressed a lot the program) but in some cases that I cannot understand this notification does not work.
I am sure that the problem is the listview because the two above statements (setImageBitmap) work properly, changing the imageViews images.
Code
Handler initialization in the Activity and passed to the class that works with threads
//class scope variable
private final Handler mHandler = new Handler(new IncomingHandlerCallback(this));
//At the end of the activity class
/**
* ref. https://groups.google.com/forum/#!msg/android-developers/1aPZXZG6kWk/lIYDavGYn5UJ
*/
class IncomingHandlerCallback implements Handler.Callback {
Activity activity;
public IncomingHandlerCallback(Activity activity) {
this.activity = activity;
}
#SuppressWarnings("unchecked")
#Override
public boolean handleMessage(Message msg) {
DeviceUtils.hideKeyboard(activity);
switch (msg.what) {
case EXECUTE_CODE_UPDATE_TCP_COUNT:
updateDebugCounter(true);
break;
.
.
.
case EXECUTE_CODE_UPDATE_LIST_COUNT:
updateDebugCounter(false);
break;
}
return true;
}
}
Like the comment says that declaration is taken here
Custom Array Adapter
public class PlateInfoListAdapter extends ArrayAdapter<PlateInfo> {
private final Activity context;
CheckBox selectAll;
List<PlateInfo> plateList;
AnprInterface anprInterface;
private MobileANPRDetailPopup readingDetailPopup;
public PlateInfoListAdapter(Activity context, List<PlateInfo> plateList, CheckBox selectAll, AnprInterface anprInterface) {
super(context, R.layout.adapter_plate_list, 0,
plateList);
this.context = context;
this.selectAll = selectAll;
this.plateList = plateList;
this.anprInterface = anprInterface;
final LayoutInflater factory = context.getLayoutInflater();
readingDetailPopup = new MobileANPRDetailPopup(context, factory.inflate(R.layout.popup_mobile_anpr_reading_detail, null));
readingDetailPopup.setBackgroundDrawable(Reso.getDrawable(context, R.drawable.grey_border_white_bck));
readingDetailPopup.setOutsideTouchable(true);
readingDetailPopup.update();
}
static class ViewHolder {
protected LinearLayout layout;
protected CheckBox checkBox;
protected TextView date;
protected TextView plate;
protected TextView plateCountry;
protected ImageView blackList;
protected ImageView whiteList;
protected ImageButton readingDetail;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = null;
PlateInfo plateInfo = plateList.get(position);
boolean hotlistDrawn = false;
if(plateList.size() == 1) {
selectAll.setVisibility(View.VISIBLE);
}
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.adapter_plate_list, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.layout = (LinearLayout) view.findViewById(R.id.ll_plate_layout);
viewHolder.checkBox = (CheckBox) view.findViewById(R.id.cb_plate);
viewHolder.plate = (TextView) view.findViewById(R.id.tv_plate_plate);
viewHolder.plateCountry = (TextView) view.findViewById(R.id.tv_plate_country);
viewHolder.date = (TextView) view.findViewById(R.id.tv_plate_data);
viewHolder.blackList = (ImageView) view.findViewById(R.id.iv_plate_blacklist);
viewHolder.whiteList = (ImageView) view.findViewById(R.id.iv_plate_whitelist);
viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Here we get the position that we have set for the checkbox using setTag.
int getPosition = (Integer) buttonView.getTag();
// Set the value of checkbox to maintain its state.
plateList.get(getPosition).setRowChecked(buttonView.isChecked());
}
});
viewHolder.readingDetail = (ImageButton) view.findViewById(R.id.ib_plate_detail);
viewHolder.readingDetail.setFocusable(false);
viewHolder.readingDetail.setFocusableInTouchMode(false);
viewHolder.readingDetail.setTag(plateInfo);
viewHolder.readingDetail.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(anprInterface.isReading()) {
return;
}
PlateInfo selectedPlateInfo = (PlateInfo) viewHolder.readingDetail.getTag();
if(selectedPlateInfo != null) {
readingDetailPopup.showCentered(v, selectedPlateInfo);
}
}
});
view.setTag(viewHolder);
} else {
view = convertView;
}
ViewHolder holder = (ViewHolder) view.getTag();
// Restore the checked state properly
holder.checkBox.setTag(position);
holder.checkBox.setChecked(plateInfo.isRowChecked());
holder.plate.setText(plateInfo.getPlate());
holder.plateCountry.setText(plateInfo.getPlateCountry());
holder.date.setText(DateUtils.formatHelianDateToCustomHumanDate("HH:mm:ss dd-MM-yyyy", plateInfo.getDate()));
holder.readingDetail.setTag(plateInfo);
if(plateInfo.getBlackWhiteListNote() != null && !plateInfo.getBlackWhiteListNote().equals("")) {
if(plateInfo.getBlackWhiteListNote().contains("WHITELIST")) {
holder.layout.setBackgroundColor(Reso.getColor(context, R.color.red_light));
holder.whiteList.setVisibility(View.VISIBLE);
hotlistDrawn = true;
}
else {
holder.whiteList.setVisibility(View.INVISIBLE);
}
if(plateInfo.getBlackWhiteListNote().contains("BLACKLIST")) {
holder.layout.setBackgroundColor(Reso.getColor(context, R.color.red_light));
holder.blackList.setVisibility(View.VISIBLE);
hotlistDrawn = true;
}
else {
holder.blackList.setVisibility(View.INVISIBLE);
}
}
else {
holder.layout.setBackgroundColor(Reso.getColor(context, R.color.transparent));
holder.whiteList.setVisibility(View.INVISIBLE);
holder.blackList.setVisibility(View.INVISIBLE);
}
if(plateInfo.isRowSelected()) {
if(hotlistDrawn) {
holder.layout.setBackgroundDrawable(Reso.getDrawable(context, R.drawable.list_selector_red_bck_blue_border_normal));
}
else {
holder.layout.setBackgroundDrawable(Reso.getDrawable(context, R.drawable.list_selector_blue_border_normal));
}
}
else if(hotlistDrawn) {
holder.layout.setBackgroundColor(Reso.getColor(context, R.color.red_light));
}
else {
holder.layout.setBackgroundColor(Reso.getColor(context, R.color.transparent));
}
return view;
}
#Override
public int getCount() {
return plateList.size();
}
#Override
public PlateInfo getItem(int position) {
return plateList.get(position);
}
#Override
public boolean hasStableIds() {
return true;
}
}
The following code is called by the children threads.
Here it is the code that generates the issue:
mHandler.post(new Runnable() {
#Override
public void run() {
mLastPlateImage.setImageBitmap(plateImage);
mLastContextImage.setImageBitmap(contextImageResized);
mPlateInfoList.add(0, plateInfo);
// That is the problem
mPlateListAdapter.notifyDataSetChanged();
System.gc();
}
});

Related

Android ListView glitching back to top for a few seconds before it works properly

I am trying to make an application with a ListView that include a Country Flag and name. This is so that the user can click on them and be shown images of the country that they wouldve taken before. However for about 3 seconds when the listview loads if i try to scroll it will sort of glitch and send me back to top. This is the code..
public class CountriesListAdapter extends ArrayAdapter {
private int resource;
private LayoutInflater inflater;
private List<CountryModel> countryModels;
private WeakReference<TextView> selectedCountryIdtxt;
private boolean useFilter;
private WeakReference<ProgressBar> progressBarWeakReference;
public int getSelectedCountryId() {
return selectedCountryId;
}
public void setSelectedCountryId(int selectedCountryId) {
this.selectedCountryId = selectedCountryId;
}
private int selectedCountryId;
public CountriesListAdapter(#NonNull WeakReference<Context> context, int resourceId, WeakReference<TextView> textView, #NonNull List<CountryModel> countryModelList, boolean useFilter, WeakReference<ProgressBar> progressBarWeakReference){
super(context.get(), resourceId, countryModelList);
selectedCountryIdtxt = textView;
resource = resourceId; //the id of the template file
inflater = LayoutInflater.from(context.get());
this.countryModels = countryModelList;
selectedCountryId = -1;
this.useFilter = useFilter;
this.progressBarWeakReference = progressBarWeakReference;
}
public int getCount() {
if (countryModels != null)
return countryModels.size();
return 0;
}
public CountryModel getItem(int position) {
if (countryModels != null)
return countryModels.get(position);
return null;
}
public long getItemId(int position) {
if (countryModels != null)
return countryModels.get(position).hashCode();
return 0;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// this method is automatically called for every object in our list
//basically it's called for every single row before it is generated
// this method is called per row
convertView = (ConstraintLayout) inflater.inflate(resource, null);
//the variable countryModel is fiiled with current object that is being processed
final CountryModel countryModel = countryModels.get(position);
TextView countryName = convertView.findViewById(R.id.countryNamelbl);
final ImageView countryFlag = convertView.findViewById(R.id.countryFlagimg);
final ImageView checked = convertView.findViewById(R.id.countryCheckedimg);
//this is done for every object in the list
assert countryModel != null;
countryName.setText(countryModel.getName());
Picasso.get().load(countryModel.getImage()).fit().into(countryFlag);
if(!useFilter) {
if (selectedCountryId == countryModel.getId()) {
checked.setVisibility(View.VISIBLE);
} else {
checked.setVisibility(View.INVISIBLE);
}
}
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(!useFilter) {
if (checked.getVisibility() == View.VISIBLE) {
checked.setVisibility(View.INVISIBLE);
selectedCountryId = -1;
selectedCountryIdtxt.get().setText(String.valueOf(selectedCountryId));
} else {
if (selectedCountryId == -1) {
checked.setVisibility(View.VISIBLE);
selectedCountryId = countryModel.getId();
} else {
selectedCountryId = countryModel.getId();
notifyDataSetChanged();
}
selectedCountryIdtxt.get().setText(String.valueOf(selectedCountryId));
}
} else {
Intent i = new Intent(getContext(), PicturesActivity.class);
i.putExtra("countryId",countryModel.getId());
i.putExtra("countryName", countryModel.getName());
getContext().startActivity(i);
}
}
});
progressBarWeakReference.get().setVisibility(View.INVISIBLE);
return convertView;
}
public List<CountryModel> getCountryModels() {
return countryModels;
}
public void setCountryModels(List<CountryModel> countryModels) {
this.countryModels = countryModels;
}
}
The problem was actually in another class, i was calling the adapter for every list item instead of just once... oops.
Thanks for the replies though!

android finalizer never ends and collects old objects, is it normal?

my simple activity has got a listview holding 14 items(genre). when i run the app, i get the snapshot and there are one 1 GenreSelectionActivity and 14 Genre in the memory normally. then i pass to other activities and go back, there are 2 GenreSelectionActivity and 28 Genre. half of them coloured red, means in finalizerReference. then doing same navigation, it becomes 3 - 42 and so on. is it normal behaviour of finalizer?
i try to call "System.exit(0)" on destroy, old activity is cleaned but an annoying black screen appears on transition.
public class GenreSelectionActivity extends Activity {
Activity activity;
ListView listViewGenre;
GenreList genreList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.genre_list);
activity = this;
createGenrePlayButton();
listViewGenre = (ListView) findViewById(R.id.listGenre);
JSONObject jsonResponseGenres = s.readInternalStoragePrivate(Constants.GENRE_FILE_NAME, getApplicationContext());
JsonResolver jsonResolver = new JsonResolver();
genreList = jsonResolver.getGenreListWithPhasesFromJson(jsonResponseGenres);
final GenreCircularAdapter genreCircularAdapter = new GenreCircularAdapter(activity, R.layout.genre_row, genreList);
listViewGenre.setAdapter(genreCircularAdapter);
listViewGenre.setSelectionFromTop(genreCircularAdapter.MIDDLE, 0);
}
public void createGenrePlayButton() {
ImageView genrePlayButton = (ImageView) findViewById(R.id.genrePlayButton);
genrePlayButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
Intent questPage = new Intent(activity, QuestionManagerActivity.class);
questPage.putExtra("genre_name", "pop");
Phase selectedPhaseData = new Phase();
selectedPhaseData.setHighScore(0);
questPage.putExtra("selected_phase_data", selectedPhaseData);
activity.startActivity(questPage);
activity.finish();
//System.exit(0);
}
});
}
}
this is the adapter i use:
public class GenreCircularAdapter extends ArrayAdapter<Genre> {
private GenreList genreList;
private Activity activity;
LayoutInflater inflater;
public static final int HALF_MAX_VALUE = Constants.GENRE_CIRCULAR_LISTVIEW_SIZE / 2;
public final int MIDDLE;
public GenreCircularAdapter(Activity activity, int resource, GenreList genreList) {
super(activity, resource, genreList);
this.genreList = genreList;
this.activity = activity;
inflater = LayoutInflater.from(activity);
MIDDLE = HALF_MAX_VALUE - HALF_MAX_VALUE % genreList.size();
}
#Override
public int getCount() {
return Constants.GENRE_CIRCULAR_LISTVIEW_SIZE;
}
#Override
public Genre getItem(int position) {
return genreList.get(position % genreList.size());
}
#Override
public long getItemId(int position) {
return genreList.get(position % genreList.size()).getId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder genreRowHolder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.genre_row, parent, false);
genreRowHolder = new ViewHolder();
genreRowHolder.attachChildViews(convertView);
convertView.setTag(genreRowHolder);
} else
genreRowHolder = (ViewHolder) convertView.getTag();
Genre genre = getItem(position);
genreRowHolder.genreName.setText(genre.getName());
try {
int genreImageResID = activity.getResources().getIdentifier(String.valueOf("genre_" + genre.getId()), "drawable", activity.getPackageName());
genreRowHolder.genreImageView.setImageDrawable(activity.getResources().getDrawable(genreImageResID));
genreRowHolder.genreImageView.setColorFilter(0x96064e66, PorterDuff.Mode.SRC_ATOP);
} catch (Exception e){
Log.e("img_not_found", "genre_" + genre.getId() + " - " + getClass().getSimpleName());
}
return convertView;
}
private static class ViewHolder {
public TextView genreName;
public ImageView genreImageView;
public ImageView genreLockImageView;
public void attachChildViews (View convertView) {
genreName = (TextView) convertView.findViewById(R.id.genreName);
genreImageView = (ImageView) convertView.findViewById(R.id.genreImageView);
genreLockImageView = (ImageView) convertView.findViewById(R.id.genreLockImage);
}
}
}
i couldn't detect the problem. i tried that workaround, it seems troubleless for now.
#Override
protected void onDestroy() {
// remove all content view
((FrameLayout)findViewById(android.R.id.content)).removeAllViews();
// empty arraylist
genreList.clear();
genreList.trimToSize();
// call garbage collector (it may not effect anything)
Runtime.getRuntime().gc();
System.gc();
System.runFinalization();
}

When custom GridView with checkable items is scrolled, checkboxes incorrectly enable on random items

I'm trying to make a GridView full of checkboxes. I'm following the ViewHolder pattern to recycle views and attempt to set checkboxes to their correct values, but for some reason I can't seem to make them not duplicate.
After my debugging efforts, I've discovered that my SparseBooleanArray IS being correctly updated - it's just that applying it to the view seems to turn on the wrong checkboxes even when I'm applying them to the right positions.
Here's my GridView's entire adapter - relevant portions being getView and onCheckedChanged
// Our image adapter takes our list of thumbnails and creates a selectable grid full of asychroniously loaded images.
public class ThumbnailImageAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener {
Context mContext;
LayoutInflater mInflater;
SparseBooleanArray mCheckedStates;
private int mItemHeight = 0;
private int mNumColumns = 0;
private RelativeLayout.LayoutParams mImageViewLayoutParams;
private ArrayList<String> mList;
private ArrayList<String> mImageFullResUrls;
private String nextURL;
public ThumbnailImageAdapter(Context context) {
super();
mContext = context;
mInflater = LayoutInflater.from(mContext);
mImageViewLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
clear();
}
public ArrayList<String> getCheckedItems() {
ArrayList<String> checkedItems = new ArrayList<String>();
for (int i = 0; i < mList.size(); i++) {
if (mCheckedStates.get(i)) {
checkedItems.add(mImageFullResUrls.get(i));
}
}
return checkedItems;
}
public boolean hasSelectedItems() {
return mCheckedStates.indexOfValue(true) >= 0;
}
#Override
public int getCount() {
// If columns have yet to be determined, return no items
if (getNumColumns() == 0) {
return 0;
}
return mList.size();
}
#Override
public Object getItem(int position) {
return mImageFullResUrls.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getView(int position, View convertView, ViewGroup container) {
if(position >= getCount()) {
return null;
}
final ThumbnailViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.selectable_imageview, null);
holder = new ThumbnailViewHolder();
holder.checkbox = (CheckBox) convertView.findViewById(R.id.photo_checkbox);
holder.imageView = (SmartImageView) convertView.findViewById(R.id.photo_imageview);
convertView.setTag(holder);
} else {
holder = (ThumbnailViewHolder) convertView.getTag();
}
holder.checkbox.setTag(position);
holder.checkbox.setOnCheckedChangeListener(this);
holder.checkbox.setChecked(mCheckedStates.get(position, false));
holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
holder.imageView.setLayoutParams(mImageViewLayoutParams);
// Finally load the image asynchronously into the ImageView, this also takes care of
// setting a placeholder image while the background thread runs
holder.imageView.setImageUrl(mList.get(position));
final View finalView = convertView;
convertView.post(new Runnable() {
#Override
public void run() {
Rect delegateArea = new Rect();
holder.imageView.getHitRect(delegateArea);
finalView.setTouchDelegate(new TouchDelegate(delegateArea, holder.checkbox));
}
});
return convertView;
}
public void setItemHeight(int height) {
if (height == mItemHeight) {
return;
}
mItemHeight = height;
mImageViewLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, mItemHeight);
notifyDataSetChanged();
}
public int getNumColumns() {
return mNumColumns;
}
public void setNumColumns(int numColumns) {
mNumColumns = numColumns;
}
public void appendImage(String thumbUrl, String fullResUrl) {
if (!mList.contains(thumbUrl)) {
mList.add(thumbUrl);
mImageFullResUrls.add(fullResUrl);
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
}
}
}
public void prependImage(String thumbUrl, String fullResUrl) {
if (!mList.contains(thumbUrl)) {
mList.add(0, thumbUrl);
mImageFullResUrls.add(0, fullResUrl);
SparseBooleanArray shiftedArray = new SparseBooleanArray(mList.size());
// Shift our entire array one down (there has to be a better way to do this)
for (int i = 0; i < mCheckedStates.size(); i++) {
shiftedArray.put(mCheckedStates.keyAt(i) + 1, mCheckedStates.valueAt(i));
}
mCheckedStates = shiftedArray;
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
}
}
public void clear() {
mList = new ArrayList<String>();
mImageFullResUrls = new ArrayList<String>();
mCheckedStates = new SparseBooleanArray();
}
public String getNextURL() {
return this.nextURL;
}
public void setNextURL(String nextURL) {
this.nextURL = nextURL;
}
public ArrayList<String> getThumbnailURLs() {
return mList;
}
#Override
public void onCheckedChanged(CompoundButton checkBoxView, boolean isChecked) {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getActivity());
final int numPhotos = Integer.parseInt(settings.getString("num_photos", null));
if (mAdapter.getCheckedItems().size() > numPhotos) {
checkBoxView.setChecked(false); // Don't allow the user to select more than numPhotos photos
}
// This animates our image "pressed" and "unpressed" states
mCheckedStates.put((Integer) checkBoxView.getTag(), isChecked);
final ImageView image = (ImageView) ((ViewGroup) checkBoxView.getParent()).findViewById(R.id.photo_imageview);
int dpi = getResources().getDisplayMetrics().densityDpi;
int _12dp = (int) (12 * (dpi / 160f));
ValueAnimator animator;
if (isChecked) {
animator = ValueAnimator.ofInt(image.getPaddingRight(), _12dp);
} else {
animator = ValueAnimator.ofInt(image.getPaddingRight(), 0);
}
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int v = (Integer) valueAnimator.getAnimatedValue();
image.setPadding(v, v, v, v);
}
});
animator.setDuration(100);
animator.start();
mOnImageSelectionChangeListener.onImageSelectionChange(getCheckedItems());
getActivity().invalidateOptionsMenu();
}
}
static class ThumbnailViewHolder {
CheckBox checkbox;
SmartImageView imageView;
}
This is due to the way grid view recycles view's.
Implement the below for your adapter
implements CompoundButton.OnCheckedChangeListener
Then have a SpareBooleanArray to keep track of checked stated
SparseBooleanArray mCheckStates;
Then
mCheckStates = new SparseBooleanArray(your data size);
In getView
holder.chkSelect.setTag(position);
holder.chkSelect.setChecked(mCheckStates.get(position, false));
holder.chkSelect.setOnCheckedChangeListener(this);
Then override
public boolean isChecked(int position) {
return mCheckStates.get(position, false);
}
public void setChecked(int position, boolean isChecked) {
mCheckStates.put(position, isChecked);
}
public void toggle(int position) {
setChecked(position, !isChecked(position));
}
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
mCheckStates.put((Integer) buttonView.getTag(), isChecked);
}
Also move this
holder.imageView = (SmartImageView) convertView.findViewById(R.id.photo_imageview);
to the if part in getView
and change this
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(mImageViewLayoutParams);
// Finally load the image asynchronously into the ImageView, this also takes care of
// setting a placeholder image while the background thread runs
imageView.setImageUrl(mList.get(position));
to
holder.imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
holder.imageView.setLayoutParams(mImageViewLayoutParams);
// Finally load the image asynchronously into the ImageView, this also takes care of
// setting a placeholder image while the background thread runs
holder.imageView.setImageUrl(mList.get(position));
You can find a similar exmaple #
How to get checkbox state in a gridview

How to get context of an activity extending ListFragment from its adapter class?

This is my adapter class where I want to call startActionMode. I call it inside setActionMode method but got these errors:
Cannot cast from Context to ActivityFragment.
The method startActionMode(ActivityFragment.ActionModeCallback) is undefined for the type
ActivityFragment.
public class ListAdapter extends ArrayAdapter<ListGettersSetters>
{
ArrayList<ListGettersSetters> arrayListGettersSetters;
LayoutInflater layoutInflater;
Context context;
int Resource, i = 0, j = 0, checkedItemsCount = 0;
Animation animation1;
Animation animation2;
CheckBox flipCheckBox;
viewHolder holder;
ActionMode actionMode;
boolean isActionModeShowing;
static class viewHolder
{
public CheckBox imageView;
public TextView textViewName;
public TextView textViewData;
public TextView textViewDetails;
}
public ListAdapter(Context context, int resource, ArrayList<ListGettersSetters> arrayListGettersSetters)
{
super(context, resource, arrayListGettersSetters);
this.arrayListGettersSetters = arrayListGettersSetters;
Resource = resource;
this.context = context;
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
animation1 = AnimationUtils.loadAnimation(context, R.anim.to_middle);
animation2 = AnimationUtils.loadAnimation(context, R.anim.from_middle);
isActionModeShowing = false;
}
#Override
public int getCount()
{
return arrayListGettersSetters.size();
}
#Override
public ListGettersSettersgetItem(int position)
{
return arrayListGettersSetters.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
holder = new viewHolder();
if(convertView == null)
{
convertView = layoutInflater.inflate(Resource, null);
holder.imageView = (CheckBox) convertView.findViewById(R.id.id_for_checkBox);
holder.textViewName = (TextView) convertView.findViewById(R.id.id_for_name_textView);
holder.textViewData = (TextView) convertView.findViewById(R.id.id_for_data_textView);
holder.textViewDetails = (TextView) convertView.findViewById(R.id.id_for_details_textView);
convertView.setTag(holder);
}
else
{
holder = (viewHolder) convertView.getTag();
}
holder.textViewName.setText(getItem(position).getName());
holder.textViewData.setText(getItem(position).getData());
holder.textViewDetails.setText(getItem(position).getDetails());
holder.imageView.setTag(position);
holder.imageView.setOnClickListener(new OnClickListener()
{
public void onClick(View view)
{
flipCheckBox = (CheckBox) view;
flipCheckBox.clearAnimation();
flipCheckBox.setAnimation(animation1);
flipCheckBox.startAnimation(animation1);
setAnimListners(arrayListGettersSetters.get(Integer.parseInt(view.getTag().toString())));
}
});
return convertView;
}
private void setAnimListners(final ListGettersSetters listGettersSetters)
{
AnimationListener animationListener = new AnimationListener()
{
#Override
public void onAnimationStart(Animation animation)
{
if (animation == animation1)
{
flipCheckBox.clearAnimation();
flipCheckBox.setAnimation(animation2);
flipCheckBox.startAnimation(animation2);
}
else
{
listGettersSetters.setIsChecked(!listGettersSetters.isChecked());
setCount();
setActionMode();
}
}
public void setCount()
{
if (listGettersSetters.isChecked())
{
checkedItemsCount++;
}
else
{
if (checkedItemsCount != 0)
{
checkedItemsCount--;
}
}
Log.v("Checked items count", checkedItemsCount + "");
}
private void setActionMode()
{
if (checkedItemsCount > 0)
{
if (!isActionModeShowing)
{
actionMode = ((ActivityFragment) context).startActionMode(new ActivityFragment.ActionModeCallback(context));
isActionModeShowing = true;
}
}
else if (actionMode != null)
{
actionMode.finish();
isActionModeShowing = false;
}
if (actionMode != null)
{
actionMode.setTitle(String.valueOf(checkedItemsCount));
}
notifyDataSetChanged();
}
#Override
public void onAnimationRepeat(Animation animation)
{
}
#Override
public void onAnimationEnd(Animation animation)
{
}
};
animation1.setAnimationListener(animationListener);
animation2.setAnimationListener(animationListener);
}
This is my ActivityFragment class also in which i have implemented a class named ActionModeCallback which is called in my adapter class. Also when i take context of ActivityFragment in this inner class then also get the same errors.
public class ActivityFragment extends ListFragment
{
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstanceState)
{
View view = layoutInflater.inflate(R.layout.folders_fragment_listview, null, false);
return view;
}
public static final class ActionModeCallback implements ActionMode.Callback
{
Context context;
public ActionModeCallback(Context context)
{
this.context = context;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem)
{
Toast toast = null;
ArrayList<FoldersFragmentGettersSetters> selectedListItems = new ArrayList<FoldersFragmentGettersSetters>();
StringBuilder selectedItems = new StringBuilder();
for (FoldersFragmentGettersSetters foldersFragmentGettersSetters : ((ActivityFragment ) context).listAdapter.arrayListGettersSetters)
{
if (foldersFragmentGettersSetters.isChecked())
{
selectedListItems.add(foldersFragmentGettersSetters);
}
}
if (menuItem.getTitle().equals("Delete"))
{
toast = Toast.makeText(context, "Delete: " + selectedItems.toString(), Toast.LENGTH_SHORT);
}
else if (menuItem.getTitle().equals("Archive"))
{
toast = Toast.makeText(context, "Archive: " + selectedItems.toString(), Toast.LENGTH_SHORT);
}
else if (menuItem.getTitle().equals("Mark unread"))
{
toast = Toast.makeText(context, "Mark unread: " + selectedItems.toString(), Toast.LENGTH_SHORT);
}
else if (menuItem.getTitle().equals("Move"))
{
toast = Toast.makeText(context, "Move: " + selectedItems.toString(), Toast.LENGTH_SHORT);
}
else if (menuItem.getTitle().equals("Remove star"))
{
toast = Toast.makeText(context, "Remove star: " + selectedItems.toString(), Toast.LENGTH_SHORT);
}
if (toast != null)
{
toast.show();
}
actionMode.finish();
return true;
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu)
{
menu.add("Delete").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Archive").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Mark unread").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Move").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add("Remove star").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
return true;
}
#Override
public void onDestroyActionMode(ActionMode actionMode)
{
((ActivityFragment ) context).inboxAdapter.checkedItemsCount = 0;
((ActivityFragment ) context).inboxAdapter.isActionModeShowing = false;
for (FoldersFragmentGettersSetters foldersFragmentGettersSettersItem : ((InboxFragment) context).inboxList)
{
foldersFragmentGettersSettersItem.setIsChecked(false);
}
((ActivityFragment ) context).listAdapter.notifyDataSetChanged();
Toast.makeText(context, "Action mode closed", Toast.LENGTH_SHORT).show();
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu)
{
return false;
}
}
}
Modify the constructor of your ListAdapter from
public ListAdapter(Context context, int resource, ArrayList<ListGettersSetters> arrayListGettersSetters)
to
public ListAdapter(ActivityFragment context, int resource, ArrayList<ListGettersSetters> arrayListGettersSetters)
One good approach would be to use callback.
Create callback interface (a listener) inside your adapter class.
Declare instance variable for interface, e.g. startActionModeCallback.
In adapter constructor, pass listener object and assign it to startActionModeCallback.
When you will create adapter's instance in ActivityFragment, pass it as listener and implement its callback method in fragment.
Call callback method anywhere in your adapter, and it will be listened by fragment.
Hope it makes sense to you. You can ask me for clarification. Good luck!
EXAMPLE
Adapter Class
public class ListAdapter extends ArrayAdapter<ListGettersSetters>
{
Interface StartActionInterface
{
public void startActionMode();
}
//declare other instance variables and add following
StartActionInterface startActionModeListener;
//change your constructor as:
public ListAdapter(Context context, int resource, ArrayList<ListGettersSetters> arrayListGettersSetters, StartActionInterface listener)
{
//normal code
startActionModeListener = listener;
}
}
ActivityFragment
public class ActivityFragment extends ListFragment implements StartActionInterface
{
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstanceState)
{
View view = layoutInflater.inflate(R.layout.folders_fragment_listview, null, false);
////////initialize adapter and pass `this` in last argument
return view;
}
//Implement callback method. Also implement `setActionMode()` method here in fragment.
void startActionMode()
{
setActionMode();
}
}
Here in function setActionMode(), replace following line:
if (!isActionModeShowing)
{
actionMode = ((ActivityFragment) context).startActionMode(new ActivityFragment.ActionModeCallback(context));
isActionModeShowing = true;
}
with:
if (!isActionModeShowing)
{
actionMode = getActivity().startActionMode(new ActionModeCallback(getActivity()));
isActionModeShowing = true;
}

List view not getting refreshed

I have displayed all the contacts within the phone along with a check box in a list view. Now when the user checks say A and B and clicks on "ok" button, then what I want is to display the list again when making all the check box checked value to false. For that, I have created a method but when I call this method the value of the selected contacts is set to unchecked only when the list is scrolled, else it remains unchecked.
Whats the problem with my code???
Code
public void getContactSync(Context context, ArrayList<ContactModel> data) {
setListAdapter(null);
contactListAdapter = new ContactListAdapter(context, data);
setListAdapter(contactListAdapter);
// contactListAdapter.notifyDataSetChanged();
}
On OK button click
Arrays.fill(ContactListAdapter.contacts, 0);
contactListFragment.getContactSync(getActivity(), dbHandler.getAlGetContacts());
Custom Adapter
public class ContactListAdapter extends BaseAdapter {
private Context context;
private ArrayList<ContactModel> data;
DbHandler dbHandler;
public static int[] contacts;
static ArrayList<String> contactsSepetrated;
public static ArrayList<String> contactsId;
public ContactListAdapter(Context context, ArrayList<ContactModel> data) {
this.context = context;
this.data = data;
contacts = new int[data.size()];
contactsSepetrated = new ArrayList<String>();
contactsId = new ArrayList<String>();
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(final int i, View view, ViewGroup viewGroup) {
final ViewHolder holder;
dbHandler = new DbHandler(context);
if (view == null) {
holder = new ViewHolder();
view = LayoutInflater.from(context).inflate(R.layout.contact_custom_list, viewGroup, false);
holder.tvContact = (TextView) view.findViewById(R.id.tv_contact_name);
holder.checkBox = (CheckBox) view.findViewById(R.id.cb_contact_checkbox);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (compoundButton == holder.checkBox) {
if (b) {
contacts[i] = 1;
//dbHandler.updateContactList(data.get(i).getUserID(), 1);
//
} else {
contacts[i] = 0;
}
}
}
}
);
holder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (contacts[i] == 1) {
contactsSepetrated.add(data.get(i).getContactName());
Log.e("Contact values", contactsSepetrated.toString());
contactsId.add(data.get(i).getUserID());
Log.e("Position", "" + i);
} else if (contacts[i] == 0) {
contactsSepetrated.remove(data.get(i).getContactName());
contactsId.remove(data.get(i).getUserID());
Log.e("Contact values", contactsSepetrated.toString());
Log.e("Position", "" + i);
}
ShareWithinpocketDocs.etContactsList.setText(contactsSepetrated.toString().subSequence(1, contactsSepetrated.toString().length() - 1));
}
});
if (contacts[i] == 0) {
holder.checkBox.setChecked(false);
// emailSeperated.remove(data.get(i).getEmail());
// Log.e("Email values", emailSeperated.toString());
// ShareWithinpocketDocs.etEmailLists.setText(emailSeperated.toString());
} else {
holder.checkBox.setChecked(true);
// emailSeperated.add(data.get(i).getEmail());
// Log.e("Email values", emailSeperated.toString());
}
holder.tvContact.setText(data.get(i).getContactName());
return view;
}
private class ViewHolder {
TextView tvContact;
CheckBox checkBox;
}
}
on click of checkbox inside adapter just call notifydatasetchanged() it will solve your problem
holder.checkBox
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton,
boolean b) {
if (compoundButton == holder.checkBox) {
if (b) {
contacts[i] = 1;
// dbHandler.updateContactList(data.get(i).getUserID(),
// 1);
//
notifyDataSetChanged();
} else {
contacts[i] = 0;
notifyDataSetChanged();
}
}
}
}
);
if you want to refresh adapter on ok button click add this to ok button click
adapter.notifydatasetchagned()
Try to call setListAdapter(contactListAdapter); again inside your onClick()

Categories

Resources