Multiple Countdown Timer in Expandable Listview Android not working - android

From last week I am trying to implement multiple countdown timer in expandable list view.I want to decrease time till 00:00:00 and according to that I need to update text in parent element of expandable list view.
My problem is :
1) on scrolling expandable list view timer restarts
2) on expand and collapse timer restarts
3) on event on child button i need to update particular position's text on parentview
One more thing I'm trying to implement is on clicking one button from child view I need to update text on parent view but i'm stucked there.
Here is my adapter containing both parent and child.
public class Sent_ListAdapter extends BaseExpandableListAdapter {
private Context _context;
**private List<SentModel> _listDataHeader;**
// child data in format of header title, child title
**private HashMap<SentModel, List<SentModel>> _listDataChild;**
private TextView txt_summary;
private TextView datetime_element;
private LinearLayout ll_arrowtorecord;
**private String[] ti;**
**private CountDownTimer cdt_sent;**
**private HashMap<TextView, CountDownTimer> counters;**
**private TextView deadline;**
public Sent_ListAdapter(Context context, List<SentModel> listDataHeader, HashMap<SentModel, List<SentModel>> listChildData) {
this._context = context;
this._listDataHeader = listDataHeader;
this._listDataChild = listChildData;
ll_end = new FrameLayout[_listDataHeader.size()];
ll_closeaceess = new FrameLayout[_listDataHeader.size()];
ll_whoaccpted = new LinearLayout[_listDataHeader.size()];
**this.counters = new HashMap<TextView, CountDownTimer>();**
}
#Override
public int getGroupCount() {
return this._listDataHeader.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return this._listDataChild.get(this._listDataHeader.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return this._listDataHeader.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return this._listDataChild.get(this._listDataHeader.get(groupPosition)).get(childPosition);
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
final SentModel headerTitle = (SentModel) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.element_sentlist, null);
}
ll_arrowtorecord = (LinearLayout) convertView.findViewById(R.id.ll_arrowtorecord);
ll_arrowtorecord.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (headerTitle.getFile().trim().contains(".mp4")) {
Log.v("", TAG + "==video==" + headerTitle.getFile());
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
Uri data = Uri.parse(headerTitle.getFile());
intent.setDataAndType(data, "video/mp4");
startActivity(intent);
} else if (headerTitle.getFile().trim().contains(".jpg")) {
Log.v("", TAG + "==image==" + headerTitle.getFile());
Intent gotorecoedactivity = new Intent(context, RecordedAsset.class);
gotorecoedactivity.putExtra("image", headerTitle.getFile());
startActivity(gotorecoedactivity);
overridePendingTransition(R.anim.right_slide_in, R.anim.left_side_out);
finish();
} else {
Toast.makeText(context, "No recorded asset is there.", Toast.LENGTH_SHORT).show();
}
}
});
txt_summary = (TextView) convertView.findViewById(R.id.txt_summary);
if (headerTitle.get_desc().equalsIgnoreCase("") || headerTitle.get_desc() == null) {
txt_summary.setText(" Description");
} else {
txt_summary.setText(headerTitle.get_desc());
}
datetime_element = (TextView) convertView.findViewById(R.id.datetime_element);
final TextView tv = datetime_element;
deadline = (TextView) convertView.findViewById(R.id.deadline);
**if (headerTitle.getRemaining_completion_time().equalsIgnoreCase("") || headerTitle.getRemaining_completion_time() == null) {
datetime_element.setText("");
}
else if (headerTitle.getRemaining_completion_time().equalsIgnoreCase("00:00:00"))
{
tv.setText("Completion time over");
deadline.setVisibility(View.GONE);
}
else
{
ti = headerTitle.getRemaining_completion_time().split(":");
int hrs = Integer.parseInt(ti[0]);
cdt_sent = counters.get(datetime_element);
int days = Integer.parseInt(headerTitle.getRemaining_days());
// int hours1 = datetime_plus(days, Integer.parseInt(ti[0]));
int min = Integer.parseInt(ti[1]);
int sec = Integer.parseInt(ti[2]);
long d1 = TimeUnit.DAYS.toMillis(days);
long m1 = TimeUnit.MINUTES.toMillis(min);
long h1 = TimeUnit.HOURS.toMillis(hrs);
long s1 = TimeUnit.SECONDS.toMillis(sec);
final long milliseco = d1 + m1 + h1 + s1;
if (cdt_sent != null) {
cdt_sent.cancel();
cdt_sent = null;
}
cdt_sent = new CountDownTimer(milliseco, 1000)
{
int days = 0;
int hours1 = 0;
private String sDate;
int min = 0;
int sec = 0;
#Override
public void onTick(long millisUntilFinished)
{
millisUntilFinished -= (days * DateUtils.DAY_IN_MILLIS);
if (millisUntilFinished > DateUtils.HOUR_IN_MILLIS)
{
hours1 = (int) (millisUntilFinished / DateUtils.HOUR_IN_MILLIS);
}
millisUntilFinished -= (hours1 * DateUtils.HOUR_IN_MILLIS);
if (millisUntilFinished > DateUtils.MINUTE_IN_MILLIS)
{
min = (int) (millisUntilFinished / DateUtils.MINUTE_IN_MILLIS);
}
millisUntilFinished -= (min * DateUtils.MINUTE_IN_MILLIS);
if (millisUntilFinished > DateUtils.SECOND_IN_MILLIS)
{
sec = (int) (millisUntilFinished / DateUtils.SECOND_IN_MILLIS);
}
sDate = " " + String.format("%02d", hours1) + "h " + String.format("%02d", min) + "m " + String.format("%02d", sec) + "s ";
_listDataHeader.get(groupPosition).setTime(sDate);
String hms = String.format("%02d,%02d:%02d:%02d", TimeUnit.MILLISECONDS.toDays(milliseco),TimeUnit.MILLISECONDS.toHours(milliseco),
TimeUnit.MILLISECONDS.toMinutes(milliseco) % TimeUnit.HOURS.toMinutes(1),
TimeUnit.MILLISECONDS.toSeconds(milliseco) % TimeUnit.MINUTES.toSeconds(1));
// Log.v("", "Bansi"+"==hms=="+hms);
tv.setText(_listDataHeader.get(groupPosition).getTime());
}
#Override
public void onFinish() {
tv.setText("Completion time over");
deadline.setVisibility(View.GONE);
}
};
counters.put(tv, cdt_sent);
cdt_sent.start();
}**
return convertView;
}
#SuppressLint("InflateParams")
#Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final SentModel childText = (SentModel) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.element_childsent, null);
}
ll_whoaccpted[groupPosition] = (LinearLayout) convertView.findViewById(R.id.ll_whoaccpted);
ll_end[groupPosition] = (FrameLayout) convertView.findViewById(R.id.ll_end);
ll_closeaceess[groupPosition] = (FrameLayout) convertView.findViewById(R.id.ll_closeaceess);
txt_whoaccepted = (TextView) convertView.findViewById(R.id.txt_whoaccepted);
img_block = (ImageView) convertView.findViewById(R.id.img_block);
img_end = (ImageView) convertView.findViewById(R.id.img_end);
txt_end = (TextView) convertView.findViewById(R.id.txt_end);
txt_closeacess = (TextView) convertView.findViewById(R.id.txt_closeacess);
ll_whoaccpted[groupPosition].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showWhoAcceptedpopup(childText.getB_id(), groupPosition + "");
if (Utils.detectInternetConnection(context)) {
new post_WhoAccepted().execute(childText.getB_id(), groupPosition + "");
} else {
progressDialog.showWarningDialog_Click(getString(R.string.no_internet), new OnClickListener() {
#Override
public void onClick(View v) {
progressDialog.dialogDismiss();
try {
Intent callGPSSettingIntent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
startActivity(callGPSSettingIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
});
if (childText.getIs_cancel().equalsIgnoreCase("0")) {
ll_end[groupPosition].setBackgroundColor(Color.parseColor("#CBCBCB"));
txt_end.setTextColor(Color.parseColor("#7E7E7E"));
txt_end.setText("You ended the .");
txt_end.setGravity(Gravity.CENTER);
img_end.setImageResource(R.drawable.cross_circleclick);
ll_end[groupPosition].setClickable(false);
} else {
ll_end[groupPosition].setBackgroundColor(Color.parseColor("#650030"));
txt_end.setTextColor(Color.parseColor("#FF0101"));
txt_end.setText("End ");
txt_end.setGravity(Gravity.RIGHT);
img_end.setImageResource(R.drawable.cross_circle);
ll_end[groupPosition].setClickable(true);
if (endornot.get(groupPosition) == 0) {
} else {
ll_end[groupPosition].setBackgroundColor(Color.parseColor("#CBCBCB"));
txt_end.setTextColor(Color.parseColor("#7E7E7E"));
txt_end.setText("You ended the .");
img_end.setImageResource(R.drawable.cross_circleclick);
txt_end.setGravity(Gravity.CENTER);
ll_end[groupPosition].setClickable(false);
}
ll_end[groupPosition].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.v("", TAG + "==childposition==" + groupPosition);
if (endornot.get(groupPosition) == 0) {
if (Utils.detectInternetConnection(context)) {
new post_EndorClose().execute(childText.getB_id(), "1", groupPosition + "");
} else {
progressDialog.showWarningDialog_Click(getString(R.string.no_internet), new OnClickListener() {
#Override
public void onClick(View v) {
progressDialog.dialogDismiss();
try {
Intent callGPSSettingIntent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
startActivity(callGPSSettingIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
} else {
}
}
});
}
if (childText.getIs_close().equalsIgnoreCase("0")) {
ll_closeaceess[groupPosition].setBackgroundColor(Color.parseColor("#E7E7E7"));
txt_closeacess.setTextColor(Color.parseColor("#7E7E7E"));
txt_closeacess.setText("Access to the closed");
txt_closeacess.setGravity(Gravity.CENTER);
ll_closeaceess[groupPosition].setClickable(false);
} else {
ll_closeaceess[groupPosition].setBackgroundColor(Color.parseColor("#006500"));
txt_closeacess.setTextColor(Color.parseColor("#043303"));
txt_closeacess.setText("Close access to ");
ll_closeaceess[groupPosition].setClickable(true);
txt_closeacess.setGravity(Gravity.RIGHT);
if (aceessdeniedornot.get(groupPosition) == 0) {
} else {
ll_closeaceess[groupPosition].setBackgroundColor(Color.parseColor("#E7E7E7"));
txt_closeacess.setTextColor(Color.parseColor("#7E7E7E"));
txt_closeacess.setText("Access to the closed");
txt_closeacess.setGravity(Gravity.CENTER);
ll_closeaceess[groupPosition].setClickable(false);
}
ll_closeaceess[groupPosition].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.v("", TAG + "==childposition==" + groupPosition);
if (aceessdeniedornot.get(groupPosition) == 0) {
if (Utils.detectInternetConnection(context)) {
new post_EndorClose().execute(childText.getB_id(), "2", groupPosition + "");
} else {
progressDialog.showWarningDialog_Click(getString(R.string.no_internet), new OnClickListener() {
#Override
public void onClick(View v) {
progressDialog.dialogDismiss();
try {
Intent callGPSSettingIntent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
startActivity(callGPSSettingIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
} else {
}
}
});
}
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
Please help me out I'm stucked here still I am trying to work on it but I have time constaint.
Thanks!

I got to say this first, your code is really hard to read.
Try to split using methods the view creation code from your busyness code on getGroupView and getChildView. Also you could use ViewHolder pattern on getChildView to hold your views instead of thoses arrays (ll_whoaccpted, etc...)
TextUtils.isEmpty() can help you check better is your String are empty or null
if (TextUtils.isEmpty(headerTitle.getRemaining_completion_time()))
//instead of
if (headerTitle.getRemaining_completion_time().equalsIgnoreCase("") || headerTitle.getRemaining_completion_time() == null)
Make Sent_ListAdapter implement OnClickListener instead of recreating the listener (new) each time Android gets a View for your list. Add a condition on the view parameter to check which view type was click.
Work with Date and SimpleDataFormat on CountDownTimer, thoses manual string formatting are just awfull and unreadable
Well now to the main subject :
on scrolling expandable list view timer restarts
This happends because a ListView recreates the views/groups that are not showned (calling the getView/getGroup methods) to reuse the rows for other data.
If you want to avoid this you should create and start your counters outside the getView and getGroup (the constructor is a good place).
on expand and collapse timer restarts
Exactly the same thing that happends on the first problem.
on event on child button i need to update particular position's text
on parentview
I didn't really get this so am guessing that you want to change the text of a TextView on the main layout (the one containing the listview). Well you need to give a reference of that TextView to the Sent_ListAdapter.
Or, instead of passing a generic Context to the Sent_ListAdapter pass the Activity/Fragment it self :
public Sent_ListAdapter(MyActivity activty, List<SentModel> listDataHeader, HashMap<SentModel, List<SentModel>> listChildData) {
this._myactivity = myactivity;
this._listDataHeader = listDataHeader;
...
}
// The listener that handles all the events of your Sent_ListAdapter
#Override
public void onClick(View v) {
if(v.getTag() == "theBoutonThatShouldResetTheCounter") { //or other condition
myactivite.myTextView.setText("------");
}
}
Edit
But how will I get position in constructor for every row?
You need to think the other way around : the listview uses your datasource to show the rows. So you need to loop over the elements on your datasource (listDataHeader in your case). Something like :
private List<CountDownTimer> counters;
public Sent_ListAdapter(Context context, List<SentModel> listDataHeader, HashMap<SentModel, List<SentModel>> listChildData) {
...
counters = new ArrayList()<>;
for(SentModel model : listDataHeader) {
long milliseco = model.getRemainingTimeInMs(); //TODO: create something like this or figure out how to get your couters starting times on ms
CountDownTimer cdt = new MyCountDownTimer(milliseco, 1000);
cdt.start(); // I don't know when you want to start your counters, if they start at the same time it could be here
}
}
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
...
datetime_element = (TextView) convertView.findViewById(R.id.datetime_element);
deadline = (TextView) convertView.findViewById(R.id.deadline);
...
CountDownTimer cdt = counters.get(groupPosition);
cdt.setTv1 = datetime_element;
cdt.setTv2 = deadline;
...
}
public class MyCountDownTimer extends CountDownTimer {
public TextView tv1; //TODO: make setters instead of public
public TextView tv2; //TODO: make setters instead of public
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
//Only use this if u have something to do each tick
SimpleDateFormat df = new SimpleDateFormat(" dd,hh:mm:ss");
Date timeRemaining = //TODO: figure out how you calculate your remaining time
if(tv1 != null) {
tv1.setText(df.format(timeRemaining));
}
}
#Override
public void onFinish() {
if(tv1 != null && tv2!= null) {
tv1.setText("Completion time over");
tv2.setVisibility(View.GONE);
}
}
}

Related

How to increment TextView value outside ListView when ListView button is clicked in Android

I have a TextView outside ListView and i need to add prices when the plus button (ie,quantity is incremented )in ListView is clicked.In my program i am not able to add prices when new position ListView button is clicked.I need to find the total price to be payed by the customer when plus button is clicked in ListView
public class ListAdapter1 extends BaseAdapter {
public int qty=1;
public ArrayList<Integer> quantity = new ArrayList<Integer>();
private TextView total;
private String[] listViewItems,prices,weight;
TypedArray images;
public static int pValue;
private Context context;
public static boolean t=false;
CustomButtonListener customButtonListener;
public void setTextView(TextView total)
{
this.total = total;
}
public ListAdapter1(Context context, String[] listViewItems, TypedArray images, String[] weight, String[] prices) {
this.context = context;
this.listViewItems = listViewItems;
this.images = images;
this.prices=prices;
this.weight=weight;
}
public void setCustomButtonListener(CustomButtonListener customButtonListner)
{
this.customButtonListener = customButtonListner;
}
#Override
public int getCount() {
return 5;
}
#Override
public String getItem(int position) {
return listViewItems[position];
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View row;
final ListViewHolder listViewHolder;
if(convertView == null)
{
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = layoutInflater.inflate(R.layout.product,parent,false);
listViewHolder = new ListViewHolder();
listViewHolder.tvProductName = (TextView) row.findViewById(R.id.tvProductName)
listViewHolder.tvPrices = (TextView) row.findViewById(R.id.tvProductPrice);
listViewHolder.btnPlus = (ImageButton) row.findViewById(R.id.ib_addnew);
listViewHolder.edTextQuantity = (EditText) row.findViewById(R.id.editTextQuantity);
listViewHolder.btnMinus = (ImageButton) row.findViewById(R.id.ib_remove);
row.setTag(listViewHolder);
}
else
{
row=convertView;
listViewHolder= (ListViewHolder) row.getTag();
}
try{
listViewHolder.edTextQuantity.setText(quantity.get(position) );
}catch(Exception e){
e.printStackTrace();
}
listViewHolder.btnMinus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, " " + position, Toast.LENGTH_SHORT).show();
int mValue = Integer.parseInt(listViewHolder.edTextQuantity.getText().toString());
if (mValue <=0) {
System.out.println("not valid");
mValue=0;
listViewHolder.edTextQuantity.setText("" +mValue);
}
else{
pValue=pValue/mValue;
mValue--;
pValue=pValue*mValue;
total.setText(String.valueOf(pValue));
System.out.println("mvalue after reducing-----------"+mValue);
System.out.println("pvalue-----------"+pValue);
listViewHolder.edTextQuantity.setText( "" +mValue );
}
}
});
listViewHolder.btnPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, " " + position, Toast.LENGTH_SHORT).show();
int mValue = Integer.parseInt(listViewHolder.edTextQuantity.getText().toString());
pValue=Integer.parseInt(listViewHolder.tvPrices.getText().toString());
mValue++;
listViewHolder.edTextQuantity.setText("" + mValue);
System.out.println("mValue after increment---" + mValue);
pValue=pValue*mValue;
System.out.println("pvalue-----------"+pValue);
total.setText(String.valueOf(pValue));
}
});
return row;
}
I need to get total price when any of the ListView button is clicked.
First you need to store value in HashMap<> when user click the plus and minus button.
Then sum the all values in HashMap.
For Example
try{
int sum = 0;
for(HashMap<String, String> map : arrayList) {
sum += Integer.parseInt(map.get("mark"));
}
} catch (Exception e) {
//Manage your exception
}
// sum has the value for the marks total.
System.out.println("Total Marks: "+sum);
Refere my previous answer Here
For that you need to create interface which notify in activity where you want that count.
put snippet in adapter to initialize interface and setter.
public interface IEvent {
void onItemChange(int count);
}
private IEvent iEvent;
//setter method for interface
public void setQuanityEvent(IEvent ievent) {
this.lastPageHandler = handler;
}
put this code in btnMinus.setOnClickListener
//if ievent interface variable register via set
if (ievent != null) {
//pValue is quality COUNT you want to send outside listview.
ievent.onItemChange(pValue);
}
activity code after creating adapter instance
//ListAdapter1 adapter = new ListAdapter1(your params);
adapter.setQuanityEvent(new ListAdapter1.IEvent() {
#Override
public void onItemChange(int count) {
}
}
});

