2013-11-28 17 views
9

Ho un problema con la mia Listview, voglio impostare un timer per il conto alla rovescia per tutti gli oggetti di ListView e ho già cercato su Google una soluzione per questo, ma non funziona correttamente. Il problema è che ListView riutilizza (riciclando) una vista e ottengo sempre un tempo di articolo errato. Uso un tag per la mia vista, ma non funziona ancora, non riesco a capire dove ho fatto un errore, per favore aiutatemi. grazie.ListView e voci con timer per il conto alla rovescia

Quindi ecco una foto che mostra il mio problema: pic1 Dove ho appena avviato un'attività; startActivity

pic2 dove ho solo scorrere verso il basso e fino

listWithError

Ed ecco il mio codice (tutta la classe):

AGGIORNATO

public class PromoListActivity extends SherlockActivity { 
private ListView mPromoList; 
private PromoListAdapter mAdapter; 
private ViewFlipper mFlipper; 
private Button mBtnRepeat; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.fragment_news_list); 
    getSupportActionBar().setDisplayHomeAsUpEnabled(true); 
    setTitle("Сохранённые акции"); 
    mFlipper = (ViewFlipper) findViewById(R.id.flipper); 
    mPromoList = (ListView) findViewById(R.id.newsList); 
    mBtnRepeat = (Button) findViewById(R.id.btnRepeat); 

    //--> 
    final Handler timerHandler = new Handler(); 
    Runnable timerRunnable = new Runnable() { 
     @Override 
     public void run() { 
      mAdapter.notifyDataSetChanged(); 
      timerHandler.postDelayed(this, 1000); // run every minute 
     } 
    }; 
    //<-- 


    mBtnRepeat.setOnClickListener(new OnClickListener() { 

     @Override 
     public void onClick(View arg0) { 
      mFlipper.setDisplayedChild(0); 
      getDummyData(); 
     } 
    }); 
    mPromoList.setOnItemClickListener(new OnItemClickListener() { 

     @Override 
     public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { 
      startActivity(new Intent(PromoListActivity.this, PromoActivityDetails.class)); 

     } 
    }); 
    getDummyData(); 
} 

private class PromoListAdapter extends BaseAdapter { 
    private ArrayList<PromoAction> mItems = new ArrayList<PromoAction>(); 
    private LayoutInflater layoutInflater; 

    private PromoListAdapter(Context context, ArrayList<PromoAction> mItems) { 
     layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     this.mItems = mItems; 
    } 

    public int getCount() { 
     return mItems.size(); 
    } 

    public PromoAction getItem(int position) { 
     return mItems.get(position); 
    } 

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

    public View getView(int position, View convertView, ViewGroup parent) { 
     ViewItem viewItem; 
     PromoAction promoAction = getItem(position); 
     if (convertView == null) { 
      viewItem = new ViewItem(); 
      convertView = layoutInflater.inflate(R.layout.listviewitem_action, null); 
      viewItem.name = (TextView) convertView.findViewById(R.id.promoAction_name); 
      viewItem.desc = (TextView) convertView.findViewById(R.id.promoAction_desc); 
      viewItem.timer = (TextView) convertView.findViewById(R.id.promoAction_timer); 
      viewItem.timer.setTag(position); 
      convertView.setTag(viewItem); 
     } else { 
      viewItem = (ViewItem) convertView.getTag(); 
     } 
     setTime(promoAction,viewItem.timer,viewItem.timer.getTag().toString()); 
     viewItem.name.setText(promoAction.name); 
     viewItem.desc.setText(promoAction.descr); 
     return convertView; 
    } 

    private void setTime(final PromoAction promoAction, final TextView tv, final String tag) { 
     if (tv.getTag().toString().equals(tag)) { 
      long outputTime = Math.abs(promoAction.timer_end 
        - System.currentTimeMillis()); 
      Date date = new java.util.Date(outputTime); 
      String result = new SimpleDateFormat("hh:mm:ss").format(date); 
      tv.setText(result); 
     } 
    } 

    public class ViewItem { 
     TextView name; 
     TextView desc; 
     TextView timer; 
    } 
} 

private void getDummyData() { 
    ArrayList<PromoAction> list = new ArrayList<PromoAction>(); 
    for (int i = 1; i < 10; i++) { 
     PromoAction action = new PromoAction(); 
     action.name = "Lorem ipsum dolor sit amet"; 
     action.descr = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "; 
     switch (i) { 
     case 1: { 
      action.timer_start = 1385971000; 
      action.timer_end = 1386104000; 
     } 
     case 2: { 
      action.timer_start = 1385889000; 
      action.timer_end = 1385812550; 
      break; 
     } 
     case 3: { 
      action.timer_start = 1385884200; 
      action.timer_end = 1385912100; 
      break; 
     } 
     default: { 
      action.timer_start = 1385856000; 
      action.timer_end = 1385892000; 
      break; 
     } 
     } 
     list.add(action); 

    } 
    mAdapter = new PromoListAdapter(PromoListActivity.this, list); 
    mPromoList.setAdapter(mAdapter); 
    mFlipper.setDisplayedChild(1); 
} 

}

