如何使用过滤的 RecyclerView 和 OnClickListener 从 ArrayList 中删除项目

Posted

技术标签:

【中文标题】如何使用过滤的 RecyclerView 和 OnClickListener 从 ArrayList 中删除项目【英文标题】:How to remove item from an ArrayList using a filtered RecyclerView and OnClickListener 【发布时间】:2019-11-07 23:35:33 【问题描述】:

检查下面的更新。

我正在为爬楼梯挑战制作一个应用程序,用于跟踪所采取的日期和步数(用户输入,非自动)。我有一个ArrayList,它存储了包含以下三个变量的对象:

String date
Int steps
Instant timeStamp

该应用程序有两个输入按钮,一个用于整数步长输入,一个用于日期选择。创建了一个简单的方法来按选定的日期过滤可见列表,并提供一些您的每日进度与当天楼梯的每日目标的视觉指标。

App screenshot

我使用 Instant 变量作为时间戳来尝试解决OnClickListener 从过滤列表中选择项目的位置而不是未过滤列表中的相应项目的问题。为此,我使用 OnClickListener 报告的位置从过滤后的 ArrayList 中的关联项中获取 timeStamp 变量,然后将该 timeStamp 与未过滤的 ArrayList 中的项进行比较,并获取匹配项的 indexOf。

当您选择一个日期时,所有过滤的 ArrayLists 都会在 RecyclerView 中正确显示。

问题在于删除项目。如果我只将项目添加到一个日期,那么您可以按照您的预期删除和添加项目。

App function without date change (gif)

如果我添加到一个日期,然后另一个,当它们正确显示时,这些项目将从正确的位置删除,但在您第一次添加项目的日期,无论该日期是否是当前选择的日期。

App function with changing date (gif)

我觉得我在这里遗漏了一些相对简单的东西,我的大脑对这个项目太饱和了,看不到它。

主要活动:

public class MainActivity extends AppCompatActivity 

    private RecyclerView mRecyclerView;
    private ExampleAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    Date temp_curr_date = Calendar.getInstance().getTime();
    SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy");
    String sel_date = df.format(temp_curr_date);
    String curr_date = df.format(temp_curr_date);

    double daily_total;
    int progress = 0;
    double daily_goal = 7.5;

    TextView textView1;
    TextView textView2;
    TextView textViewFlights;
    ProgressBar pb;

    List<ExampleItem> mExampleList;
    List<ExampleItem> filteredList;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

// ----- LOAD SAVED ARRAY LIST -----
        loadData();

// ----- SET VARIABLES -----
        daily_total = totalOutput(mExampleList, sel_date);
        textView1 = findViewById(R.id.total);
        textView1.setText(String.valueOf(daily_total));
        textViewFlights = findViewById(R.id.flights);

        pb = findViewById(R.id.progress_bar);
        pb.setProgress(getProgress(mExampleList, sel_date), true);

// ----- BUILD RECYCLERVIEW -----
        buildRecyclerView();
        filter(sel_date);

// ----- ADD STEPS DIALOGUE -----
        setAddStepButton();

