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

标签 java android android-recyclerview android-adapter android-filterable

检查下面的更新。

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

String date
Int steps
Instant timeStamp

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

App screenshot

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

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

问题出在删除项目上。如果我仅向一个日期添加项目,那么您可以按照预期删除和添加项目。

App function without date change (gif)

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

App function with changing date (gif)

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

主要 Activity :

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();
    }
}

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

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

最佳答案

你应该使用

mAdapter.notifyDataSetChanged();

而不是

mAdapter.notifyItemRemoved(position);

欲了解更多详情,请访问 this.

关于java - 如何使用过滤的 RecyclerView 和 OnClickListener 从 ArrayList 中删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56765750/

相关文章:

android - 如何使用 Android 获取 Firebase 数据库中的值?

android - 海量数据+Objectbox+RecyclerView适配器

适用于 Windows 7 和 Windows 10 的 Java 程序

JAVAFX - 如何在应用程序启动时调用方法

java - 在 Gradle 中创建多个 sourceSet

java - Android端和php端的HmacSHA1结果不同

android - 无需用户交互即可在我的 apk 中下载 Apk

java - 在 ndk 中找不到原生的实现

android - 在 RecyclerView 中选择项目

android - Jquery Mobile 后退按钮重定向到特定页面