Manikandan
Manikandan

Reputation: 130

Removing Item From Recyclerview When Time Expired

I need to remove an item when time expired, partially i got output by referring this How to handle multiple countdown timers in ListView?

After scrolled the list, some of the time expired items are not removed and times are not updated.

package com.techno.deliveryboy.Adapter;

import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.techno.deliveryboy.Pojos.DummyTimer;
import com.techno.deliveryboy.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by developer on 23/7/16.
 */
public class Incoiming_orders_Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>  {

    private LayoutInflater lf;
    Boolean onBind = true;
    private List<MyViewHolder> lstHolders;
    ArrayList<Integer> unbindvalues=new ArrayList<>();
    private Handler mHandler = new Handler();
    List<DummyTimer> lstProducts=new ArrayList<>();
    private Runnable updateRemainingTimeRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (lstHolders) {
                long currentTime = System.currentTimeMillis();

                for (MyViewHolder holder : lstHolders) {

                    holder.updateTimeRemaining(currentTime);


                }


            }
        }
    };

    public Incoiming_orders_Adapter(FragmentActivity activity, List<DummyTimer> lstProduct) {

        lstHolders = new ArrayList<>();
        lstProducts=lstProduct;

        startUpdateTimer();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.incoming_orders_item, parent, false);
        return new MyViewHolder(itemView);
    }

    private void startUpdateTimer() {
        Timer tmr = new Timer();
        tmr.schedule(new TimerTask() {
            @Override
            public void run() {
                mHandler.post(updateRemainingTimeRunnable);

            }
        }, 1000, 1000);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
      if(holder instanceof MyViewHolder){
          onBind=true;
          MyViewHolder holder1= (MyViewHolder) holder;
          synchronized (lstHolders) {
              lstHolders.add(holder1);

           }
          holder1.setData(lstProducts.get(position),position);
          onBind=false;

      }
    }

    @Override
    public int getItemCount() {
        return lstProducts.size();
    }
    public void removeAt(int position) {

       /* for (Iterator<MyViewHolder> iterator = lstHolders.iterator(); iterator.hasNext();) {

           iterator.remove();
        }*/


        if(!onBind) {
            if(unbindvalues!=null&&unbindvalues.size()!=0&&position>=0){
                for (Integer i:unbindvalues) {
                    lstProducts.remove(position);
                    notifyItemRemoved(position);
                }
                unbindvalues.clear();

            }else {
                if(position>=0){
                    lstProducts.remove(position);
                    notifyItemRemoved(position);
                }

            }




            notifyDataSetChanged();
        }else {
            System.out.println("+Bind->true+");
            if(position>=0)
            unbindvalues.add(position);
        }
    }


    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, tvTimeRemaining, genre;
        DummyTimer mProduct;
        public void setData(DummyTimer item, int position) {
            mProduct = item;
            title.setText(item.name);
            updateTimeRemaining(System.currentTimeMillis());
        }

        public MyViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.Item_Totalvalue);
            tvTimeRemaining= (TextView) view.findViewById(R.id.Item_timeout);
        }

        public void updateTimeRemaining(long currentTime) {
            long timeDiff = mProduct.expirationTime - currentTime;
            if (timeDiff > 0) {
                int seconds = (int) (timeDiff / 1000) % 60;
                int minutes = (int) ((timeDiff / (1000 * 60)) % 60);
                int hours = (int) ((timeDiff / (1000 * 60 * 60)) % 24);
                tvTimeRemaining.setText(hours + " hrs " + minutes + " mins " + seconds + " sec");
            } else {
              // tvTimeRemaining.setText(String.valueOf(getAdapterPosition()));


                removeAt(getAdapterPosition());

            }
        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
}

Please give your comment.

Upvotes: 3

Views: 2123

Answers (3)

s.d
s.d

Reputation: 29436

You can have a periodic operation set-up that will remove items from RecyclerView adapter. Below is a crude example.

First, define the item class that represents list items:

import android.text.format.DateFormat;

public class TimedItem {
    private final long expireAt;
    private final String  name;

    public TimedItem(String name, long expireAt) {
        this.name = name;
        this.expireAt = expireAt;
    }

    public String getName() {
        return name;
    }

    public String getDescription(){
        return String.format("Expires at %s.", DateFormat.format("h:mm:ss a ddd, MMM, YYYY",this.expireAt));
    }

    public boolean isExpired(){
        return System.currentTimeMillis() > this.expireAt;
    }
}

Since the items are to be displayed using RecyclerView, define a ViewHolder as well:

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;

public class TimedItemHolder extends RecyclerView.ViewHolder {
    private final TextView nameView;
    private final TextView descView;
    public TimedItemHolder(View itemView) {
        super(itemView);
        this.nameView = (TextView) itemView.findViewById(android.R.id.text1);
        this.descView = (TextView) itemView.findViewById(android.R.id.text2);
    }

    public TextView getNameView() {
        return nameView;
    }

