Как удалить элемент из ArrayList, используя отфильтрованные RecyclerView и OnClickListener - PullRequest
0 голосов
/ 26 июня 2019

Проверьте обновления ниже.

Я создаю приложение для соревнований по восхождению по лестнице, которое отслеживает дату и количество предпринятых шагов (пользовательский ввод, а не автоматический). У меня есть ArrayList, в котором хранятся объекты, содержащие следующие три переменные:

String date
Int steps
Instant timeStamp

Приложение имеет две кнопки ввода, одну для целочисленного пошагового ввода и одну для выбора даты. Существует простой метод, позволяющий отфильтровать видимый список по выбранной дате и пару визуальных индикаторов вашего ежедневного прогресса в сравнении с ежедневной целью для лестничных пролетов за день.

Снимок экрана приложения

Я использую переменную Instant в качестве метки времени, чтобы попытаться обойти проблему OnClickListener выбора позиции элемента из отфильтрованного списка вместо соответствующего элемента в нефильтрованном списке. Я делаю это, используя позицию, сообщаемую из OnClickListener, для извлечения переменной timeStamp из связанного элемента в отфильтрованном ArrayList, затем сравниваю это timeStamp с элементами в нефильтрованном ArrayList и извлекаю indexOf из соответствующего элемента.

Все отфильтрованные списки массивов правильно отображаются в RecyclerView при выборе даты.

Проблема заключается в удалении предметов. Если я добавляю элементы только к одной дате, вы можете удалять и добавлять элементы так, как вы ожидаете.

Функция приложения без изменения даты (GIF)

Если я добавлю к одной дате, то к другой, пока они правильно отображаются, элементы будут удалены с правильной позиции, но в дату, когда вы впервые добавили элементы, независимо от того, является ли эта дата выбранной в данный момент или нет.

Функция приложения с изменением даты (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();
    }
}

Если у кого-то есть какие-либо идеи, я хотел бы услышать от вас!

ОБНОВЛЕНИЕ: Включенный код теперь отражает изменения, предложенные пользователями, и полностью функционален.

Ответы [ 3 ]

0 голосов
/ 26 июня 2019

Я понял это для тех, кто заинтересован.Сравнение меток времени работало нормально, но я поместил его не в ту часть цикла OnClickListener.Его необходимо поместить в метод MainActivity buildRecyclerView в переопределении setOnClickListener.Я обновил исходный код, чтобы отразить это изменение.

Спасибо всем, кто нашел время, чтобы взглянуть на мой пост.

0 голосов
/ 26 июня 2019

может быть, было бы лучше разместить onClickListner в вашем классе adpater..so. Вы можете контролировать каждую отдельную карту, если она должна быть кликабельной или нет ... или если вы хотите разместить какую-либо рекламу между карточками

ГГК

0 голосов
/ 26 июня 2019

Вы должны использовать

mAdapter.notifyDataSetChanged();

Вместо

mAdapter.notifyItemRemoved(position);

Для получения более подробной информации посетите this.

...