android-advancedrecyclerview
android-advancedrecyclerview copied to clipboard
last item diplay empty
I use android-advancedrecyclerview to display prod list, product's name is header, product's detail is child. in some phone , when last group item scrolling to visiability , the child 's button and editext display emtpy , very strange.

thank you for help.
Hmm. This seems very strange. Is the issue occurs every time on specific devices? Have you verified that bindViewHolder() is called for the last item?
Also, I want more info to investigate the issue;
- Version of Advanced RecyclerView
- Version of support libraries
- Android OS version
- Which features (DnD, swipe, expand, ...) do you use?
- How many item view types int the list?
Thanks.
thanks for your response very much.
- advrecycler_view_version = '0.8.6@aar' // I have test ver.0.10.3 ,the issue occurs also .
- android_support_version = '24.2.1'
- Android OS and Phone: 4.4.2 (19),Huawei:HUAWEI P7-L07:armeabi-v7a (ps: the phone have the Navigation Bar the bottom, as menu,home, back)
- Just use expand
- just one view types , bindViewHolder is called ,I has debug this case。
when view init, list has 4 items ,last item's header visiblity, last item 's child under the virtual key , scroll up ,the strang thing must come, textview.settext("string") is ok, but EditText and Button setText do not work, is empty. the stranger thing is , when list more then 6 items , everything is ok ,last item do work.
code
package com.mlt.mobileclient.activity.check.display;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.h6ah4i.android.widget.advrecyclerview.expandable.ExpandableSwipeableItemAdapter;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem;
import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractExpandableItemAdapter;
import com.mlt.mobile.base.bean.ProdHeaderBean;
import com.mlt.mobile.base.bean.Production;
import com.mlt.mobile.base.utils.LogUtil;
import com.mlt.mobile.base.utils.StringUtil;
import com.mlt.mobile.base.vo.BaseProdDataProvider;
import com.mlt.mobile.base.vo.ProdGroupWrap;
import com.mlt.mobile.base.vo.ProdWrap;
import com.mlt.mobileclient.component.common.MltDateComponent;
import com.mlt.mobileclient.myview.dialog.SystemCommonDialog;
import com.mlt.mobileclient.util.MathUtil;
import com.mlt.mobileclient.visiter.R;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
public class CheckDisplayAdapter extends AbstractExpandableItemAdapter<CheckDisplayGroupViewHolder, CheckDisplayChildViewHolder>
implements ExpandableSwipeableItemAdapter<CheckDisplayGroupViewHolder, CheckDisplayChildViewHolder> {
private static final String TAG = CheckDisplayAdapter.class.getSimpleName();
private Context mContext;
private BaseProdDataProvider mProvider;
public CheckDisplayAdapter(Context mContext, BaseProdDataProvider provider) {
this.mContext = mContext;
this.mProvider = provider;
// ExpandableItemAdapter, ExpandableDraggableItemAdapter and ExpandableSwipeableItemAdapter
// require stable ID, and also have to implement the getGroupItemId()/getChildItemId() methods appropriately.
setHasStableIds(true);
}
/**
* 写入组的布局文件
*
* @param parent The ViewGroup into which the new View will be added after it is bound to an adapter position
* @param viewType The view type of the new View
*/
@Override
public CheckDisplayGroupViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
final View v = inflater.inflate(R.layout.check_display_header_item, parent, false);
return new CheckDisplayGroupViewHolder(v);
}
/**
* 写入子的布局文件
*
* @param parent The ViewGroup into which the new View will be added after it is bound to an adapter position
* @param viewType The view type of the new View
*/
@Override
public CheckDisplayChildViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
final View v = inflater.inflate(R.layout.check_display_child_item, parent, false);
return new CheckDisplayChildViewHolder(v, mProvider);
}
@Override
public int getGroupCount() {
return mProvider.getGroupCount();
}
@Override
public int getChildCount(int groupPosition) {
return mProvider.getChildCount(groupPosition);
}
@Override
public long getGroupId(int groupPosition) {
return mProvider.getGroupItem(groupPosition).getGroupId();
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return mProvider.getChildItem(groupPosition, childPosition).getChildId();
}
@Override
public int getGroupItemViewType(int groupPosition) {
return 0;
}
@Override
public int getChildItemViewType(int groupPosition, int childPosition) {
return 0;
}
/**
* 建立起ViewHolder中视图与数据的关联
*
* @param holder The ViewHolder which should be updated to represent the contents of the item at the given position in the data set
* @param groupPosition The position of the group item within the adapter's data set
* @param viewType The view type code
*/
@Override
public void onBindGroupViewHolder(final CheckDisplayGroupViewHolder holder, final int groupPosition, int viewType) {
holder.isGroupBinding = true;
//组的数据
final ProdGroupWrap groupWrap = mProvider.getGroupItem(groupPosition);
final ProdHeaderBean prodHeaderBean = groupWrap.getHeader();
holder.mProductName.setText(prodHeaderBean.getProdName());
groupWrap.setPinned(false);
//回退动画
// holder.setSwipeItemHorizontalSlideAmount(groupWrap.isPinned() ? SwipeableItemConstants.OUTSIDE_OF_THE_WINDOW_LEFT : 0);
holder.isGroupBinding = false;
}
@Override
public void onBindChildViewHolder(final CheckDisplayChildViewHolder holder, final int groupPosition, final int childPosition, int viewType) {
holder.isChildBinding = true;
//子的数据
final ProdWrap prodWrap = mProvider.getChildItem(groupPosition, childPosition);
final Production prod = prodWrap.getItem();
holder.updatePosition(groupPosition, childPosition);
holder.mUnitPrice.setText(MathUtil.ceil(prod.getRealtimeOutPrice(),2));
holder.mProductShrimpRow.getEditText().setText(prod.getShrimpRow() < 0 ? "" : Integer.toString(prod.getShrimpRow()));
/**
* 数量输入
*/
if (prod.isStandard()) {
holder.mProductCountEt.getEditText().setText(prod.getCountNeg() < 0 ? "" : Integer.toString(prod.getCountNeg()));
holder.mProductBigDateCountEt.getEditText().setText(prod.getBigDateCount() < 0 ? "" : Integer.toString(prod.getBigDateCount()));
holder.mProductCountEt.setHasPoint(false);
holder.mProductBigDateCountEt.setHasPoint(false);
} else {
holder.mProductCountEt.getEditText().setText(prod.getSumWeightNeg() < 0 ? "" : MathUtil.hideZeroDecimal(prod.getSumWeightNeg()));
holder.mProductBigDateCountEt.getEditText().setText(prod.getBigDateWeight() < 0 ? "" : MathUtil.hideZeroDecimal(prod.getBigDateWeight()));
holder.mProductCountEt.setHasPoint(true);
holder.mProductBigDateCountEt.setHasPoint(true);
}
/**
* 以下为日期选择按钮逻辑
*/
if (StringUtil.isNotNull(prod.getProductionDate())) {
holder.mProduceDate.setText(prod.getProductionDate());
final String time = prod.getProductionDate();
this.initDatePickerDialog(time, holder.mProduceDate);
} else {
holder.mProduceDate.setText("");
}
prodWrap.setPinned(false);
//回退动画
// holder.setSwipeItemHorizontalSlideAmount(prodWrap.isPinned() ? SwipeableItemConstants.OUTSIDE_OF_THE_WINDOW_LEFT : 0);
holder.isChildBinding = false;
}
/**
* 是否能展开
*/
@Override
public boolean onCheckCanExpandOrCollapseGroup(CheckDisplayGroupViewHolder holder, int groupPosition, int x, int y, boolean expand) {
return false;
}
/**
* 移除全部
*/
public void clearGroupsItems() {
mProvider.removeAllItems();
}
/**
* 组的滑动控制
*
* @return 返回值决定了组的滑动效果 BaseExpandableSwipeableItemAdapter里有所有可展开状态下的的滑动效果
*/
@Override
public int onGetGroupItemSwipeReactionType(CheckDisplayGroupViewHolder holder, int groupPosition, int x, int y) {
return Swipeable.RESULT_NONE;
}
/**
* 子的滑动控制
*
* @return 返回值决定了子的滑动效果 BaseExpandableSwipeableItemAdapter里有所有可展开状态下的的滑动效果
*/
@Override
public int onGetChildItemSwipeReactionType(CheckDisplayChildViewHolder holder, int groupPosition, int childPosition, int x, int y) {
return Swipeable.RESULT_NONE;
}
@Override
public void onSetGroupItemSwipeBackground(CheckDisplayGroupViewHolder holder, int groupPosition, int type) {
}
@Override
public void onSetChildItemSwipeBackground(CheckDisplayChildViewHolder holder, int groupPosition, int childPosition, int type) {
}
}


