2015-06-25 11 views
14

Ich habe eine Listview (mit einem benutzerdefinierten Listenadapter), ich muss einen Countdown für jede Zeile anzeigen.Wie behandelt man mehrere Countdown-Timer in ListView?

Zum Beispiel, wenn meine Liste 4 Elemente enthält, werde ich 4 Zeilen haben. An diesem Punkt muss ich 4 verschiedene Countdowns (einer für jede Zeile) behandeln, weil die Zeit anders ist.

enter image description here

Bisher bin ich Umgang es die folgende Art und Weise: in der benutzerdefinierten Liste Adapter, innerhalb getView() -Methode erstelle ich eine neue CountDownTimer und Anzeige innerhalb Textview verbleibende Zeit.

Aber das Problem ist, dass es die Aktivität sehr verlangsamt, ich kann im schlimmsten Fall sogar nicht richtig scrollen (weil jedes Mal, wenn eine Zeile angezeigt wird, ein neuer CountDownTimer erstellt wird).

Ich suchte viel nach einer besseren Lösung, aber niemand war befriedigend.

Gibt es eine sauberere und glattere Lösung, um mehrere Countdown-Timer in einem ListView zu behandeln?

Dank

+0

Vielleicht http://learnncode.co/2014/01/21/listview-getviewtype-and-getviewtypecount-in-action/? – Andreyua

Antwort

21

Anstatt zu versuchen, die verbleibende Zeit für alle zu zeigen, ist die Idee, die verbleibende Zeit für die Elemente zu aktualisieren, die sichtbar sind.

Bitte folgen Sie den folgenden Beispielcode und lassen Sie mich wissen:

MainActivity:

public class MainActivity extends Activity { 

private ListView lvItems; 
private List<Product> lstProducts; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    lvItems = (ListView) findViewById(R.id.lvItems); 
    lstProducts = new ArrayList<>(); 
    lstProducts.add(new Product("A", System.currentTimeMillis() + 10000)); 
    lstProducts.add(new Product("B", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("C", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("D", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("E", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("F", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("G", System.currentTimeMillis() + 30000)); 
    lstProducts.add(new Product("H", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("I", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("J", System.currentTimeMillis() + 40000)); 
    lstProducts.add(new Product("K", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("L", System.currentTimeMillis() + 50000)); 
    lstProducts.add(new Product("M", System.currentTimeMillis() + 60000)); 
    lstProducts.add(new Product("N", System.currentTimeMillis() + 20000)); 
    lstProducts.add(new Product("O", System.currentTimeMillis() + 10000)); 

    lvItems.setAdapter(new CountdownAdapter(MainActivity.this, lstProducts)); 
} 

private class Product { 
    String name; 
    long expirationTime; 

    public Product(String name, long expirationTime) { 
     this.name = name; 
     this.expirationTime = expirationTime; 
    } 
} 


public class CountdownAdapter extends ArrayAdapter<Product> { 

    private LayoutInflater lf; 
    private List<ViewHolder> lstHolders; 
    private Handler mHandler = new Handler(); 
    private Runnable updateRemainingTimeRunnable = new Runnable() { 
     @Override 
     public void run() { 
      synchronized (lstHolders) { 
       long currentTime = System.currentTimeMillis(); 
       for (ViewHolder holder : lstHolders) { 
        holder.updateTimeRemaining(currentTime); 
       } 
      } 
     } 
    }; 

    public CountdownAdapter(Context context, List<Product> objects) { 
     super(context, 0, objects); 
     lf = LayoutInflater.from(context); 
     lstHolders = new ArrayList<>(); 
     startUpdateTimer(); 
    } 

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

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     ViewHolder holder = null; 
     if (convertView == null) { 
      holder = new ViewHolder(); 
      convertView = lf.inflate(R.layout.list_item, parent, false); 
      holder.tvProduct = (TextView) convertView.findViewById(R.id.tvProduct); 
      holder.tvTimeRemaining = (TextView) convertView.findViewById(R.id.tvTimeRemaining); 
      convertView.setTag(holder); 
      synchronized (lstHolders) { 
       lstHolders.add(holder); 
      } 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     holder.setData(getItem(position)); 

     return convertView; 
    } 
} 

private class ViewHolder { 
    TextView tvProduct; 
    TextView tvTimeRemaining; 
    Product mProduct; 

    public void setData(Product item) { 
     mProduct = item; 
     tvProduct.setText(item.name); 
     updateTimeRemaining(System.currentTimeMillis()); 
    } 

    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("Expired!!"); 
     } 
    } 
} 
} 

activity_main.xml:

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

<ListView 
    android:id="@+id/lvItems" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 

</RelativeLayout> 

list_item.xml

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

<TextView 
    android:id="@+id/tvProduct" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_margin="10dp" 
    android:text="Product Name" 
    android:textSize="16dp" 
    android:textStyle="bold" /> 

<TextView 
    android:id="@+id/tvTimeRemaining" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_margin="10dp" 
    android:text="Time Remaining : " /> 

</LinearLayout> 
+0

Es funktioniert wie ein Charme, einfach perfekt! Vielen Dank – Rob

+1

Jeder kann das mit recyclerview tun, ich habe 2 Tage daran gearbeitet, bitte helfen Sie !! –

+1

@AhmadAlkhateeb hast du eine Lösung bekommen? –

8

Es Macht zu spät, aber dies ist RecyclerView-Version mit PHP und JSON basierend auf hervorragende Antwort von @Eldhose M Babu. Ich hoffe, nützlich zu sein :)

Multiple countdown photo display

Adapter.java

public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> { 

    private Context context; 
    private final List<ViewHolder> lstHolders; 
    public List<Model> lst; 

    private Handler mHandler = new Handler(); 
    private Runnable updateRemainingTimeRunnable = new Runnable() { 
     @Override 
     public void run() { 
      synchronized (lstHolders) { 
       long currentTime = System.currentTimeMillis(); 
       for (ViewHolder holder : lstHolders) { 
        holder.updateTimeRemaining(currentTime); 
       } 
      } 
     } 
    }; 

    public Adapter(List<Model> lst, Context context){ 
     super(); 
     this.lst = lst; 
     this.context = context; 
     lstHolders = new ArrayList<>(); 
     startUpdateTimer(); 
    } 

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

    @Override 
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list, parent, false); 
     ViewHolder viewHolder = new ViewHolder(v); 
     return viewHolder; 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     holder.setData(lst.get(position)); 
     synchronized (lstHolders) { 
      lstHolders.add(holder); 
     } 
     holder.updateTimeRemaining(System.currentTimeMillis()); 
    } 

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

    class ViewHolder extends RecyclerView.ViewHolder{ 
     public TextView textViewName; 
     public TextView tvTimeRemaining; 
     Model mModel; 

     public void setData(Model item) { 
      mModel = item; 
      textViewName.setText(item.name); 
      updateTimeRemaining(System.currentTimeMillis()); 
     } 

     public void updateTimeRemaining(long currentTime) { 
      long timeDiff = mModel.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("Expired!!"); 
      } 
     } 

     public ViewHolder(View itemView) { 
      super(itemView); 
      tvTimeRemaining = (TextView) itemView.findViewById(R.id.cd); 
      textViewName = (TextView) itemView.findViewById(R.id.textViewName); 
     } 
    } 
} 

MainActivity.java

public class MainActivity extends AppCompatActivity { 

private List<Model> lst; 
private RecyclerView recyclerView; 
private RecyclerView.LayoutManager layoutManager; 
private RecyclerView.Adapter adapter; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
    setSupportActionBar(toolbar); 