Android list view change text when row is deleted

I have a ListView, which has an hidden button which become visible on user long click on row.
If someone clicks this button, the row is deleted.
My rows are composed by transactions, and in the same Activity i got a TextView displaying the amount.
When I add a transaction, my text is changed and the budget updated. My problem is updating it when an user clicks the button and deletes a row.
here is my adapter class
public class HomePageListAdapter extends ArrayAdapter<TRANSAZIONE> {
ArrayList<TRANSAZIONE> transazioni;
public HomePageListAdapter(Context context, int textViewResourceId,
ArrayList<TRANSAZIONE> objects) {
super(context, textViewResourceId, objects);
transazioni = objects;
}
TRANSAZIONE transazione;
NumberFormat formatter = new DecimalFormat("#0.00");
#Override
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.adapter_home_page_list, null);
TextView tvDesc = (TextView) view.findViewById(R.id.tvDescription);
TextView tvAmou = (TextView) view.findViewById(R.id.tvAmount);
final Button btnElimina = (Button) view.findViewById(R.id.btnElimina);
transazione = transazioni.get(position);
String dText = transazione.getDescription();
String aText = "";
if(transazione.getAmount() != null) {
aText = formatter.format(transazione.getAmount()) + " €";
if (transazione.getAmount() > 0) {
tvAmou.setTextColor(Color.GREEN);
} else {
tvAmou.setTextColor(Color.RED);
}
}
tvDesc.setText(dText);
tvAmou.setText(aText);
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
btnElimina.setVisibility(View.VISIBLE);
return false;
}
});
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (btnElimina.getVisibility() == View.VISIBLE) {
btnElimina.setVisibility(View.GONE);
}
}
});
btnElimina.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
new TRANSAZIONE().Delete(TRANSAZIONE.class, getContext(), "where id = '" + transazioni.get(position).getId() + "'");
Toast.makeText(getContext(), "Transazione eliminata.", Toast.LENGTH_SHORT).show();
transazioni.remove(position);
notifyDataSetChanged();
} catch (Exception ex) {
Toast.makeText(getContext(), "Errore non gestito.", Toast.LENGTH_SHORT).show();
}
}
});
return view;
}
}
It works properly, and I have no problems updating my layout.
** And this is the method which updates my TextView's text and calls the Adapter. It's in the Activity**
public void LoadTotal() throws Exception {
#SuppressWarnings("unchecked")
ArrayList<TRANSAZIONE> transazioni = (ArrayList<TRANSAZIONE>) new TRANSAZIONE().SelectAll(TRANSAZIONE.class, getContext(), "");
Double totale = Settings.getLimitAmount();
//prendo solo quelle del mese corrente
if (transazioni.size() > 0) {
int numeroAggiornamento = Settings.getResettingDay();
Calendar today = Calendar.getInstance();
Calendar transactionDate = Calendar.getInstance();
Calendar lastChangeDate = Calendar.getInstance();
lastChangeDate.set(Calendar.DAY_OF_MONTH, numeroAggiornamento);
if (today.get(Calendar.DAY_OF_MONTH) < numeroAggiornamento) {
lastChangeDate.add(Calendar.MONTH, -1);
}
for (TRANSAZIONE t : transazioni) {
transactionDate.setTime(t.getDate());
if (transactionDate.compareTo(lastChangeDate) == -1) {
transazioni.remove(t);
} else {
totale += t.getAmount();
}
}
}
if (transazioni.size() == 0) {
transazioni.add(new TRANSAZIONE("Nessuna transazione per il mese in corso.", null, null));
}
HomePageListAdapter adapter = new HomePageListAdapter(getContext(), R.layout.adapter_home_page_list, transazioni);
lvTransactions.setAdapter(adapter);
tvBudget.setText(formatter.format(totale));
}
My problem is the following:
When I delete a row, it disappears from the list, but I can't intercept this in my Activity.
I need someway to call the method LoadTotal() when my row is deleted.
Any help will be appreciated.
Thanks all and sorry for my not perfect English.
The cleanest way of doing it is by using a DataSetObserver.
Inside your activity you have this object:
private DataSetObserver adapterObserver = new DataSetObserver() {
#Override
public void onChanged(){
// here you call your method
LoadTotal();
}
}
and then you register/unreguster this observer during onResume/onPause
#Override
public void onResume(){
super.onResume();
LoadTotal(); // update with latest values
adapter.registerDataSetObserver(adapterObserver);
}
#Override
public void onPause(){
super.onPause();
adapter.unregisterDataSetObserver(adapterObserver);
}
edit: some debug info for the op.
here is the code for notifyDataSetChanged() from BaseAdapter
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
and then inside DataSetObservable is simply looping through the list of observers
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
That means there's very little to actually go wrong there. But it's important to understand what is happening. So my suggestion is to put a breakpoint on all the method calls: onPause, onResume, onChanged and the line you call notifyDataSetChanged. And run it with the debugger, so you can see what is being called when and find out why it's not working.
In your adapter class
public class HomePageListAdapter extends ArrayAdapter<TRANSAZIONE> {
Context context;
ArrayList<TRANSAZIONE> transazioni;
public HomePageListAdapter(Context context, int textViewResourceId,
ArrayList<TRANSAZIONE> objects) {
super(context, textViewResourceId, objects);
transazioni = objects;
this.context=context;
}
TRANSAZIONE transazione;
NumberFormat formatter = new DecimalFormat("#0.00");
#Override
public View getView(final int position, View view, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.adapter_home_page_list, null);
TextView tvDesc = (TextView) view.findViewById(R.id.tvDescription);
TextView tvAmou = (TextView) view.findViewById(R.id.tvAmount);
final Button btnElimina = (Button) view.findViewById(R.id.btnElimina);
transazione = transazioni.get(position);
String dText = transazione.getDescription();
String aText = "";
if(transazione.getAmount() != null) {
aText = formatter.format(transazione.getAmount()) + " €";
if (transazione.getAmount() > 0) {
tvAmou.setTextColor(Color.GREEN);
} else {
tvAmou.setTextColor(Color.RED);
}
}
tvDesc.setText(dText);
tvAmou.setText(aText);
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
btnElimina.setVisibility(View.VISIBLE);
return false;
}
});
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (btnElimina.getVisibility() == View.VISIBLE) {
btnElimina.setVisibility(View.GONE);
}
}
});
btnElimina.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
new TRANSAZIONE().Delete(TRANSAZIONE.class, getContext(), "where id = '" + transazioni.get(position).getId() + "'");
Toast.makeText(getContext(), "Transazione eliminata.", Toast.LENGTH_SHORT).show();
transazioni.remove(position);
notifyDataSetChanged();
} catch (Exception ex) {
Toast.makeText(getContext(), "Errore non gestito.", Toast.LENGTH_SHORT).show();
}
}
});
return view;
}
}
You can call the method of your activity like
((YourActivityName)context).LoadTotal();

