2015-06-19 14 views
7

In meiner App muss ich den Countdown-Timer für jedes Element in der Listenansicht anzeigen. Ich konnte dies unter Verwendung CountDownTimer tun. Problem ist jedoch, wenn die Liste nach oben oder unten gescrollt wird, der Timer beginnt zu flackern. Viel gesucht, aber keine Lösung gefunden.ListView mit Coundown-Timer. Timer flackert beim Scrollen der Listenansicht

My Adapter Klasse

public class BuyListingListAdapter extends BaseAdapter { 

private Context mContext; 
private ArrayList<VehicleAttributes> mVehicleList = new ArrayList<VehicleAttributes>(); 
private Date currentDate; 
//Saving position in map to check if timer has been //started for this row 
private HashMap<Integer, Boolean> timerMap = new HashMap<Integer, Boolean>(); 

public BuyListingListAdapter(Context context, 
     ArrayList<VehicleAttributes> vehicleList, boolean showGridView) { 
    this.mContext = context; 
    this.mVehicleList = vehicleList; 
    this.showGridView = showGridView; 
    currentDate = new Date(System.currentTimeMillis()); 

    int listSize = mVehicleList.size(); 
    for (int i = 0; i < listSize; i++) 
     timerMap.put(i, false); 
} 

@Override 
public int getCount() { 
    return mVehicleList.size(); 
} 

@Override 
public Object getItem(int position) { 
    return mVehicleList.get(position); 
} 

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

@Override 
public View getView(final int position, View convertView, ViewGroup parent) { 
    final ViewHolder holder; 
    if (convertView == null) { 
     LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
     convertView = inflater.inflate(R.layout.row_buy_listing_grid, 
        parent, false); 
     holder = new ViewHolder(); 
        holder.timer_layout = (LinearLayout) convertView 
       .findViewById(R.id.timer_layout); 
        holder.txt_remaining_days = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_days); 
     holder.txt_remaining_hours = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_hours); 
     holder.txt_remaining_mins = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_mins); 
     holder.txt_remaining_secs = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_secs); 
     holder.listing_status = (ImageView) convertView 
       .findViewById(R.id.listing_status); 

     convertView.setTag(holder); 
    } else 
     holder = (ViewHolder) convertView.getTag(); 

    final VehicleAttributes vehicleAttributes = mVehicleList.get(position); 

    AuctionModel mAuctionModel = vehicleAttributes.getAuctionDetailModel(); 
    if (mAuctionModel != null) { 
     holder.img_auction.setVisibility(View.VISIBLE); 

     Date auctionStartDate = Util 
       .getDateFromString(mAuctionModel.getStarted_at(), 
         "yyyy-MM-dd hh:mm:ss", "GMT"); 
     Date auctionEndDate = Util.getDateFromString(
       mAuctionModel.getEnded_at(), "yyyy-MM-dd hh:mm:ss", "GMT"); 
     long diff = currentDate.getTime() - auctionEndDate.getTime(); 

     if (diff < 0) 
      diff = -diff; 
     else 
      diff = 0; 

     if (timerMap.get(position) == null || !timerMap.get(position)) { 

      timerMap.put(position, true); 
      MyCountDown countDown = new MyCountDown(position, diff, 1000, 
        holder.txt_remaining_days, holder.txt_remaining_hours, 
        holder.txt_remaining_mins, holder.txt_remaining_secs); 
      countDown.start(); 
     } 
    } 
    return convertView; 
} 

private class MyCountDown extends CountDownTimer { 
    RobotoCondensedBoldTextView txt_remaining_days; 
    RobotoCondensedBoldTextView txt_remaining_hours; 
    RobotoCondensedBoldTextView txt_remaining_mins; 
    RobotoCondensedBoldTextView txt_remaining_secs; 
    int position; 

    public MyCountDown(int position, long millisInFuture, long countDownInterval, 
      RobotoCondensedBoldTextView txt_remaining_days, 
      RobotoCondensedBoldTextView txt_remaining_hours, 
      RobotoCondensedBoldTextView txt_remaining_mins, 
      RobotoCondensedBoldTextView txt_remaining_secs) { 
     super(millisInFuture, countDownInterval); 
     this.position = position; 
     this.txt_remaining_days = txt_remaining_days; 
     this.txt_remaining_hours = txt_remaining_hours; 
     this.txt_remaining_mins = txt_remaining_mins; 
     this.txt_remaining_secs = txt_remaining_secs; 
    } 

    @Override 
    public void onFinish() { 

    } 

    @Override 
    public void onTick(long millisUntilFinished) { 
     updateTimerLabel(position, millisUntilFinished, txt_remaining_days, 
       txt_remaining_hours, txt_remaining_mins, txt_remaining_secs); 
    } 
} 

private void updateTimerLabel(int position, long millis, 
     RobotoCondensedBoldTextView txt_remaining_days, 
     RobotoCondensedBoldTextView txt_remaining_hours, 
     RobotoCondensedBoldTextView txt_remaining_mins, 
     RobotoCondensedBoldTextView txt_remaining_secs) { 
    String days = String.format("%02d", 
      TimeUnit.MILLISECONDS.toDays(millis)); 
    String hours = String.format(
      "%02d", 
      TimeUnit.MILLISECONDS.toHours(millis) 
        - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS 
          .toDays(millis))); 
    String mins = String.format(
      "%02d", 
      TimeUnit.MILLISECONDS.toMinutes(millis) 
        - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS 
          .toHours(millis))); 
    String secs = String.format(
      "%02d", 
      TimeUnit.MILLISECONDS.toSeconds(millis) 
        - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS 
          .toMinutes(millis))); 

    txt_remaining_days.setText(days); 
    txt_remaining_hours.setText(hours); 
    txt_remaining_mins.setText(mins); 
    txt_remaining_secs.setText(secs); 
} 

