Android: Multiple timer di count simultanei in un ListView

Sto creando un'applicazione che richiede un ListView con un numero indefinito di elementi, ognuno dei quali ha un timer che count da un numero variabile. Sono in grado di eseguire con successo un count, ma non riesco a capire come includere un timer in each elemento del ListView.

Attualmente sto utilizzando un CountDownTimer (assicuratevi di capitalizzare il D se si copia dal sito web, lo hanno sbagliato).

  • Come catturare l'image e salvarlo in una scheda SD
  • Android - Servizio di Google Play: Leaderboard, numero limitato di richieste
  • Come faccio a fare app Android che fanno qualcosa each X secondo
  • Come sostituire una string per un buildvariant con gradle in studio android?
  • Cordova non costruirà più
  • Imansible utilizzare entrambe le telecamere di Evo 4G usando OpenCV4Android
  • Qualsiasi codice o fonti per indicarmi nella giusta direzione sono molto apprezzati.

    Ecco la mia attuale class EventAdapter, imposta il text visualizzato in each TextView di un elemento ListView. Quello che devo fare è rendere il TextView count each secondo. Poiché each elemento del ListView sta visualizzando qualcosa di diverso, suppongo che ho bisogno di un modo per differenziare each elemento.

    Potrei aggiornare l'elenco solo each secondo, ma ci sono altri elementi che non ho incluso, come le immagini caricate da Internet, che sarebbe inesistente aggiornare each secondo.

    private class EventAdapter extends ArrayAdapter<Event> { private ArrayList<Event> items; public EventAdapter(Context context, int textViewResourceId, ArrayList<Event> items) { super(context, textViewResourceId, items); this.items = items; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.row, null); } Event e = items.get(position); if (e != null) { TextView tv = (TextView) v.findViewById(R.id.text); if (tv != null) tv.setText(e.getName()); } return v; } } 

  • Come fare qualcosa quando una casella di controllo cambia stato?
  • Firebase Error non può accedere a zzanb dopo aver utilizzato play-services-xxx: 9.8.00
  • Chiamata a OpenGL ES API senza context corrente
  • Imansible inserire il record nel database SQLite da Firebase Message Service quando l'applicazione è in stato di background o chiuso
  • Aggiornamento di un ImageView con un'image da un URL
  • Quando si salva il bitmap su disco, i routes solidi mostrano gli artefatti
  • 5 Solutions collect form web for “Android: Multiple timer di count simultanei in un ListView”

    Dai un'occhiata qui al mio blog where troverai un esempio su come realizzarlo.

    Una soluzione è quella di mettere il TextView che rappresenta each contatore in un HashMap insieme alla sua posizione nell'elenco come chiave.

    In getView ()

     TextView counter = (TextView) v.findViewById(R.id.myTextViewTwo); if (counter != null) { counter.setText(myData.getCountAsString()); // add the TextView for the counter to the HashMap. mCounterList.put(position, counter); } 

    Quindi è ansible aggiornare i contatori utilizzando un gestore e where submit un runnable.

     private final Runnable mRunnable = new Runnable() { public void run() { MyData myData; TextView textView; // if counters are active if (mCountersActive) { if (mCounterList != null && mDataList != null) { for (int i=0; i < mDataList.size(); i++) { myData = mDataList.get(i); textView = mCounterList.get(i); if (textView != null) { if (myData.getCount() >= 0) { textView.setText(myData.getCountAsString()); myData.reduceCount(); } } } } // update every second mHandler.postDelayed(this, 1000); } } }; 

    Questo è un esempio del modo in cui lo faccio e funziona perfettamente:

     public class TestCounterActivity extends ListActivity { TestAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Example values ArrayList<Date> values = new ArrayList<Date>(); values.add(new Date(1482464366239L)); values.add(new Date(1480464366239L)); values.add(new Date(1470464366239L)); values.add(new Date(1460464366239L)); values.add(new Date(1450464366239L)); values.add(new Date(1440464366239L)); values.add(new Date(1430464366239L)); values.add(new Date(1420464366239L)); values.add(new Date(1410464366239L)); values.add(new Date(1490464366239L)); adapter = new TestAdapter(this, values); setListAdapter(adapter); } @Override protected void onStop() { super.onStop(); // Dont forget to cancel the running timers adapter.cancelAllTimers(); } } 

    E questo è l'adattatore

     public class TestAdapter extends ArrayAdapter<Date> { private final Activity context; private final List<Date> values; private HashMap<TextView,CountDownTimer> counters; static class TestViewHolder { public TextView tvCounter; } public TestAdapter(Activity context, List<Date> values) { super(context, R.layout.test_row, values); this.context = context; this.values = values; this.counters = new HashMap<TextView, CountDownTimer>(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View rowView = convertView; if(rowView == null) { LayoutInflater inflater = context.getLayoutInflater(); rowView = inflater.inflate(R.layout.test_row, null); final TestViewHolder viewHolder = new TestViewHolder(); viewHolder.tvCounter = (TextView) rowView.findViewById(R.id.tvCounter); rowView.setTag(viewHolder); } TestViewHolder holder = (TestViewHolder) rowView.getTag(); final TextView tv = holder.tvCounter; CountDownTimer cdt = counters.get(holder.tvCounter); if(cdt!=null) { cdt.cancel(); cdt=null; } Date date = values.get(position); long currentDate = Calendar.getInstance().getTime().getTime(); long limitDate = date.getTime(); long difference = limitDate - currentDate; cdt = new CountDownTimer(difference, 1000) { @Override public void onTick(long millisUntilFinished) { int days = 0; int hours = 0; int minutes = 0; int seconds = 0; String sDate = ""; if(millisUntilFinished > DateUtils.DAY_IN_MILLIS) { days = (int) (millisUntilFinished / DateUtils.DAY_IN_MILLIS); sDate += days+"d"; } millisUntilFinished -= (days*DateUtils.DAY_IN_MILLIS); if(millisUntilFinished > DateUtils.HOUR_IN_MILLIS) { hours = (int) (millisUntilFinished / DateUtils.HOUR_IN_MILLIS); } millisUntilFinished -= (hours*DateUtils.HOUR_IN_MILLIS); if(millisUntilFinished > DateUtils.MINUTE_IN_MILLIS) { minutes = (int) (millisUntilFinished / DateUtils.MINUTE_IN_MILLIS); } millisUntilFinished -= (minutes*DateUtils.MINUTE_IN_MILLIS); if(millisUntilFinished > DateUtils.SECOND_IN_MILLIS) { seconds = (int) (millisUntilFinished / DateUtils.SECOND_IN_MILLIS); } sDate += " "+String.format("%02d",hours)+":"+String.format("%02d",minutes)+":"+String.format("%02d",seconds); tv.setText(sDate.trim()); } @Override public void onFinish() { tv.setText("Finished"); } }; counters.put(tv, cdt); cdt.start(); return rowView; } public void cancelAllTimers() { Set<Entry<TextView, CountDownTimer>> s = counters.entrySet(); Iterator it = s.iterator(); while(it.hasNext()) { try { Map.Entry pairs = (Map.Entry)it.next(); CountDownTimer cdt = (CountDownTimer)pairs.getValue(); cdt.cancel(); cdt = null; } catch(Exception e){} } it=null; s=null; counters.clear(); } } 

    dopo aver esaminato pochi modi per farlo è una soluzione creativa che ho scritto. semplici e funziona perfettamente.

    l'idea di verificare se il Runnable che aggiorna i dati sta aggiornando lo stesso TextView e se il TextView è collegato a una vista diversa, il Runnable si arresta e in questo modo non sarà più presente Thread in modo da non essere lampeggiando il text o la perdita di memory.

    1. all'interno del vostro getView() aggiungere each tag di TextView con la sua posizione.

     text = (TextView) view .findViewById(R.id.dimrix); text.setTag(position); 

    2. creare la class che implementa Runnable in modo da poter passare i parametri.

     public class mUpdateClockTask implements Runnable { private TextView tv; final Handler mClockHandler = new Handler(); String tag; public mUpdateClockTask(TextView tv, String tag) { this.tv = tv; this.tag = tag; } public void run() { if (tv.getTag().toString().equals(tag)) { // do what ever you want to happen every second mClockHandler.postDelayed(this, 1000); } } }; 

    quindi ciò che accade è se il TextView non è uguale al tag originale che il Runnable si arresta.

    3. torna al tuo getView()

      final Handler mClockHandler = new Handler(); mUpdateClockTask clockTask = new mUpdateClockTask(text, activeDraw, text.getTag().toString()); mClockHandler.post(clockTask); 

    è così, il lavoro è perfetto!

    Ecco un'altra soluzione di utilizzare ListView con più CountDownTimer. Innanzitutto, creiamo una class MyCustomTimer che detiene il CountDownTimer:

     public class MyCustomTimer{ public MyCustomTimer() { } public void setTimer(TextView tv, long time) { new CountDownTimer(time, 1000) { public void onTick(long millisUntilFinished) { //Set formatted date to your TextView tv.setText(millisUntilFinished); } public void onFinish() { tv.setText("Done!"); } }.start(); } } 

    Quindi, initilizza la class creata nella tua scheda:

     public class MyAdapter extends BaseAdapter { private LayoutInflater mInflater; private MyCustomTimer myTimer; private ArrayList<Item> myItems; public MyAdapter(Context context, ArrayList<Item> data) { mInflater = LayoutInflater.from(context); myTimer= new MyCustomTimer(); myItems = data; } //... implementation of other methods @Override public View getView(int position, View convertView, ViewGroup parent) { convertView = mInflater.inflate(R.layout.listview_row, null); TextView tvTimer = (TextView) convertView.findViewById(R.id.textview_timer); TextView tvName = (TextView) convertView.findViewById(R.id.textview_name); Item item = data.get(position); tvName.setText(item.getName()); myTimer.setTimer(tvTimer, item.getTime()); return convertView; } } 

    Ecco la mia soluzione (codice completo) 20 contatore indispensabile in ListView che può essere avviato, arrestato, riavviato, resettato in modo indipendente.

    Ho sofferto anche questo problema pochi giorni fa, ma alla fine ho trovato la soluzione di problemi. Ho creato un'applicazione che dispone di 20 timer nella vista elenco che può funzionare in modo indipendente da un solo CountDownTimer. each timer può iniziare, arrestarsi, ripristinare, riavviare in modo indipendente. Ogni timer è impostato su 2 minuti. ecco il mio codice completo


    ** clicchi per vedere App Screen shot **


    Fase 1: crea un'applicazione android con attività vuota


    Fase 2: Codice del file di layout di MainActivity


     <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/lv"/> </RelativeLayout> 

    Passo 3: crea un file di layout che viene utilizzato come elemento di elenco per il tuo listView (nome file res / layout / list_item.xml)


     <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorAccent" android:padding="5dp" android:layout_margin="5dp" android:textDirection="firstStrong"> <Button android:layout_width="100dp" android:layout_height="wrap_content" android:text="RESET" android:id="@+id/resetBtn" android:layout_alignParentLeft="true" android:background="@color/colorAccent" android:layout_weight=".2" android:textColor="#ffffff" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv" android:layout_toRightOf="@+id/resetBtn" android:text="Time : 02:00" android:textAlignment="center" android:textColor="#ffffff" android:layout_weight=".6" android:padding="@dimen/activity_vertical_margin" android:focusableInTouchMode="false" android:focusable="false" android:enabled="false" /> <Button android:layout_width="100dp" android:layout_height="wrap_content" android:textColor="#ffffff" android:id="@+id/startStopBtn" android:text="START" android:layout_weight=".2" android:background="@color/colorAccent" android:layout_alignParentRight="true" /> </LinearLayout> 

    Fase 4: creare una class che memorizza le informazioni di each timer (nome mio class CounterInfo)

      package com.example.rahul.timerapp1; import java.util.ArrayList; import java.util.List; public class CounterInfo { public boolean status; public int time; public static List<CounterInfo> getCounterListInfo() { List<CounterInfo> l = new ArrayList<CounterInfo>(); for(int i=0; i<20;i++) { CounterInfo c = new CounterInfo(); c.status=false; c.time=-1; l.add(c); } return l; } } 

    Passo 5: crea un adattatore per listView (il mio nome adattatore MyAdapter.java)


     import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.TextView; import java.util.List; public class MyAdapter extends BaseAdapter { List<CounterInfo> counterInfo; LayoutInflater inflater; Context context; MyAdapter(MainActivity mainActivity , List<CounterInfo> c) { context=mainActivity; counterInfo=c; } @Override public int getCount() { return counterInfo.size(); } @Override public Object getItem(int position) { return (CounterInfo)counterInfo.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { if(convertView==null) { inflater =(LayoutInflater)context.getSystemService(context.LAYOUT_INFLATER_SERVICE); convertView=inflater.inflate(R.layout.list_item, parent ,false); } Button resetBtn =(Button)convertView.findViewById(R.id.resetBtn); resetBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { counterInfo.get(position).time=-1; counterInfo.get(position).status=false; notifyDataSetChanged(); } }); Button startStopBtn = (Button)convertView.findViewById(R.id.startStopBtn); startStopBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if ((counterInfo.get(position)).status) { (counterInfo.get(position)).status = false; } else { (counterInfo.get(position)).status = true; if(counterInfo.get(position).time==-1 || counterInfo.get(position).time==-2) (counterInfo.get(position)).time = 119; } notifyDataSetChanged(); } }); TextView title=(TextView) convertView.findViewById(R.id.tv); title.setText(getRemainingTime(((CounterInfo)counterInfo.get(position)).time)); if(getRemainingTime(counterInfo.get(position).time).equals("done!")) { counterInfo.get(position).status=false; counterInfo.get(position).time=-2; } if((counterInfo.get(position).status)) { startStopBtn.setText("STOP"); } else { if(counterInfo.get(position).time==-2) startStopBtn.setText("RESTART"); else { if(counterInfo.get(position).time==-1) startStopBtn.setText("START"); else startStopBtn.setText("RESTART"); } } return convertView; } public String getRemainingTime(int seconds) { String time; if(seconds==-1) { time="02:00"; } else { if (seconds >= 60) { time = "01"; time += ":" + (seconds - 60); } else { if (seconds==-2) { time="done!"; } else { time = "00:" + seconds; } } } if(time.length()==4) time=time.substring(0,3)+"0"+time.charAt(3); if(time.equals("00:00")) { time="done!"; } return time; } } 

    Fase 6: eseguire l'applicazione!

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.