Closed or circular Vertical ListView Android

I have an Vertical listview i want listview should be closed. For example if the last item is reached in Listview then show the first item below the last item. It means item should be in circular format. And if i scroll from first item it should show last item before first item. I want scrolling for both side.
public class MainActivity extends Activity {
ListView list;
long startTime;
long endTime;
List<String> mList = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = (ListView) findViewById(R.id.list);
downloadDetails();
String str;
for (int i = 0; i < 10; i++) {
str = new String("Data --- " + i);
mList.add(str);
}
CircularAdapter adapter = new CircularAdapter(this, 0, mList);
list.setAdapter(adapter);
final YourRunnable runy = new YourRunnable();
list.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
startTime = (new Date()).getTime();
runy.onPause();// pausing thread actually pauses scrolling
}
if (event.getAction() == MotionEvent.ACTION_UP) {
endTime = (new Date()).getTime();
if ((endTime - startTime) <= 100) {// 100 mill second limit
// for click
// Log.i("ITEM CLICK() ", "item : ");
}
runy.onResume(); // resume scrolling
}
return false;
}
});
new Thread(runy).start();
}
class YourRunnable implements Runnable {
private Object mPauseLock;
private boolean mPaused;
private boolean mFinished;
public YourRunnable() {
mPauseLock = new Object();
mPaused = false;
mFinished = false;
}
#SuppressLint("NewApi")
public void run() {
while (!mFinished) {
// for loop is not infinite but enough as Integer.MAX_VALUE
for (int index = 0; index < list.getAdapter().getCount(); index++) {
list.smoothScrollToPositionFromTop(list.getLastVisiblePosition() + 1, 0, 10000);
try {
// it helps scrolling to stay smooth as possible (by
// experiment)
Thread.sleep(3000);
synchronized (mPauseLock) {
while (mPaused) {
try {
mPauseLock.wait();// putting thread in wait
// list of mPauseLock
// object
} catch (InterruptedException e) {
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// to pause list
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
// resume thread
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();// notify all object that are waiting on
// the wait list of mPauseLock object
}
}
}
private class CircularAdapter extends ArrayAdapter {
List<String> mlist;
Context mContext;
LayoutInflater inflater;
public final int HALF_MAX_VALUE = Integer.MAX_VALUE / 2;
public final int MIDDLE;
#SuppressWarnings("unchecked")
public CircularAdapter(Context ctx, int resId, List<String> objects) {
super(ctx, resId, objects);
mContext = ctx;
mlist = objects;
inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
MIDDLE = HALF_MAX_VALUE - HALF_MAX_VALUE % mlist.size();
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return Integer.MAX_VALUE;
}
#Override
public String getItem(int position) {
// TODO Auto-generated method stub
int relativePos = position % mlist.size();
Log.i("RELATIVE : ", " POS:" + relativePos);
return mlist.get(relativePos);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.item, parent, false);
holder.name = (TextView) convertView.findViewById(R.id.name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
String model = getItem(position);
holder.name.setText(model);
convertView.setOnClickListener(new ListenerT(model) {
#Override
public void onClick(View v) {
Log.i("CLICK", "ITEM---" + name);
}
});
return convertView;
}
}
// use your own listener to pass parameter
private class ListenerT implements OnClickListener {
String name;
public ListenerT(String nm) {
name = nm;
}
#Override
public void onClick(View v) {
}
}
private class ViewHolder {
TextView name;
}
}

Override default expandablelistview expand behaviour

How does one go about manually expanding and collapsing an expandablelistview? I know of expandGroup(), but am not sure where to set the onClickListener(), as half of this code, is in a separate library project.
ExpandableDeliveryList
package com.goosesys.dta_pta_test;
[imports removed to save space]
public class ExpandableDeliveryList<T> extends ExpandableListActivity {
private ArrayList<GooseDeliveryItem> parentItems = new ArrayList<GooseDeliveryItem>();
private ArrayList<DeliverySiteExtras> childItems = new ArrayList<DeliverySiteExtras>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// CREATE THE EXPANDABLE LIST AND SET PROPERTIES //
final ExpandableListView expandList = getExpandableListView();
expandList.setDividerHeight(0);
expandList.setGroupIndicator(null);
expandList.setClickable(false);
// LIST OF PARENTS //
setGroupParents();
// CHILDREN //
setChildData();
// CREATE ADAPTER //
GooseExpandableArrayAdapter<?> adapter = new GooseExpandableArrayAdapter<Object>(
R.layout.goose_delivery_item,
R.layout.goose_delivery_item_child,
parentItems,
childItems);
adapter.setInflater((LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE), this);
expandList.setAdapter(adapter);
expandList.setOnChildClickListener(this);
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case android.R.id.home:
{
Intent intent = new Intent(this, Main.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
return true;
}
default:
{
return super.onOptionsItemSelected(item);
}
}
}
public void setGroupParents()
{
DatabaseHelper dbHelper = new DatabaseHelper(this);
List<DeliverySite> sites = new ArrayList<DeliverySite>();
sites = dbHelper.getAllSites();
GooseDeliveryItem[] deliveries = new GooseDeliveryItem[sites.size()];
for(int i=0; i<sites.size(); i++)
{
Delivery del = new Delivery();
try
{
del = dbHelper.getDeliveryByJobNo(sites.get(i).id);
}
catch(Exception e)
{
e.printStackTrace();
}
final GooseDeliveryItem gdi;
if((Double.isNaN(sites.get(i).lat)) || (Double.isNaN(sites.get(i).lng)))
{
gdi = new GooseDeliveryItem(sites.get(i).id, sites.get(i).company);
}
else
{
gdi = new GooseDeliveryItem(sites.get(i).id, sites.get(i).company, sites.get(i).lat, sites.get(i).lng);
}
if(del.getReportedFully() == 1)
{
gdi.isReportedFully = true;
}
deliveries[i] = gdi;
}
// FINALLY ADD THESE ITEMS TO THE PARENT ITEMS LIST ARRAY //
for(GooseDeliveryItem g : deliveries)
parentItems.add(g);
}
public void setChildData()
{
//DatabaseHelper dbHelper = new DatabaseHelper(this);
ArrayList<DeliverySiteExtras> extras = new ArrayList<DeliverySiteExtras>();
for(int i=0; i<parentItems.size(); i++)
{
DeliverySiteExtras dse = new DeliverySiteExtras();
extras.add(dse);
}
childItems = extras;
}
}
ArrayAdapter
package com.goosesys.gooselib.Views;
[imports removed to save space]
public class GooseExpandableArrayAdapter<Object> extends BaseExpandableListAdapter
{
private Activity activity;
private ArrayList<DeliverySiteExtras> childItems;
private LayoutInflater inflater;
ArrayList<GooseDeliveryItem> parentItems;
private DeliverySiteExtras child;
private int layoutId;
private int childLayoutId;
public GooseExpandableArrayAdapter(int layoutId, int childLayoutId, ArrayList<GooseDeliveryItem> parents, ArrayList<DeliverySiteExtras> children)
{
this.layoutId = layoutId;
this.childLayoutId = childLayoutId;
this.parentItems = (ArrayList<GooseDeliveryItem>) parents;
this.childItems = (ArrayList<DeliverySiteExtras>)children;
}
public GooseExpandableArrayAdapter(ArrayList<GooseDeliveryItem> parents, ArrayList<DeliverySiteExtras> children, int layoutId)
{
this.parentItems = parents;
this.childItems = children;
this.layoutId = layoutId;
}
public void setInflater(LayoutInflater inflater, Activity activity)
{
this.inflater = inflater;
this.activity = activity;
}
#Override
public Object getChild(int arg0, int arg1)
{
return null;
}
#Override
public long getChildId(int arg0, int arg1)
{
return 0;
}
/*
* Child view get method
* Utilise this to edit view properties at run time
*/
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
{
child = childItems.get(groupPosition);
if(convertView == null)
{
convertView = inflater.inflate(this.childLayoutId, null);
}
// GET ALL THE OBJECT VIEWS AND SET THEM HERE //
setGeoLocation(groupPosition, convertView);
convertView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
}
});
return convertView;
}
#Override
public void onGroupCollapsed(int groupPosition)
{
super.onGroupCollapsed(groupPosition);
}
#Override
public void onGroupExpanded(int groupPosition)
{
super.onGroupExpanded(groupPosition);
}
#Override
public int getChildrenCount(int groupPosition)
{
return 1; //childItems.get(groupPosition);
}
#Override
public Object getGroup(int groupPosition)
{
return null;
}
#Override
public int getGroupCount()
{
return parentItems.size();
}
#Override
public long getGroupId(int arg0)
{
return 0;
}
/*
* Parent View Object get method
* Utilise this to edit view properties at run time.
*/
#Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)
{
if(convertView == null)
{
convertView = inflater.inflate(this.layoutId, null);
}
// GET ALL OBJECT VIEWS AND SET THEM HERE -- PARENT VIEW //
TextView name = (TextView)convertView.findViewById(R.id.customerName);
name.setText(parentItems.get(groupPosition).customerText);
ImageView go = (ImageView)convertView.findViewById(R.id.moreDetails);
go.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Intent i = new Intent(activity, DeliveryJobActivity.class);
i.putExtra("obj", parentItems.get(groupPosition));
activity.startActivity(i);
}
});
return convertView;
}
#Override
public boolean hasStableIds()
{
return false;
}
#Override
public boolean isChildSelectable(int arg0, int arg1)
{
return false;
}
private void setGeoLocation(final int groupPosition, View parent)
{
GeoLocation geoLocation = new GeoLocation(activity);
final double lat = geoLocation.getLatitude();
final double lng = geoLocation.getLongitude();
// GET OUR START LOCATION //
Location startLocation = new Location("Start");
startLocation.setLatitude(lat);
startLocation.setLongitude(lng);
// GET OUR DESTINATION //
Location destination = new Location("End");
destination.setLatitude(((GooseDeliveryItem)parentItems.get(groupPosition)).latitude);
destination.setLongitude(((GooseDeliveryItem)parentItems.get(groupPosition)).longitude);
double distanceValue = startLocation.distanceTo(destination);
TextView tv = (TextView)parent.findViewById(R.id.extraHeader);
tv.setText(parentItems.get(groupPosition).customerText + " information:");
TextView ds = (TextView)parent.findViewById(R.id.deliveryDistance);
ds.setText("Distance (from location): " + String.valueOf(Math.ceil(distanceValue * GooseConsts.METERS_TO_A_MILE)) + " Mi (approx)");
ImageView img = (ImageView)parent.findViewById(R.id.directionsImage);
img.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// invoke google maps with lat / lng position
Intent navigation = new Intent(Intent.ACTION_VIEW, Uri.parse(
"http://maps.google.com/maps?saddr="
+ (lat) + "," + (lng)
+ "&daddr="
+ ((GooseDeliveryItem)parentItems.get(groupPosition)).latitude + ","
+ ((GooseDeliveryItem)parentItems.get(groupPosition)).longitude
));
activity.startActivity(navigation);
}
});
}
}
Ideally, my bosses would like to have a "+" button, that when clicked expands the listview manually. Rather than clicking anywhere on the view and it doing it automatically. Is this possible? Also, setting setClickable(false) seems to have no effect. Because it'll still expand when any list item is clicked. Am I missing something there also?
Cheers.
You can add an ExpandableListView Group Click Listener ("ExpandableListView::setOnGroupClickListener") to monitor and suppress click event for the ListView Groups. Using your code example, this would be done in your "ExpandableDeliveryList" module after you create the ExpandableListView.
Then in your "+" (and "-") Button click handlers, you can add logic to expand/collapse some or all of the ListView Groups using the "ExpandableListView::expandGroup()" and "ExpandableListView::collapseGroup()" methods.
You do not need to return "false" from the overridden "isChildSelectable()" method as this has no effect on what you are trying to accomplish (and will prevent anyone from clicking/selecting child items in the ListView).
Code examples are shown below:
// CREATE THE EXPANDABLE LIST AND SET PROPERTIES //
final ExpandableListView expandList = getExpandableListView();
//...
expandList.setOnGroupClickListener(new android.widget.ExpandableListView.OnGroupClickListener() {
#Override
public boolean onGroupClick( ExpandableListView parent,
View view,
int groupPosition,
long id) {
// some code...
// return "true" to consume the event (and prevent the Group from expanding/collapsing) / "false" to allow the Group to expand/collapse normally
return true;
}
});
To manually expand and collapse the ListView Groups:
// enumerate thru the ExpandableListView Groups
// [in this code example, a single index is used...]
int groupPosition = 0;
// expand the ListView Group/s
if (m_expandableListView.isGroupExpanded(groupPosition) == false) {
// API Level 14+ allows you to animate the Group expansion...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
m_expandableListView.expandGroup(groupPosition, true);
}
// else just expand the Group without animation
else {
m_expandableListView.expandGroup(groupPosition);
}
}
// collapse the ListView Group/s
else {
m_expandableListView.collapseGroup(groupPosition);
}
Hope this Helps.