static class ViewHolder { 
    NetworkImageView mVehicleImage; 
    RobotoCondensedBoldTextView txt_remaining_days, txt_remaining_hours, 
      txt_remaining_mins, txt_remaining_secs; 
    LinearLayout timer_layout; 
} 
} 
+0

Ein Problem vermissen Sie die sonst Teil dieser if (mAuctionModel! = Null) { – Amsheer

+0

@Amsheer Ich hatte meinen Code zugeschnitten und zeigte nur das, was relevant ist. Der Timer wird auch nur angezeigt, wenn dieses Modell vorhanden ist. – Nitish

+0

Haben Sie das auf mehreren Geräten/Android-Versionen getestet? – bernlim

Antwort

1

UPDATE

Ich habe meine Antwort aktualisiert hier einen Blick: (es ist Verwendungen cardview mit recyclerview aber das gleiche Prinzip kann auch für die Listenansicht angewendet werden) How to change text based on time and date?

Sie haben dafür Sorge zu tragen, wenn Sie das schaffen countdowntimer Instanz und wenn Sie es abbrechen. Wenn Sie den Timer nicht abbrechen, werden die falschen Ansichten aktualisiert.

2

Sie sollten Ihre Listview und Countdown-Timer in zwei Fragmente werden Trennen unbeabsichtigte Störungen zu vermeiden. Android ist nicht für eine solche Implementierung ausgelegt.

Fragmente sind der Weg zu gehen: http://developer.android.com/guide/components/fragments.html

Edit: Für Ihren Fall können Sie eine separate Datenbank von Timern für jedes Listenelement ausgeführt wird, dann nur Ihre Artikel im Listview-Liste. Wenn ein Benutzer das Timing kennen muss, klickt er auf Ihr Listenelement, das die Datenbank für eine aktuelle Zeit aufruft. Diese aktuelle Zeit wird dann auf dem Listeneintrag angezeigt. Das ist NICHT live, also wird sich die Zeit nicht ändern. Dadurch vermeiden Sie das Flackern.

+0

Ich muss Timer in jedem Listenansicht Element zeigen. Hat nicht, wie dies das Problem zu lösen ? – Nitish

+0

Ok ich sehe.Ich habe oben für Ihr spezielles Anliegen – bernlim

3

Ok lets talk über das Problem ersten

if (convertView == null) { 
     LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
     convertView = inflater.inflate(R.layout.row_buy_listing_grid, 
        parent, false); 
     holder = new ViewHolder(); 
        holder.timer_layout = (LinearLayout) convertView 
       .findViewById(R.id.timer_layout); 
        holder.txt_remaining_days = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_days); 
     holder.txt_remaining_hours = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_hours); 
     holder.txt_remaining_mins = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_mins); 
     holder.txt_remaining_secs = (RobotoCondensedBoldTextView) convertView 
       .findViewById(R.id.txt_remaining_secs); 
     holder.listing_status = (ImageView) convertView 
       .findViewById(R.id.listing_status); 

     convertView.setTag(holder); 
    } else 
     holder = (ViewHolder) convertView.getTag(); 

Der Code oben in der Listenansicht den Punkt für die Komponenten, beispielsweise wiederverwenden, wenn wir eine Liste laden nur 6 Punkte auf der Liste, Listenansicht angezeigt werden Erstellen Sie diese Elemente, aber wenn Sie nach oben und unten scrollen, anstatt ein neues Element zu erstellen, wird es die gleiche Ansicht für die nächsten Positionen wiederverwenden. Wenn Sie Ihre Ansicht an countDown-Timer übergeben, werden die gleichen Ansichten mit einem anderen Countdown-Timer aktualisiert

Nun, was die Lösung sein wird, müssen Sie herausfinden, welche Elementansichten auf dem Geröll sichtbar sind n und stoppen Sie den Countdown-Timer für andere Ansichten. oder gibt es eine sehr einfache Art und Weise, aber nicht empfohlen, da es Speicherproblem verursachen kann

LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
    convertView = inflater.inflate(R.layout.row_buy_listing_grid, 
       parent, false); 
    holder = new ViewHolder(); 
       holder.timer_layout = (LinearLayout) convertView 
      .findViewById(R.id.timer_layout); 
       holder.txt_remaining_days = (RobotoCondensedBoldTextView) convertView 
      .findViewById(R.id.txt_remaining_days); 
    holder.txt_remaining_hours = (RobotoCondensedBoldTextView) convertView 
      .findViewById(R.id.txt_remaining_hours); 
    holder.txt_remaining_mins = (RobotoCondensedBoldTextView) convertView 
      .findViewById(R.id.txt_remaining_mins); 
    holder.txt_remaining_secs = (RobotoCondensedBoldTextView) convertView 
      .findViewById(R.id.txt_remaining_secs); 
    holder.listing_status = (ImageView) convertView 
      .findViewById(R.id.listing_status); 

    convertView.setTag(holder); 

Einfach entfernen if(convertview==null) und erlauben für jede Zeile eine neue Ansicht aufzublasen.

+1

ausgearbeitet dies dezimiert den ganzen Punkt von 'ViewHolder' Muster, um die begrenzten Ansichten in Bezug auf den Anzeigebereich Ihres Bildschirms zu recyceln – trpride

+0

Ja, ich weiß und nur deshalb habe ich diese Erklärung geschrieben " Now was ist die Lösung, Sie müssen herausfinden, welche Elementansichten auf dem Bildschirm sichtbar sind und den Countdown-Timer für andere Ansichten stoppen. oder es gibt einen sehr einfachen Weg, aber nicht empfohlen, weil es Speicherprobleme verursachen kann. " –