    public TextView getDescView() {
        return descView;
    }
}

Now, to display items in RecycleView, we need to define an RecyclerView.Adapter. This will also handle item removal on expiry :

import android.os.Handler;
import android.os.Looper;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;


public class TimerAdapter extends RecyclerView.Adapter<TimedItemHolder> {
    private final List<TimedItem> items = new ArrayList<>();
    private final Handler handler = new Handler(Looper.getMainLooper());
    private final long interval;
    private final Runnable task = new Runnable() {
        @Override
        public void run() {
            int i = 0;
            Iterator<TimedItem> iterator = TimerAdapter.this.items.iterator();
            while (iterator.hasNext()) {
                TimedItem item = iterator.next();
                if (item.isExpired()) {
                    iterator.remove();
                    notifyItemRemoved(i);
                } else {
                    i++;
                }
            }
            handler.postDelayed(this, interval);
        }
    };

    public TimerAdapter(long interval) {
        this.interval = interval;
        handler.postDelayed(task, interval);
    }

    public void addItem(TimedItem item) {
        this.items.add(item);
    }

    public void addAll(Collection<? extends TimedItem> items) {
        this.items.addAll(items);
    }

    public void clear() {
        this.items.clear();
    }

    @Override
    public TimedItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_2, parent, false);
        return new TimedItemHolder(view);
    }

    @Override
    public void onBindViewHolder(TimedItemHolder holder, int position) {
        TimedItem item = this.items.get(position);
        holder.getNameView().setText(item.getName());
        holder.getDescView().setText(item.getDescription());
    }

    @Override
    public int getItemCount() {
        return this.items.size();
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        handler.removeCallbacks(task);
    }
}

Finally, we can test it:

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.Random;


public class TestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        RecyclerView list = new RecyclerView(this);
        list.setLayoutManager(new LinearLayoutManager(this));
        TimerAdapter adapter = new TimerAdapter(1000);
        list.setAdapter(adapter);
        setContentView(list);


        Random random = new Random();

        for (int i = 0; i < 20; i++) {
            String name = "Item: " + i;
            long expireAt = System.currentTimeMillis() + 5000 + random.nextInt(20000);
            adapter.addItem(new TimedItem(name,expireAt));
        }

        adapter.notifyDataSetChanged();
    }
}

Upvotes: 0

Keval Patel
Keval Patel

Reputation: 592

You can achieve this by setting up the CountDownTimer which will trigger onTick() method every second. In onTick() method check if there are any objects those are expired? If you find any object remove them by calling notifyItemRemoved().

Here is the code of recycler view adapter:

private class RecyclerViewAdapter extends RecyclerView.Adapter { private ArrayList mData;

    public RecyclerViewAdapter(ArrayList<RowData> data) {
        mData = data;

        //find out the maximum time the timer
        long maxTime = System.currentTimeMillis();
        for (RowData item : mData) {
            maxTime = Math.max(maxTime, item.endTime);
        }

        //set the timer which will refresh the data every 1 second.
        new CountDownTimer(maxTime - System.currentTimeMillis(), 1000) {
            @Override
            public void onTick(long l) {
                for (int i = 0, dataLength = mData.size(); i < dataLength; i++) {
                    RowData item = mData.get(i);
                    item.timeRemaining -= 1000;
                }

                //remove the expired items
                Iterator<RowData> dataIterator = mData.iterator();
                while (dataIterator.hasNext()) {
                    RowData rd = dataIterator.next();
                    if (rd.timeRemaining <= 0) dataIterator.remove();
                }
                notifyDataSetChanged();
            }

            @Override
            public void onFinish() {
                mData.clear();
                notifyDataSetChanged();
            }
        }.start();
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new MyViewHolder(LayoutInflater.from(MainActivity.this).inflate(android.R.layout.simple_list_item_2, parent, false));
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        RowData rowData = mData.get(position);
        holder.titleTv.setText(rowData.title);
        holder.remainingTimeTv.setText(millToMins(rowData.timeRemaining) + " mins remaining");
    }

    private String millToMins(long millisec) {
        return millisec / (60000) + ":" + (int) (millisec/1000) % (60);
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        private TextView remainingTimeTv;
        private TextView titleTv;

        public MyViewHolder(View itemView) {
            super(itemView);
            remainingTimeTv = (TextView) itemView.findViewById(android.R.id.text2);
            titleTv = (TextView) itemView.findViewById(android.R.id.text1);
        }
    }

}

P.S. : Here is the full code demo available on my GitHub account.

Upvotes: 3

Terril Thomas
Terril Thomas

Reputation: 1506

The thing that you want is similar to filter on difference is that you want the item to be removed . I would suggest setting an Observer for all the timers in the list and whenever your timer crosses the schedule you have to update the observer , which will remove it form the list or arraylist of items that you have. Notify your data set that a change has occurred which will refresh your RecyclerView.

Upvotes: 0

Related Questions