@lengxf Hi. I have checked your adapter code over and over again, but I cannot find out any reasons that cause the issue.
However, I am now curious about the CheckDisplayChildViewHolder. I guess this class is attaching a TextWatcher to EditTexts in its constructor 🤔
@h6ah4i Yes, you guess right. Every EditText has one more TextWatchers:
class CheckDisplayChildViewHolder extends BaseViewHolder {
private static final int MAX_INT = 99999;
private static final Double MAX_DOUBLE = 99999.999;
public final Button mUnitPrice;
public final MltEditTextComponent mProductShrimpRow;
public final MltEditTextComponent mProductCountEt;
public final MltEditTextComponent mProductBigDateCountEt;
public final MltDateComponent mProduceDate;
public boolean isChildBinding;
WheelViewAdapter mWheelViewAdapter;
private int groupPosition;
private int childPosition;
private BaseProdDataProvider mProvider;
private Production mProd;
private Context mContext;
public CheckDisplayChildViewHolder(View v, BaseProdDataProvider prodDataProvider) {
super(v);
mContext = v.getContext();
this.mProvider = prodDataProvider;
mUnitPrice = (Button) v.findViewById(R.id.produce_unit_price);
mUnitPrice.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showPriceWheel(0); //priceType 不限制上下调
}
});
this.mProductShrimpRow = new MltEditTextComponent(v.getContext(),
(EditText) v.findViewById(R.id.product_Shrimp_row_et),
"countEdit");
this.mProductShrimpRow.getEditText().setInputType(InputType.TYPE_NULL);
this.mProductShrimpRow.setMaxInputNumber(2);
this.mProductShrimpRow.getEditText().addTextChangedListener(new ProdShrimpRowInputWatcher(mProductShrimpRow.getEditText()));
this.mProductCountEt = new MltEditTextComponent(v.getContext(),
(EditText) v.findViewById(R.id.product_inventory_et),
"product_inventory_et");
this.mProductCountEt.getEditText().setInputType(InputType.TYPE_NULL);
this.mProductCountEt.getEditText().addTextChangedListener(new ProdInventoryInputWatcher(mProductCountEt.getEditText()));
this.mProductBigDateCountEt = new MltEditTextComponent(v.getContext(),
(EditText) v.findViewById(R.id.product_big_date_inventory_et),
"product_big_date_inventory_et");
this.mProductBigDateCountEt.getEditText().setInputType(InputType.TYPE_NULL);
this.mProductBigDateCountEt.getEditText().addTextChangedListener(new ProdBigDateInventoryInputWatcher(mProductBigDateCountEt.getEditText()));
this.mProduceDate = new MltDateComponent(v.getContext(), (Button) itemView.findViewById(R.id.produce_date), "prod_date");
this.mProduceDate.setCallback(new ProduceDatePick());
}
public void updatePosition(int groupPosition, int childPosition) {
this.groupPosition = groupPosition;
this.childPosition = childPosition;
this.mProd = mProvider.getChildItem(groupPosition, childPosition).getItem();
mProductCountEt.setHasPoint(!mProd.isStandard());
checkInput();
}
private void showPriceWheel(final int priceType) {
final int[] ids_temp =
{R.id.point1, R.id.point0, R.id.uint, R.id.ten,
R.id.hundred, R.id.thru, R.id.tenthru};
try {
mWheelViewAdapter = new WheelViewAdapter(new CallBack() {
@Override
public void exec(final Object[] objs) {
double setedPrice;
String setedPricePre;
// 如果存在第二个参数 则说明,是清空价格
if (objs.length > 1) {
} else {
final int[] values = (int[]) objs[0];
final StringBuffer value = new StringBuffer();
for (int value1 : values) {
value.append(value1);
}
// 截取拼接价格信息
setedPricePre =
value.substring(0, value.length() - 2) + "."
+ value.substring(value.length() - 2);
setedPrice = "".equals(setedPricePre) ? 0 : Double.parseDouble(setedPricePre);
if (priceType == 1) {
//单价仅下调
if (mProd.getRealtimeOutPrice() - setedPrice < 0) {
ToastManager.showToastShort("只允许下调价格");
return;
}
} else if (priceType == 2) {
//单价仅上调
if (mProd.getRealtimeOutPrice() - setedPrice > 0) {
ToastManager.showToastShort("只允许上调价格");
return;
}
}
mProd.setRealtimeOutPrice(setedPrice);
mUnitPrice.setText(String.format("%.2f", setedPrice));
}
}
}, mContext);
mWheelViewAdapter.initData(ids_temp);
this.mWheelViewAdapter.setDecimalDigits(2);
this.mWheelViewAdapter.setDialogTitle("修改单价");
final int[] currentPrice = this.setPriceForWheel(String.format("%.2f", mProd.getRealtimeOutPrice()), ids_temp);
this.mWheelViewAdapter.getAlertDialog().show();
mWheelViewAdapter.setNum(currentPrice);
} catch (final Exception e) {
LogUtil.log(e);
}
}
/**
* <pre>
* 功能描述:为 价格Wheel设置初始值
* 使用示范:
*
* @return </pre>
*/
public int[] setPriceForWheel(String price, final int[] ids_temp) {
final int[] currentPrice = new int[ids_temp.length];
final StringBuilder buffer = new StringBuilder();
if ((price != null) && !("".equals(price))) {
final StringBuilder builder = new StringBuilder(price);
if (builder.substring(builder.lastIndexOf(".")).length() <= 2) {
builder.append("0");
}
builder.deleteCharAt(builder.indexOf("."));
for (int i = 0; i < (ids_temp.length - builder.length()); i++) {
buffer.append("0");
}
if (buffer.length() > 0) {
price = buffer.toString() + builder.toString();
} else {
price = builder.toString();
}
for (int i = 0; i < price.length(); i++) {
currentPrice[i] = Integer.parseInt(new String(new char[]{price.charAt(i)}));
}
}
return currentPrice;
}
private void checkInput() {
if (mProd.isStandard()) {
if (mProd.getCountNeg() > 0) {
enableBigDate();
}
} else {
if (mProd.getSumWeight() > 0) {
enableBigDate();
}
}
if (mProd.getShrimpRow() > 0) {
enableBigDate();
} else {
if (mProd.isStandard()) {
if (mProd.getCountNeg() <= 0) {
clearAndDisableBigDate();
}
} else {
if (mProd.getSumWeight() <= 0) {
clearAndDisableBigDate();
}
}
}
}
private void clearAndDisableBigDate() {
mProd.setBigDateCount(-1);
mProd.setBigDateWeight(-1);
mProd.setProductionDate("");
mProductBigDateCountEt.getEditText().setText("");
mProductBigDateCountEt.setEnable(false);
mProduceDate.getDataET().setText("");
mProduceDate.getDataET().setEnabled(false);
}
private void enableBigDate() {
mProduceDate.getDataET().setEnabled(true);
mProductBigDateCountEt.setEnable(true);
}
private class ProduceDatePick implements CallBack {
@Override
public void exec(final Object[] objs) {
if (isChildBinding) return;
String currDate = (String) objs[0];
final String date = DateUtil.getDateyyyy_MM_dd();
if (DateUtil.compareDate(currDate, "yyyy-MM-dd", date, "yyyy-MM-dd") > 0) {
currDate = date;
mProduceDate.resetDate();
Toast.makeText(mProduceDate.getDataET().getContext(), "生产日期选择不正确", Toast.LENGTH_SHORT).show();
}
mProduceDate.setValue(currDate);
mProd.setProductionDate(currDate);
}
}
private class ProdInventoryInputWatcher implements TextWatcher {
// private final int MAX_COUNT = 99999;
private final Pattern COUNT = Pattern.compile("^[0-9]{1,4}$");
private final Pattern WEIGHT = Pattern.compile("^[0-9]{1,4}(\\.[0-9]{1,3})?$");
private final Pattern PART = Pattern.compile("^[0-9]{1,4}\\.$");
private String oldString = "";
private EditText mEditText;
public ProdInventoryInputWatcher(EditText editText) {
mEditText = editText;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (isChildBinding) return;
String tempStr = s.toString();
//判断空字符
if (tempStr.equals("")) {
if (mProd.isStandard()) {
mProd.setCount(-1);
} else {
mProd.setSumWeight(-1);
}
oldString = "";
// mProvider.calculateSum();
checkInput();
return;
}
//控制非法字符
if (mProd.isStandard()) {
if (COUNT.matcher(tempStr).matches()) {
} else {
mEditText.setText(oldString);
mEditText.setSelection(mEditText.getText().length());
return;
}
} else {
if (WEIGHT.matcher(tempStr).matches() || PART.matcher(tempStr).matches()) {
} else {
mEditText.setText(oldString);
mEditText.setSelection(mEditText.getText().length());
return;
}
}
//控制长度
if (PART.matcher(tempStr).matches()) {
tempStr = tempStr.replace(".", "");
}
/* if (Double.parseDouble(tempStr) > MAX_COUNT) {
holder.mEditText.setText(String.valueOf(MAX_COUNT));
holder.mEditText.setSelection(holder.mEditText.getText().length());
return;
}*/
//赋值
if (mProd.isStandard()) {
int input = Integer.parseInt(tempStr);
if (mProd.getBigDateCount()>=0&&input < mProd.getBigDateCount()) {
ToastManager.showToastShort(mProd.getName()+",库存不能小于大库龄库存");
/*mEditText.setText(oldString);
mEditText.setSelection(mEditText.getText().length());
return;*/
mProd.setCount(input);
} else {
mProd.setCount(input);
}
} else {
double input = Double.parseDouble(tempStr);
if (mProd.getBigDateWeight()>=0&&input < mProd.getBigDateWeight()) {
ToastManager.showToastShort(mProd.getName()+",库存不能小于大库龄库存");
/* mEditText.setText(oldString);
mEditText.setSelection(mEditText.getText().length());
return;*/
mProd.setSumWeight(input);
} else {
mProd.setSumWeight(input);
}
}
oldString = s.toString();
checkInput();
// mProvider.calculateSum();
}
}
private class ProdBigDateInventoryInputWatcher implements TextWatcher {
// private final int MAX_COUNT = 99999;
private final Pattern COUNT = Pattern.compile("^[0-9]{1,4}$");
private final Pattern WEIGHT = Pattern.compile("^[0-9]{1,4}(\\.[0-9]{1,3})?$");
private final Pattern PART = Pattern.compile("^[0-9]{1,4}\\.$");
private String oldString = "";
private EditText mEditText;
public ProdBigDateInventoryInputWatcher(EditText editText) {
mEditText = editText;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (isChildBinding) return;
String tempStr = s.toString();
//判断空字符
if (tempStr.equals("")) {
if (mProd.isStandard()) {
mProd.setBigDateCount(-1);
} else {
mProd.setBigDateWeight(-1);
}
oldString = "";
return;
}
//控制非法字符
if (mProd.isStandard()) {
if (COUNT.matcher(tempStr).matches()) {
} else {
mEditText.setText(oldString);
mEditText.setSelection(mEditText.getText().length());
return;
}
} else {
if (WEIGHT.matcher(tempStr).matches() || PART.matcher(tempStr).matches()) {
} else {
mEditText.setText(oldString);
mEditText.setSelection(mEditText.getText().length());
return;
}
}
//控制长度
if (PART.matcher(tempStr).matches()) {
tempStr = tempStr.replace(".", "");
}
/* if (Double.parseDouble(tempStr) > MAX_COUNT) {
holder.mEditText.setText(String.valueOf(MAX_COUNT));
holder.mEditText.setSelection(holder.mEditText.getText().length());
return;
}*/
//赋值
if (mProd.isStandard()) {
mProd.setBigDateCount(Integer.parseInt(tempStr));
if (mProd.getBigDateCount() > mProd.getCountNeg()) {
ToastManager.showToastShort(mProd.getName() + ",大库龄库存应不大于其库存数量");
mProd.setCount(mProd.getBigDateCount());
mProductCountEt.getEditText().setText(mProd.getCountNeg() < 0 ? "" : Integer.toString(mProd.getCountNeg()));
}
} else {
mProd.setBigDateWeight(Double.parseDouble(tempStr));
if (mProd.getBigDateWeight() > mProd.getSumWeightNeg()) {
ToastManager.showToastShort(mProd.getName() + ",大库龄库存应不大于其库存数量");
mProd.setSumWeight(mProd.getBigDateWeight());
mProductCountEt.getEditText().setText(mProd.getSumWeightNeg() < 0 ? "" : MathUtil.hideZeroDecimal(mProd.getSumWeightNeg()));
}
}
oldString = s.toString();
mProvider.calculateSum();
}
}
private class ProdShrimpRowInputWatcher implements TextWatcher {
// private final int MAX_COUNT = 99;
private final Pattern COUNT = Pattern.compile("^[0-9]{1,2}$");
private String oldString = "";
private EditText mEditText;
public ProdShrimpRowInputWatcher(EditText editText) {
mEditText = editText;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (isChildBinding) return;
String tempStr = s.toString();
//判断空字符
if (tempStr.equals("")) {
oldString = "";
mProd.setShrimpRow(-1);
checkInput();
return;
}
//控制非法字符
if (COUNT.matcher(tempStr).matches()) {
} else {
mEditText.setText(oldString);
mEditText.setSelection(mEditText.getText().length());
return;
}
mProd.setShrimpRow(Integer.parseInt(tempStr));
oldString = s.toString();
checkInput();
}
}
}
I think TextWatcher do not lead the problem . Other child item work well, TextWatcher is the same . I do not know different ondraw between EditText and TextView , TextView make work, why not do EditText at that stuation?