// ----- CALENDAR DIALOGUE -----
        setDateChangeButton();
    

    public double totalOutput(List<ExampleItem> steps, String date) 
        try
            int temp_total = 0;
            double flight_total;
            for (int a = 0; a < steps.size(); a++) 
                if (date.equals(steps.get(a).getText1()))
                temp_total += steps.get(a).getText2();
            
            flight_total = round(temp_total / 16.0, 2);
            return flight_total;
         catch (Exception e)
            return 0.0;
        
    

    public static double round(double value, int places) 
        if (places < 0) throw new IllegalArgumentException();

        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    

    public static int toInt(double value) 
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(0, RoundingMode.HALF_UP);
        return bd.intValue();
    

    public static Date getDate(int year, int month, int day) 
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month);
        cal.set(Calendar.DAY_OF_MONTH, day);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    

    private void saveData()
        SharedPreferences sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        Gson gson = new Gson();
        String json = gson.toJson(mExampleList);
        editor.putString("task list", json);
        editor.apply();
    

    private void loadData()
        SharedPreferences sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE);
        Gson gson = new Gson();
        String json = sharedPreferences.getString("task list", null);
        Type type = new TypeToken<ArrayList<ExampleItem>>() .getType();
        mExampleList = gson.fromJson(json, type);

        if (mExampleList == null)
            mExampleList = new ArrayList<>();
        
    

    private int getProgress(List<ExampleItem> steps, String date)
        int daily_progress_int;
        try
            int temp_progress = 0;
            double flight_total;
            for (int a = 0; a < steps.size(); a++) 
                if (date.compareTo(steps.get(a).getText1()) == 0)
                    temp_progress += steps.get(a).getText2();
            
            flight_total = round(temp_progress / 16.0, 2);
            daily_progress_int = toInt((flight_total/daily_goal)*100);
            return daily_progress_int;
         catch (Exception e)
            return 0;
        
    

    private void addProgress(double x, int prog)
        int daily_progress_int = toInt((x/daily_goal)*100);

        if (progress <= 100-daily_progress_int)
            progress = progress + prog;
            pb = findViewById(R.id.progress_bar);
            pb.setProgress(daily_progress_int, true);
         else if (progress + daily_progress_int > 100)
            pb = findViewById(R.id.progress_bar);
            pb.setProgress(100, true);
        

    

    private void removeProgress(double x, int prog)
        int daily_progress_int = toInt((x/daily_goal)*100);
        progress = progress - prog;
        if (progress <= 100) 
            pb = findViewById(R.id.progress_bar);
            pb.setProgress(daily_progress_int, true);
         else 
            pb = findViewById(R.id.progress_bar);
            pb.setProgress(0, true);

        
    

    public void addItem(String date, int steps, Instant ts)
        mExampleList.add(new ExampleItem(date, steps, ts));
        filter(sel_date);
    

    public void removeItem(final int position)
        final AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        View viewInflated = LayoutInflater.from(MainActivity.this).inflate(R.layout.confirm, (ViewGroup) findViewById(android.R.id.content), false);
        builder.setCancelable(true);
        builder.setView(viewInflated);
        builder.setPositiveButton("Yup",
                new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialog, int which) 
                        mExampleList.remove(position);
                        mAdapter.notifyDataSetChanged(position);
                        filter(sel_date);

                        daily_total = totalOutput(mExampleList, sel_date);
                        textView1 = findViewById(R.id.total);
                        textView1.setText(String.valueOf(daily_total));

                        removeProgress(daily_total,progress);

                        if (daily_total == 1.0)
                            textViewFlights.setText("flight");
                         else 
                            textViewFlights.setText("flights");
                        

                        saveData();
                    
                );
        builder.setNegativeButton("Nope", new DialogInterface.OnClickListener() 
            @Override
            public void onClick(DialogInterface dialog, int which) 
            
        );

        AlertDialog dialog = builder.create();
        dialog.show();
    

    public void buildRecyclerView()
        mRecyclerView = findViewById(R.id.recyclerView);
        mRecyclerView.setHasFixedSize(true);
        mLayoutManager = new LinearLayoutManager(this);

        mAdapter = new ExampleAdapter(mExampleList);

        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);

        mAdapter.setOnItemClickListener(new ExampleAdapter.OnItemClickListener() 
            @Override
        public void onItemClick(int position) 
            Instant test = filteredList.get(position).getTimeStamp();
            for (ExampleItem item : mExampleList)
                if (test.compareTo(item.getTimeStamp()) == 0)
                    removeItem(mExampleList.indexOf(item));
            
        );
    

    public void filter(String text)
        filteredList = new ArrayList<>();

        for (ExampleItem item : mExampleList)
            if (item.getText1().toLowerCase().contains(text.toLowerCase()))
                filteredList.add(item);
            
        

        mAdapter.filterList(filteredList);
    

    public void setAddStepButton()
        FloatingActionButton fab = findViewById(R.id.addSteps);
        fab.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                View viewInflated = LayoutInflater.from(MainActivity.this).inflate(R.layout.add_steps, (ViewGroup) findViewById(android.R.id.content), false);

                // Step input
                final EditText input = viewInflated.findViewById(R.id.input);
                builder.setView(viewInflated);

                // OK Button
                builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialog, int which) 
                        if (input.getText().length() != 0) 
                            try 
                                int in = Integer.parseInt(String.valueOf(input.getText()));
                                if (in > 0) 
                                    Instant timeStamp = Instant.now();
                                    addItem(sel_date, in, timeStamp);
                                    dialog.dismiss();
                                 else 
                                    dialog.cancel();
                                
                             catch (Exception e) 
                                dialog.cancel();
                            

                            daily_total = totalOutput(mExampleList, sel_date);
                            textView1 = findViewById(R.id.total);
                            textView1.setText(String.valueOf(daily_total));
                            addProgress(daily_total, progress);
                            mAdapter.notifyDataSetChanged();
                            filter(sel_date);

                            if (daily_total == 1.0)
                                textViewFlights.setText("flight");
                             else 
                                textViewFlights.setText("flights");
                            

                            saveData();
                         else
                            dialog.cancel();
                        

                    
                );
                // Cancel Button
                builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialog, int which) 
                        dialog.cancel();
                    
                );
                builder.show();
            
        );
    

    public void setDateChangeButton()
        FloatingActionButton fabcal = findViewById(R.id.calendarButton);
        fabcal.setOnClickListener(new View.OnClickListener()
            @Override
            public void onClick(View view) 
                LayoutInflater inflater = (LayoutInflater)getApplicationContext().getSystemService
                        (Context.LAYOUT_INFLATER_SERVICE);
                LinearLayout ll= (LinearLayout)inflater.inflate(R.layout.calendar, null, false);
                CalendarView cv = (CalendarView) ll.getChildAt(0);

                long milliseconds = 0;
                try 
                    Date d = df.parse(sel_date);
                    milliseconds = d.getTime();
                 catch (ParseException e) 
                    e.printStackTrace();
                

                cv.setDate(milliseconds);
                cv.setOnDateChangeListener(new CalendarView.OnDateChangeListener() 

                    @Override
                    public void onSelectedDayChange(
                            @NonNull CalendarView view,
                            int year,
                            int month,
                            int dayOfMonth)
                    
                        Date temp_sel_date = getDate(year, month, dayOfMonth);
                        sel_date = df.format(temp_sel_date);

                        textView2 = findViewById(R.id.daily_total);

                        if (sel_date.equals(curr_date))
                            textView2.setText("Today");
                         else 
                            String dt_day = (String) DateFormat.format("dd",   temp_sel_date);
                            String dt_month  = (String) DateFormat.format("MMM",  temp_sel_date);
                            textView2.setText(dt_month + " " + dt_day);
                        

                        daily_total = totalOutput(mExampleList, sel_date);

                        textView1 = findViewById(R.id.total);
                        textView1.setText(String.valueOf(daily_total));

                        pb = findViewById(R.id.progress_bar);
                        pb.setProgress(getProgress(mExampleList, sel_date), true);
                        mAdapter.notifyDataSetChanged();
                        filter(sel_date);
                    
                );

                new AlertDialog.Builder(MainActivity.this)
                        .setView(ll)
                        .setPositiveButton("Ok", new DialogInterface.OnClickListener() 
                                    public void onClick(DialogInterface dialog, int whichButton) 
                                        dialog.dismiss();
                                    
                                
                        ).show();
            
        );
    