risposta

10

I così ho capito diversamente nel mio caso. Invece di avere un gestore di timer impostato all'interno del tuo getView(), ho appena impostato la differenza di orario tra l'ora corrente e l'ora desiderata per il TextView ogni volta che viene chiamato getView(). Quindi spostare il codice del tuo nuovo dentro getView():

long outputTime = Math.abs(promoAction.timer_end 
        - System.currentTimeMillis()); 
Date date = new java.util.Date(outputTime); 
String result = new SimpleDateFormat("hh:mm:ss").format(date); 
tv.setText(result); 

quindi creare un gestore nell'attività di chiamare notifyDatasetChanged() ogni minuto su adattatore del listview:

Handler timerHandler = new Handler(); 
Runnable timerRunnable = new Runnable() { 
    @Override 
    public void run() { 
     myAdapter.notifyDataSetChanged(); 
     timerHandler.postDelayed(this, 60000); //run every minute 
    } 
}; 

mi fermo questo gestore su onPause():

@Override 
protected void onPause() { 
    timerHandler.removeCallbacks(timerRunnable); 
    super.onPause(); 
} 

E comincio di nuovo sul onResume():

@Override 
protected void onResume() { 
    timerHandler.postDelayed(timerRunnable, 500); 
    super.onResume(); 
} 

E questo è tutto. :)

Spero che aiuti.

+0

Non avevo un timer in sé, come vedi il mio codice, uso il gestore per chiamare notifyDataSetChanged() proprio come te, non capisco perché listview imposta timer sbagliati a suo figlio, qualunque sia stato grazie per il tuo risposta – whizzzkey

+0

@whizzzkey Si sta avendo il gestore del timer all'interno di 'getView()'. Non farlo. Prova a farlo come ho suggerito di vedere se funziona. –

+0

Ho aggiornato la mia risposta. Vedi se è più chiaro ora. –

1

È possibile utilizzare il recyclerview. Scaricare il codice da qui()

activity_main.xml

<RelativeLayout android:layout_width="match_parent" 
android:layout_height="match_parent" 
xmlns:android="http://schemas.android.com/apk/res/android"> 

<android.support.v7.widget.RecyclerView 
android:id="@+id/recycler_view" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:scrollbars="vertical" /> 

</RelativeLayout> 

MainActivity.java

package com.androidsolutionworld.multipletimer; 

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

import java.util.ArrayList; 

public class MainActivity extends AppCompatActivity { 
    private RecyclerView recyclerView; 
    private ArrayList al_data = new ArrayList<>(); 
    private Adapter obj_adapter; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     recyclerView = (RecyclerView)findViewById(R.id.recycler_view); 
     al_data.add("1234"); 
     al_data.add("1257"); 
     al_data.add("100"); 
     al_data.add("1547"); 
     al_data.add("200"); 
     al_data.add("500"); 
     al_data.add("2000"); 
     al_data.add("1000"); 

     obj_adapter = new Adapter(al_data); 
     LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext(),LinearLayoutManager.VERTICAL,false); 
     recyclerView.setLayoutManager(layoutManager); 
     recyclerView.setAdapter(obj_adapter); 
    } 
} 

adapter_layout.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:textSize="15dp" 
     android:padding="10dp" 
     android:id="@+id/tv_timer"/> 

</LinearLayout> 
Adattatore 10

personalizzato:

package com.androidsolutionworld.multipletimer; 


import android.os.CountDownTimer; 
import android.support.v7.widget.RecyclerView; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 

import java.util.ArrayList; 

public class Adapter extends RecyclerView.Adapter{ 

    private ArrayList al_data; 

    public class MyViewHolder extends RecyclerView.ViewHolder{ 
     public TextView tv_timer; 
     CountDownTimer timer; 

     public MyViewHolder (View view){ 
      super(view); 
      tv_timer = (TextView)view.findViewById(R.id.tv_timer); 

     } 


    } 

    public Adapter(ArrayList al_data) { 
     this.al_data = al_data; 
    } 

    @Override 
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout,parent,false); 


     return new MyViewHolder(view); 
    } 

    @Override 
    public void onBindViewHolder(final MyViewHolder holder, int position) { 

     holder.tv_timer.setText(al_data.get(position)); 

     if (holder.timer != null) { 
      holder.timer.cancel(); 
     } 
     long timer = Long.parseLong(al_data.get(position)); 

     timer = timer*1000; 

     holder.timer = new CountDownTimer(timer, 1000) { 
      public void onTick(long millisUntilFinished) { 
       holder.tv_timer.setText("" + millisUntilFinished/1000 + " Sec"); 
      } 

      public void onFinish() { 
       holder.tv_timer.setText("00:00:00"); 
      } 
     }.start(); 


    } 

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



} 

Grazie!