    recyclerView = (RecyclerView) findViewById(R.id.recyclerView); 
    recyclerView.setHasFixedSize(true); 
    layoutManager = new LinearLayoutManager(this); 
    recyclerView.setLayoutManager(layoutManager); 
    lst = new ArrayList<>(); 
    getData(); 


    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 
    fab.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show(); 
     } 
    }); 
} 

private void getData(){ 
    final ProgressDialog loading = ProgressDialog.show(this,"Loading Data", "Please wait...",false,false); 

    JsonArrayRequest jsonArrayRequest = new JsonArrayRequest("http://192.168.200.102/api.php", 
      new Response.Listener<JSONArray>() { 
       @Override 
       public void onResponse(JSONArray response) { 
        loading.dismiss(); 
        parseData(response); 
       } 
      }, 
      new Response.ErrorListener() { 
       @Override 
       public void onErrorResponse(VolleyError error) { 

       } 
      }); 

    RequestQueue requestQueue = Volley.newRequestQueue(this); 
    requestQueue.add(jsonArrayRequest); 
} 

private void parseData(JSONArray array){ 
    for(int i = 0; i<array.length(); i++) { 
     Model model = new Model(); 
     JSONObject json = null; 
     try { 
      json = array.getJSONObject(i); 
      model.setexpirationTime(json.getLong("expirationTime")); 
      model.setName(json.getString("name")); 
     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 
     lst.add(model); 
    } 

    adapter = new Adapter(lst, this); 
    recyclerView.setAdapter(adapter); 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    getMenuInflater().inflate(R.menu.menu_main, menu); 
    return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    int id = item.getItemId(); 

    if (id == R.id.action_settings) { 
     return true; 
    } 

    return super.onOptionsItemSelected(item); 
}} 

Model.java