适配器类:

public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> 
    private static List<ExampleItem> mExampleList;
    private static List<ExampleItem> exampleListFull;
    private OnItemClickListener mListener;

    public interface OnItemClickListener
        void onItemClick(int position);
    

    public void setOnItemClickListener(OnItemClickListener listener)
        mListener = listener;
    

    public static class ExampleViewHolder extends RecyclerView.ViewHolder 
        public TextView mTextView1;
        public ImageView mDeleteImage;

        public ExampleViewHolder(View itemView, final OnItemClickListener listener) 
            super(itemView);
            mTextView1 = itemView.findViewById(R.id.textView);
            mDeleteImage = itemView.findViewById(R.id.image_delete);



            mDeleteImage.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View view) 

                    if (listener != null)
                        int position = getAdapterPosition();
                        if (position != RecyclerView.NO_POSITION)
                            Instant test = mExampleList.get(position).getTimeStamp();
                            for (ExampleItem item : exampleListFull)
                                int compare = test.compareTo(item.getTimeStamp());
                                if (compare == 0)
                                    int delIndex = exampleListFull.indexOf(item);
                                    position = delIndex;
                                
                            
                            listener.onItemClick(position);
                        

                    
                
            );
        
    

    public ExampleAdapter(List<ExampleItem> exampleList)
        this.mExampleList = exampleList;
        exampleListFull = new ArrayList<>(exampleList);
    

    @NonNull
    @Override
    public ExampleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) 
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.example_item, parent, false);
        ExampleViewHolder evh = new ExampleViewHolder(v, mListener);
        return evh;
    

    @Override
    public void onBindViewHolder(@NonNull ExampleViewHolder holder, int position) 
        ExampleItem currentItem = mExampleList.get(position);

        if (currentItem.getText2() == 1.0)
            holder.mTextView1.setText(currentItem.getText2() + " step");
         else 
            holder.mTextView1.setText(currentItem.getText2() + " steps");
        
    

    @Override
    public int getItemCount() 
        return mExampleList.size();
    

    public void filterList(List<ExampleItem> filteredList)
        mExampleList = filteredList;
        notifyDataSetChanged();
    

如果有人有任何想法,我很乐意听取您的意见!

更新:包含的代码现在反映了用户建议的更改并且功能齐全。

【问题讨论】:

【参考方案1】:

你应该使用

mAdapter.notifyDataSetChanged();

代替

mAdapter.notifyItemRemoved(position);

更多详情请访问 this.

【讨论】:

谢谢你,我按照你的建议做了,行为没有改变。【参考方案2】:

我想通了,对于那些感兴趣的人。比较时间戳工作正常,但我把它放在OnClickListener 循环的错误部分。它需要放在setOnClickListener 覆盖的MainActivity buildRecyclerView 方法中。我更新了原始代码以反映这一变化。

感谢所有花时间看我帖子的人。

【讨论】:

【参考方案3】:

也许将 onClickListner 放置在您的 adpater-class 中可能会更好。所以您可以控制每张卡片是否应该可点击...或者您是否想在卡片之间放置任何广告

GGK

【讨论】:

以上是关于如何使用过滤的 RecyclerView 和 OnClickListener 从 ArrayList 中删除项目的主要内容,如果未能解决你的问题,请参考以下文章

搜索过滤器后如何更新android RecyclerView项目?

如何显示按最喜欢的评论过滤的recyclerview项目?

使用 Room 和 RecyclerView 在 SearchView 中添加过滤器

过滤recyclerview在刷卡时没有得到正确的卡片位置

过滤 RecyclerView 项目并单击它后会给出错误的项目

RecyclerView 项目样式应用于过滤后的所有项目