如何在ListView中处理多个倒数计时器?
我有一个列表视图(与自定义列表适配器),我需要显示在每一行倒计时。
例如,如果我的列表包含4个项目,我将有4行。 在这一点上,我需要处理4个不同的倒计时(每行一个),因为时间是不同的。
到目前为止,我正在处理它的方式如下:在自定义列表适配器里面,getView()方法创build一个新的CountDownTimer并显示TextView中的剩余时间。
但是问题在于它减慢了很多活动,在最坏的情况下我甚至无法正确滚动(因为每次显示一行时,都会创build一个新的CountDownTimer)。
我search了很多更好的解决scheme,但没有人满意。
有一个更清洁和更顺利的解决scheme来处理listView内的多个倒计时定时器?
谢谢
而不是试图显示所有的剩余时间,这个想法是更新可见项目的剩余时间。
请按照下面的示例代码,让我知道:
主要活动 :
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>
它可能会迟到,但这是基于@Eldhose M巴布优秀答案php和json recyclerView版本。 希望有所帮助:)
多次倒计时照片显示
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>
list.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>
对于url部分,你可以做一些事情:
<?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);
请看看这个倒计时定时器在ListView的Android例子。
自定义适配器
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(); } }
主要活动
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); } }
谢谢
适配器类: –
公共类CountdownAdapter扩展RecyclerView.Adapter {ArrayList mList; 上下文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(); }
}