public class Model { 
public String name; 
public long expirationTime; 

public long getexpirationTime() { 
    return expirationTime; 
} 

public void setexpirationTime(long expire) { 
    this.expirationTime = expire; 
} 

public String getName() { 
    return name; 
} 

public void setName(String name) { 
    this.name = name; 
}} 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fitsSystemWindows="true" 
    tools:context="here.math.MainActivity"> 

    <android.support.design.widget.AppBarLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:theme="@style/AppTheme.AppBarOverlay"> 

     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      app:popupTheme="@style/AppTheme.PopupOverlay" /> 

    </android.support.design.widget.AppBarLayout> 

    <include layout="@layout/content_main" /> 

    <android.support.design.widget.FloatingActionButton 
     android:id="@+id/fab" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="bottom|end" 
     android:layout_margin="@dimen/fab_margin" 
     android:src="@android:drawable/ic_dialog_email" /> 

</android.support.design.widget.CoordinatorLayout> 

content_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    app:layout_behavior="@string/appbar_scrolling_view_behavior" 
    tools:context="here.math.MainActivity" 
    tools:showIn="@layout/activity_main"> 

     <android.support.v7.widget.RecyclerView 
      android:id="@+id/recyclerView" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content"> 
     </android.support.v7.widget.RecyclerView> 
</RelativeLayout> 

Liste.xml

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

    <android.support.v7.widget.CardView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="20dp"> 

     <LinearLayout 
      android:padding="@dimen/activity_horizontal_margin" 
      android:orientation="vertical" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent"> 


      <TableLayout 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content"> 

       <TableRow> 
        <TextView 
         android:text="Expire time" 
         android:paddingRight="10dp" 
         android:layout_width="wrap_content" 
         android:layout_height="wrap_content" /> 

        <TextView 
         android:id="@+id/cd" 
         android:textStyle="bold" 
         android:layout_width="wrap_content" 
         android:layout_height="wrap_content" /> 

       </TableRow> 

       <TableRow> 
        <TextView 
         android:text="Name" 
         android:paddingRight="10dp" 
         android:layout_width="wrap_content" 
         android:layout_height="wrap_content" /> 

        <TextView 
         android:id="@+id/textViewName" 
         android:textStyle="bold" 
         android:layout_width="wrap_content" 
         android:layout_height="wrap_content" /> 

       </TableRow> 

      </TableLayout> 
     </LinearLayout> 
    </android.support.v7.widget.CardView> 

</RelativeLayout> 

und für url Teil können Sie Art von etwas tun:

<?php 

$arr = array(
array(
     'name' => "Android", 
     'expirationTime' => 1456860322 * 1000, // timestamp multiply for display in milliseconds 
), 
array(
     'name' => "Android 2", 
     'expirationTime' => 1456900522 * 1000, 
), 
array(
     'name' => "Android 3", 
     'expirationTime' => 1459509819 * 1000, 
), 
array(
     'name' => "Android 4", 
     'expirationTime' => 1457021950 * 1000, 
), 
); 

echo json_encode($arr); 
+0

wie kann ich es nur für nur 2 Reihe tun – andro

+0

@andro, basierend auf PHP-Skript, das ich gepostet habe, entfernen Sie die letzten beiden Arrays. Lass es mich wissen, wenn du auf etwas feststeckst. –

+0

in unserem Beispiel Problem ist synchronisiert (lstHolders) { lstHolders.add (Halter); } Sie immer Halter zur Liste hinzufügen. also sssay wenn der 10 reihe sind, wenn ich nach oben streiche Größe von lstHolders wird es sollte maximal 10 sein – andro

1

Bitte schauen Sie auf dieser Countdown Timer in listview android Beispiel.

Individuelle Adapter

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<Adapter.MyViewHolder>{ 

private ArrayList<String> 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<String> 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(); 
} 



} 

Hauptaktivität

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<String> 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); 
} 
} 

Dank

0

Adapter Klasse: -


Öffentliche Klasse CountdownAdapter erweitert RecyclerView.Adapter { ArrayList mList; Kontext mContext;

public CountdownAdapter(ArrayList<Long> mList, Context mContext) { 
    this.mList = mList; 
    this.mContext = mContext; 
} 

public class ViewHolder extends RecyclerView.ViewHolder { 
    CountDownTimer timerCount; 
    TextView mCountDownTxt; 

    public ViewHolder(View convertView) { 
     super(convertView); 
     mCountDownTxt = (TextView)convertView.findViewById(R.id.countdown_text); 
    } 
} 

@Override 
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    return null; 
} 

@Override 
public void onBindViewHolder(final ViewHolder holder, final int position) { 
    if(holder.timerCount==null) { 
     holder.timerCount = new CountDownTimer(mList.get(position), 1000) { 
      @Override 
      public void onTick(long millis) { 
       String hms = String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))); 
       holder.mCountDownTxt.setText(hms); 
      } 

      @Override 
      public void onFinish() { 

      } 
     }; 
    } 
    holder.mCountDownTxt.setVisibility(View.VISIBLE); 
    holder.timerCount.start(); 
} 

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

}