【问题标题】:android - RecyclerView updating every second and have a longPressListenerandroid - RecyclerView 每秒更新一次并有一个 longPressListener
【发布时间】:2016-10-24 09:14:14
【问题描述】:

我在每个列表项中有一个带有计数器的RecyclerView,当调用计数器回调时,它更新了相关字段并调用nottifyDataSetChanged

它工作正常,但问题是,我还附加了一个长按监听器,因为在用户按下项目时数据会更新,因此按下会丢失

我该如何处理?

更新代码:

public void setCountDown(int countDown){
    mCountDown = countDown;
    notifyDataSetChanged();
}

长按监听器:

    holder.container.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            FragmentManager fm = ((AppCompatActivity)activity).getSupportFragmentManager();
            EditAccountFragment editAccountFragmentDialog = EditAccountFragment.newInstance(_id);
            editAccountFragmentDialog.show(fm, "fragment_edit_account");

            return false;
        }
    });

应要求添加适配器

public class AccountAdapter extends RecyclerView.Adapter<AccountAdapter.ItemViewHolder> {

    private static final String TAG = "ITEM_ADAPTER";

    private Cursor itemCursor;
    private Activity activity;
    private ItemColumnIds feedColumnIds;
    private int mCountDown;
    private boolean ignoreDatasetChange = false;

    /**
     * initilaizer for recycler view adapter, takes in activity although better way is to handle
     * activity related tasks within activiyt, but this is just done to speed up the overall process
     * @param activity
     */
    public AccountAdapter(Activity activity){
        this.activity = activity;
    }

    @Override
    public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(activity).inflate(R.layout.account_item,
                parent, false);

        feedColumnIds = new ItemColumnIds();

        if (itemCursor != null){
            // initilize column indices information
            feedColumnIds.colId = itemCursor.getColumnIndex(
                    AuthContract.AccountEntry._ID);
            feedColumnIds.colAcctId = itemCursor.getColumnIndex(
                    AuthContract.AccountEntry.COLUMN_USERNAME);
            feedColumnIds.colPin = itemCursor.getColumnIndex(
                    AuthContract.AccountEntry.COLUMN_PIN);
            feedColumnIds.colIssuer = itemCursor.getColumnIndex(
                    AuthContract.AccountEntry.COLUMN_ISSUER);
        }

        return new ItemViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ItemViewHolder holder, int position) {

        if(itemCursor == null)
            return;

        if(!itemCursor.moveToPosition(position))
            return;

        //get values from cursor
        String pin = itemCursor.getString(feedColumnIds.colPin);
        String email = itemCursor.getString(feedColumnIds.colAcctId);
        String issuer = itemCursor.getString(feedColumnIds.colIssuer);
        final long _id = itemCursor.getLong(feedColumnIds.colId);


        //set view values
        holder.tvEmail.setText(email);
        holder.tvPin.setText(pin);
        holder.tvIssuer.setText(issuer);
        holder.apCountDown.setProgress(mCountDown);

        holder.container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String pin = holder.tvPin.getText().toString();
                ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
                ClipData clip = ClipData.newPlainText("Secret Key", pin);
                clipboard.setPrimaryClip(clip);

                Toast.makeText(activity, "OTP code "+ pin +" copied to clipboard", Toast.LENGTH_SHORT).show();

            }
        });

        holder.container.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                FragmentManager fm = ((AppCompatActivity)activity).getSupportFragmentManager();
                EditAccountFragment editAccountFragmentDialog = EditAccountFragment.newInstance(_id);
                editAccountFragmentDialog.show(fm, "fragment_edit_account");

                return false;
            }

        });

    }

    @Override
    public int getItemCount() {
        if(itemCursor == null)
            return 0;
        return itemCursor.getCount();
    }



    /**
     * close previurous cursor if any and replace that with the new on from host class
     * @param cursor
     */
    public void swapCursor(Cursor cursor) {
        if(itemCursor != null) {
            itemCursor.close();
            itemCursor = null;
        }

        itemCursor = cursor;
        notifyDataSetChanged();

    }

    public void setCountDown(int countDown){
        mCountDown = countDown;

        if(!ignoreDatasetChange)
            notifyDataSetChanged();
    }

    /**
     * View golder for auction item entry
     */
    public class ItemViewHolder extends RecyclerView.ViewHolder {
        TextView tvEmail;
        TextView tvPin;
        TextView tvIssuer;
//        TextView tvCountDown;
        ArcProgress apCountDown;
        View container;

        public ItemViewHolder(View itemView) {
            super(itemView);
            tvEmail = (TextView) itemView.findViewById(R.id.tv_email);
            tvPin = (TextView) itemView.findViewById(R.id.tv_pin);
            tvIssuer = (TextView) itemView.findViewById(R.id.tv_issuer);
            apCountDown = (ArcProgress) itemView.findViewById(R.id.arc_progress);
            container = itemView.findViewById(R.id.container);
        }
    }

    /**
     * databse column id holder for auction item
     */
    class ItemColumnIds {

        public int colId;
        public int colPin;
        public int colAcctId;
        public int colIssuer;

    }

}

