(カスタムリストアダプターを使用した)リストビューがあります。すべての行にカウントダウンを表示する必要があります。
たとえば、リストに4つのアイテムが含まれている場合、4つの行があります。この時点では、時間が異なるため、4つの異なるカウントダウン(行ごとに1つ)を処理する必要があります。
これまでのところ、私は次のように処理しています:カスタムリストアダプターのgetView()メソッド内で、新しいCountDownTimerを作成し、TextView内に残り時間を表示します。
しかし問題は、アクティビティが大幅に遅くなることです。最悪の場合でも正しくスクロールできません(行が表示されるたびに新しいCountDownTimerが作成されるため)。
私はより良い解決策を求めてたくさん検索しましたが、誰も満足していませんでした。
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 Babuの優れた回答に基づく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 extends 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();
}
}