Buttons displaying download progress (from background thread) get mixed up when scrolling in Android

I have a bug that I think is due to the way that lists reuse objects. I have a list of download buttons that get a progress readout when downloading. The update code is in a background thread.
When I scroll the list, the buttons that are showing progress jump into other list elements. How can I stop this? It's difficult to visualize, so I made a video of it:
http://www.youtube.com/watch?v=EiT2YWb2Prs&feature=youtu.be
BTW, the video was made by my client, so disregard the "samsung bug" bit. I'm the developer...
Here is the code:
public class VideosActivity extends Activity {
ListView video_list;
CustomList2 adapter;
File storage_dir;
String s3_bucket = "xx";
String s3_dir = "android/vol1/"; //the directory after the boucket that the files are stored in (do not add first slash)
Handler handler = new Handler(); //'tunnel' through whci other threads communicate with main thread
ArrayList<String> arr_videos = new ArrayList<String>();
ArrayList<String> arr_sdcardvideos = new ArrayList<String>();
int images[] = {R.drawable.kr115,R.drawable.kr200,R.drawable.kr201,R.drawable.kr202,R.drawable.kr203,R.drawable.kr205,R.drawable.kr206,R.drawable.kr207,R.drawable.kr208,R.drawable.kr209,R.drawable.kr210,R.drawable.kr211,R.drawable.kr212,R.drawable.kr213,R.drawable.kr213,R.drawable.kr214,R.drawable.kr215,R.drawable.kr216,R.drawable.kr210,R.drawable.kr211,R.drawable.kr212,R.drawable.kr213};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
storage_dir = getApplicationContext().getExternalFilesDir(null); //private to app, removed with uninstall
adapter = new CustomList2(this, R.layout.customlist, arr_videos);
video_list = (ListView)findViewById(R.id.list);
video_list.setAdapter(adapter); //set adapter that specifies list contents
ensureStorageDirExists( storage_dir ); //make sure storage dir exists
set_sdcard_video_data(); //store vids arleady on card
set_video_data(); //store vid dat in array
if(!have_connection())
{
Toast.makeText(this, "No Internet connection", Toast.LENGTH_LONG).show();
return;
}
}
protected void ensureStorageDirExists( File dir )
{
if (!dir.exists())
{
dir.mkdirs();
}
}
public void set_sdcard_video_data()
{
arr_sdcardvideos.clear();
for(File f:storage_dir.listFiles())
{
arr_sdcardvideos.add( f.getName() );
}
}
public void set_video_data()
{
arr_videos.add("02Posture_and_Walk.m4v");
arr_videos.add("03Embrace_Connection_and_Musicality.m4v");
arr_videos.add("04Left_Turning_Check_Step.m4v");
arr_videos.add("05Basic_Right_Turn.m4v");
arr_videos.add("06Ocho_Cortado.m4v");
arr_videos.add("07Media_Vuelta.m4v");
arr_videos.add("08The_Cross.m4v");
arr_videos.add("09Front_Ochos.m4v");
arr_videos.add("10The_Cross_in_Cross_System.m4v");
arr_videos.add("11Back_Ochos.m4v");
arr_videos.add("12Molinete_Giro.m4v");
arr_videos.add("13Right_Turn.m4v");
arr_videos.add("14Combining_All_the_Elements_1.m4v");
arr_videos.add("15Combining_All_the_Elements_2.m4v");
arr_videos.add("16Combining_All_the_Elements_3.m4v");
arr_videos.add("17Combining_All_the_Elements_4.m4v");
arr_videos.add("18Combining_All_the_Elements_5.m4v");
arr_videos.add("19Combining_All_the_Elements_6.m4v");
arr_videos.add("20Demo_Using_All_the_Elements.m4v");
arr_videos.add("36Etiquette.m4v");
}
public SharedPreferences stored_vals()
{
return PreferenceManager.getDefaultSharedPreferences(this);
}
public boolean have_connection()
{
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm.getActiveNetworkInfo()!=null && cm.getActiveNetworkInfo().isConnected() && cm.getActiveNetworkInfo().isAvailable())
{
return true;
}
else
{
return false;
}
}
public void download_video(int position, View btn)
{
}
public class CustomList2 extends ArrayAdapter<String>
{
View view;
int position;
Button btn;
public CustomList2(Context context, int layout_id, ArrayList<String> objects)
{
super(context, layout_id, objects);
}
#Override
public View getView(final int position, View convertView, ViewGroup view_group)
{
set_view(convertView);
this.position = position;
TextView text_view = (TextView) view.findViewById(R.id.name);
ImageView image = (ImageView) view.findViewById(R.id.img);
btn = (Button) view.findViewById(R.id.play);
prepare_btn();
text_view.setText( list_text() );
image.setImageResource(images[position]);
return view;
}
public String list_text()
{
String s = arr_videos.get( position ).replace("_", " ").replace(".m4v", "");
s = s.substring(2, s.length());
return s;
}
public void set_view(View convertView)
{
if(convertView == null)
{
LayoutInflater inflater = getLayoutInflater();
view = inflater.inflate(R.layout.customlist, null);
}
else
{
view = convertView;
}
}
public Boolean is_downloaded()
{
return arr_sdcardvideos.contains(arr_videos.get(position));
}
public void prepare_btn()
{
btn.setTag((Integer) position);
if(is_downloaded() == true)
{
btn.setText("Play ");
btn.setEnabled(true);
btn.setOnClickListener( new OnClickListener()
{
public void onClick(View btn)
{
int position = (Integer) btn.getTag();
Intent i = new Intent(VideosActivity.this, PlayVideoActivity.class);
String video_path = storage_dir + "/" + arr_videos.get(position);
Log.v("video_path", video_path);
i.putExtra("video_path", video_path);
startActivity(i);
}
});
}
else
{
btn.setText("Download ");
btn.setOnClickListener( new OnClickListener()
{
public void onClick(View btn)
{
int position = (Integer) btn.getTag();
btn.setEnabled(false);
//download_video( position, btn );
Download d = new Download();
d.start(position, (Button) btn);
}
});
}
}
}
public class Download
{
File new_video_file;
Button btn; //the progress meter needs to know what button called this. set via setter method below.
int position;
com.amazonaws.services.s3.transfer.Download download;
protected void start(int position, Button btn)
{
this.btn = (Button) btn;
this.position = position;
this.new_video_file = new File(storage_dir, arr_videos.get(position)); //local file to be writtent to
AWSCredentials credentials = new BasicAWSCredentials("xx", "xx" );
TransferManager tx = new TransferManager(credentials);
this.download = tx.download(s3_bucket, s3_dir + arr_videos.get(position), new_video_file);
download.addProgressListener(new ProgressListener()
{
public void progressChanged(final ProgressEvent pe)
{
handler.post( new Runnable()
{
#Override
public void run()
{
if ( pe.getEventCode() == ProgressEvent.COMPLETED_EVENT_CODE )
{
Download.this.onComplete();
}
else
{
Download.this.onProgressUpdate();
}
}
});
}
});
}
//protected void onProgressUpdate(Double progress)
protected void onProgressUpdate()
{
Double progress = this.download.getProgress().getPercentTransfered();
String percent = progress.intValue() + "%";
Log.v("runnable", percent);
btn.setText(percent);
Log.v("dev", progress + "");
}
protected void onComplete()
{
Log.v("dev", "download complete!!!");
set_sdcard_video_data();
adapter.notifyDataSetChanged();
// this.download.abort();
}
}
}
Your Download Thread keeps a reference to the Button. The Buttons get reused though for different list elements when you scroll. You need to find a way to update the Button in the Thread somehow. The Button in the Thread can also be null, when the list element is not visible.
Edit:
It's really not that complicated. First of all: you should use a ViewHolder, that's gonna make your life much easier. Then you could do something like that
#Override
public View getView(final int position, View convertView, ViewGroup view_group) {
View view = null;
ViewHolder holder = null;
if(convertView == null){
view = {inflate view}
view.setTag(holder = new ViewHolder());
holder.view1 = view.findViewById(...);
{get rest of the views}
}else{
view = convertView;
holder = (ViewHolder)view.getTag();
}
if(holder.getDownloadThread() != null){
holder.getDownloadThread().setButton(null);
}
...
}
You get the idea.

Categories

Resources