【问题讨论】:

  • 你是什么意思“媒体迷路了”?
  • 说我已经接触到一个期望它运行 longClickEvent 的项目,但是在 longClick 超时之前,会发生一个倒计时更新回调,该回调会更新所有视图的计数。在这种状态下,longclick 事件不会触发
  • 你的刷新率低于300ms?你为什么不让它更长呢?
  • 你介意用你的适配器代替吗?
  • 我已经共享了我的适配器

标签: android android-recyclerview notifydatasetchanged long-press


【解决方案1】:

修好了!

所以基本上问题是,每次发生更新以对抗整个适配器时都会填充整个视图,包括侦听器,即使在 ViewHolder 中设置侦听器也不起作用。

我做了什么,我扩展了我的布局管理器并添加了一个方法来仅更新视图的计数器小部件,而其余部分保持不变。

这是 TimedGridLayoutManager:

public class TimedGridLayoutManager extends GridLayoutManager {

   public TimedGridLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    //updates the counter every second
    public void setCountDown(int countDown) {
        //return null if there are no items and avoid crash
        if(this.getItemCount() <= 0)
            return;

        //get first and last visible child
        int firstPos = this.findFirstVisibleItemPosition();
        int lastPos = this.findLastVisibleItemPosition();

        //loop through the range and set counter
        for(int i = firstPos; i <= lastPos; i++) {
            View itemView = this.findViewByPosition(i);
            ArcProgress arcCounter = (ArcProgress) itemView.findViewById(R.id.arc_counter);
            arcCounter.setProgress(countDown);

        }
    }
}

它不知道它是否是最有效的解决方案,但它对我来说就像一个魅力,而且我根本不需要接触我的适配器代码。

【讨论】:

    【解决方案2】:

    我认为您应该考虑在用户触摸视图时停止快速刷新。

    为此,您只需实现onTouchEvent,并在检测到 MotionEvent.ACTION_DOWN 时设置一个标志。

    ...
    if (event.getAction()==MotionEvent.ACTION_DOWN) isUserTouching = true;
    if (event.getAction()==MotionEvent.ACTION_UP) isUserTouching = false;
    ...
    

    然后,您的更新程序代码变为:

    public void setCountDown(int countDown){
       if (!isUserTouching) {
          mCountDown = countDown;
          notifyDataSetChanged();
       }
    }
    

    【讨论】:

    • 我之前尝试过同样的方法,但问题是......如果用户只是将手指从视图中滑开,并且我什至无法捕获离开视图的手指,则不会调用 ACTION_DOWN,HOVER_EXIT 也是不叫。另一个问题是,OnClick 和 OnLongClick 事件停止运行,这意味着我也必须手动处理它们,导致解决方案很长
    【解决方案3】:

    您必须在创建视图持有人时设置单击和长按侦听器,而不是在视图持有人的绑定中。

    将您的视图持有者更新为:

    public class ItemViewHolder extends RecyclerView.ViewHolder {
            TextView tvEmail;
            TextView tvPin;
            TextView tvIssuer;
    //        TextView tvCountDown;
            ArcProgress apCountDown;
            View container;
    
            public ItemViewHolder(View itemView) {
                super(itemView);
                tvEmail = (TextView) itemView.findViewById(R.id.tv_email);
                tvPin = (TextView) itemView.findViewById(R.id.tv_pin);
                tvIssuer = (TextView) itemView.findViewById(R.id.tv_issuer);
                apCountDown = (ArcProgress) itemView.findViewById(R.id.arc_progress);
                container = itemView.findViewById(R.id.container);
    
                container.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        String pin = tvPin.getText().toString();
                        ClipboardManager clipboard = (ClipboardManager) itemView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
                        ClipData clip = ClipData.newPlainText("Secret Key", pin);
                        clipboard.setPrimaryClip(clip);
    
                        Toast.makeText(itemView.getContext(), "OTP code "+ pin +" copied to clipboard", Toast.LENGTH_SHORT).show();
    
                    }
                });
    
                container.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View v) {
                        FragmentManager fm = ((AppCompatActivity)itemView.getContext()).getSupportFragmentManager();
                        EditAccountFragment editAccountFragmentDialog = EditAccountFragment.newInstance(_id);
                        editAccountFragmentDialog.show(fm, "fragment_edit_account");
    
                        return true; //if you handle it, return true!
                    }
    
                });
            }
        }
    

    并在onBindViewHolder 方法中删除holder.container.setOnClickListenerholder.container.setOnLongClickListener

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-07
      • 2015-04-16
      • 2017-11-27
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多