I read the article about "Making ListView Scrolling Smooth" on android.developer.com but there is one thing I don't understand : where to put or get the value of "position" because my eclipse says :"Cannot refer to a non-final variable position inside an inner class defined in a different method".
I put this code in my adapter class in the getView method.
package com.example.filemanager;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Formatter.BigDecimalLayoutForm;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.DateSorter;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
public class ItemAdapter extends ArrayAdapter<Item> {
private final Context context;
private final ArrayList<Item> values;
public int position;
public ItemAdapter(Context context, ArrayList<Item> values) {
super(context, R.layout.item, values);
this.context = context;
this.values = values;
}
#Override
public Item getItem(int position) {
// TODO Auto-generated method stub
return super.getItem(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.item, parent, false);
TextView title = (TextView) rowView.findViewById(R.id.title);
TextView info = (TextView) rowView.findViewById(R.id.info);
ImageView icon = (ImageView) rowView.findViewById(R.id.icon);
ImageView menu = (ImageView) rowView.findViewById(R.id.menu);
title.setText(values.get(position).getName());
info.setText(sizeString(position) + " " + dateString(position) + " "
+ rightsString(position));
if (values.get(position).isisDir()) {
icon.setImageResource(R.drawable.dir);
} else if (!values.get(position).isisDir()) {
if (values.get(position).getPath().endsWith(".jpg")
|| values.get(position).getPath().endsWith(".png")) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 50;
options.inDensity = 100;
options.inScreenDensity = 1;
Bitmap myBitmap = BitmapFactory.decodeFile(values.get(position).getPath(), options);
icon.setImageBitmap(myBitmap);
}else{
icon.setImageResource(R.drawable.file);
}
}
menu.setImageResource(R.drawable.menu);
ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
holder.menu = (ImageView) convertView.findViewById(R.id.menu);
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.info = (TextView) convertView.findViewById(R.id.info);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progressSpinner);
convertView.setTag(holder);
// Using an AsyncTask to load the slow images in a background thread
new AsyncTask<ViewHolder, Void, Bitmap>() {
private ViewHolder v;
#Override
protected Bitmap doInBackground(ViewHolder... params) {
v = params[0];
//return mFakeImageLoader.getImage();
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (v.position == position) {
// If this item hasn't been recycled already, hide the
// progress and set and show the image
v.progress.setVisibility(View.GONE);
v.icon.setVisibility(View.VISIBLE);
v.icon.setImageBitmap(result);
}
}
}.execute(holder);
return rowView;
}
private String rightsString(int position) {
String temp = "";
if (values.get(position).isReadable()) {
temp += "r";
} else {
temp += "-";
}
if (values.get(position).isWritable()) {
temp += "w";
} else {
temp += "-";
}
if (values.get(position).isExecutable()) {
temp += "x";
} else {
temp += "-";
}
return temp;
}
private String dateString(int position) {
DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
return df.format(values.get(position).getDate());
}
private String sizeString(int position) {
long bytes = values.get(position).getSize();
double kb = bytes / 1024.0;
double mb = kb / 1024.0;
double gb = mb / 1024.0;
if (gb >= 1) {
return gb + " GB";
}
if (mb >= 1) {
return mb + " MB";
}
if (kb >= 1) {
return kb + " KB";
} else {
return bytes + " bytes";
}
}
static class ViewHolder {
ImageView icon, menu;
TextView title, info;
ProgressBar progress;
int position;
}
}
Okay, so you need to understand a little bit about outer,inner and anonymous classes,etc. What's going on is that you are creating an anonymous class with the declaration of
new AsyncTask()....
and any variables inside of that class need to be final or not referencing the parent class.
So, what you need to do is this:
final int finalPosition = position;
// Using an AsyncTask to load the slow images in a background thread
new AsyncTask() {
private ViewHolder v;
#Override
protected Bitmap doInBackground(ViewHolder... params) {
v = params[0];
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (v.position == finalPosition) {
// If this item hasn't been recycled already, hide the
// progress and set and show the image
v.progress.setVisibility(View.GONE);
v.icon.setVisibility(View.VISIBLE);
v.icon.setImageBitmap(result);
}
}
}.execute(holder);
Reference
Related
i have a custom listview and custom adapter. each row has multiple items inside it, when i click on like button it change the color of imageview but it also effect the 4th,7th and 10th row.
after searching on internet i learned that i have to use getTag and setTag but i dont know how to use it.
please help me in understanding the concept of getTag and setTag and solving this error.
here is my code:-
package rj.osmthemes;
import java.util.ArrayList;
import android.content.Context;
import android.os.Build;
import android.provider.ContactsContract;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import static android.R.attr.data;
import static rj.osmthemes.R.id.downlink;
import static rj.osmthemes.R.id.likebtn;
import static rj.osmthemes.R.id.likecount;
public class ListAdapter extends ArrayAdapter<DataModel> {
customButtonListener customListner;
private ArrayList<DataModel> dataSet;
public String temp1;
public interface customButtonListener {
public void onButtonClickListner(int position,String value);
public void onImageClickListner(int position,String value);
public void onlikeImageClickListner(int position,String value);
public void ondislikeImageClickListner(int position,String value);
}
public void setCustomButtonListner(customButtonListener listener) {
this.customListner = listener;
}
private Context context;
//private ArrayList<String> data = new ArrayList<String>();
public ListAdapter(ArrayList<DataModel> data, Context context) {
super(context, R.layout.list_layout, data);
this.dataSet = data;
this.context = context;
}
private int lastPosition = -1;
// public ListAdapter(Context context, ArrayList<String> dataItem) {
// super(context, R.layout.list_layout, dataItem);
// this.data = dataItem;
// this.context = context;
// }
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
final DataModel dataModel = getItem(position);
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.list_layout, null);
viewHolder = new ViewHolder();
viewHolder.themename = (TextView) convertView.findViewById(R.id.themename);
viewHolder.madeby = (TextView) convertView.findViewById(R.id.madeby);
viewHolder.downcount = (TextView) convertView.findViewById(R.id.downcount);
viewHolder.likecount = (TextView) convertView.findViewById(likecount);
viewHolder.dislikecount = (TextView) convertView.findViewById(R.id.dislikecount);
viewHolder.ss1 = (ImageView) convertView.findViewById(R.id.img1);
viewHolder.ss2 = (ImageView) convertView.findViewById(R.id.img2);
viewHolder.ss3 = (ImageView) convertView.findViewById(R.id.img3);
viewHolder.likebtn = (ImageView) convertView.findViewById(likebtn);
viewHolder.dislikebtn = (ImageView) convertView.findViewById(R.id.dislikebtn);
viewHolder.btndownload = (Button) convertView.findViewById(downlink);
convertView.setTag(viewHolder);
final String temp = getItem(position).toString();
viewHolder.likebtn.setTag(temp);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
lastPosition = position;
//final String temp = getItem(position).toString();
// viewHolder.tempid = Integer.parseInt(dataModel.getId());
final String ss1link,ss2link,ss3link,downlink;
viewHolder.themename.setText(dataModel.getTheme_name());
viewHolder.madeby.setText(dataModel.getMade_by());
viewHolder.downcount.setText(dataModel.getDown_count());
viewHolder.likecount.setText(dataModel.getLike_count());
viewHolder.dislikecount.setText(dataModel.getDislike_count());
ss1link = dataModel.getSs1();
ss2link = dataModel.getSs2();
ss3link = dataModel.getSs3();
downlink = dataModel.getDown_link();
// viewHolder.text.setText(temp);
viewHolder.btndownload.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
int downcounttmp = Integer.parseInt(dataModel.getDown_count());
downcounttmp++;
viewHolder.downcount.setText(""+downcounttmp);
String name = downlink + "#" + dataModel.getTheme_name() + "#" + dataModel.getId() + "#" + downcounttmp;
customListner.onButtonClickListner(position,name);
}
}
});
viewHolder.ss1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
customListner.onImageClickListner(position,ss1link);
}
}
});
viewHolder.ss2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
customListner.onImageClickListner(position,ss2link);
}
}
});
viewHolder.ss3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
customListner.onImageClickListner(position,ss3link);
}
}
});
viewHolder.likebtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
// Toast.makeText(context, dataModel.getId() + " { " ,Toast.LENGTH_LONG).show();
if(viewHolder.check == 0){
int likecount = Integer.parseInt(dataModel.getLike_count());
likecount++;
viewHolder.likecount.setText(""+likecount);
String name = likecount + "#" + dataModel.getId();
// Toast.makeText(context,position + " " + temp,Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
viewHolder.likebtn.setImageResource(R.drawable.ic_thumb_up_red_24dp);
//viewHolder.likebtn.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_thumb_up_red_24dp, getContext().getTheme()));
viewHolder.check = 1;
} else {
viewHolder.likebtn.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_thumb_up_red_24dp));
viewHolder.check = 1;
}
customListner.onlikeImageClickListner(position,name);
}
else {
Toast.makeText(context,"You cant use this action",Toast.LENGTH_LONG).show();
}
}
}
});
viewHolder.dislikebtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
if(viewHolder.check == 0) {
int dislikecount = Integer.parseInt(dataModel.getDislike_count());
dislikecount++;
viewHolder.dislikecount.setText(""+dislikecount);
String name = dislikecount + "#" + dataModel.getId();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
viewHolder.dislikebtn.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_thumb_down_red_24dp, getContext().getTheme()));
viewHolder.check = 1;
} else {
viewHolder.dislikebtn.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_thumb_down_red_24dp));
viewHolder.check = 1;
}
customListner.ondislikeImageClickListner(position,name);
}
else {
Toast.makeText(context,"You cant use this action",Toast.LENGTH_LONG).show();
}
}
}
});
Glide
.with(context)
.load(ss1link)
.into(viewHolder.ss1);
Glide
.with(context)
.load(ss2link)
.into(viewHolder.ss2);
Glide
.with(context)
.load(ss3link)
.into(viewHolder.ss3);
return convertView;
}
public class ViewHolder {
TextView themename,madeby,downcount,likecount,dislikecount;
Button btndownload;
ImageView ss1,ss2,ss3,likebtn,dislikebtn;
int check = 0, tempid = 0;
}
}
This is because of object reuse in your list view.
You can manage separate ArrayList or HashMap to maintain your likes.
And based on that you should update in your getView like this,
if([already selected]) {
viewHolder.likebtn.setBackground([your selected drawable]);
} else {
viewHolder.likebtn.setBackground([your non selected drawable]);
}
I am using list view with each and every row has its own timer.I want to delete the position of a list view when timer is completed its time interval.I had implemented as below but position is always catching wrongly and last item is deleting every time.Please see my code below,inside onfinish() of timer i am trying to remove the position but it is not getting deleted properly, help me.
ProductListAdapter.java
package com.devpoint.adapter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.w3c.dom.Document;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.CountDownTimer;
import android.os.Handler;
import android.text.Html;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TableLayout;
import android.widget.TextView;
import com.devpoint.PlacesandMaps.GMapV2Direction;
import com.devpoint.PlacesandMaps.PlacesMapActivity;
import com.devpoint.common.GetAllGooglePlaces;
import com.devpoint.model.ListDetails;
import com.devpoint.rprtgnet.LoadActivity;
import com.devpoint.rprtgnet.MapFragmentActivity;
import com.devpoint.rprtgnet.R;
import com.devpoint.sharedpreferences.SharedPreference;
import com.devpoint.tabsswipe.ListOnGoing;
import com.devpoint.tabsswipe.SwipeViewPagerAdapter;
import com.devpoint.user.PostLogcatErrors;
import com.devpoint.volley.AppController;
import com.google.android.gms.maps.GoogleMap;
import com.squareup.picasso.Picasso;
import android.view.animation.Transformation;
#SuppressLint({ "InflateParams", "ShowToast" })
public class ProductListAdapter extends ArrayAdapter<ListDetails> {
private Activity context;
List<ListDetails> products;
SharedPreference sharedPreference;
public static com.android.volley.toolbox.ImageLoader imageLoader;
LayoutInflater inflater;
//ViewHolder holder;
protected String Day = "";
public static View alertLayout;
private static GMapV2Direction gmapdirection;
public static GoogleMap gmap;
protected Document doc;
static final int ANIMATION_DURATION = 200;
//TextView timer;
//String Pagename;
private HashMap<TextView,CountDownTimer> counters;
static class TestViewHolder
{
public TextView tvCounter;
}
public ProductListAdapter(Context context, List<ListDetails> products) {
super(context, R.layout.adapter_offer_list_item, products);
this.context = (Activity) context;
this.products = products;
sharedPreference = new SharedPreference();
imageLoader = AppController.getInstance().getImageLoader();
this.counters = new HashMap<TextView, CountDownTimer>();
inflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
}
private class ViewHolder {
TextView productNameTxt;
//TextView Ratingsno;
TextView productPriceTxt;
//TextView timedist;
TableLayout distancesection;
TextView categoryname;
ImageView favoriteImg;
RatingBar rb;
ImageView OfferImage;
//ImageView MapImage;
ImageView listimage;
public TextView distance;
public ImageView indicator;
TextView timer;
TextView move;
//TextView Postedon;
}
#Override
public int getCount() {
return products.size();
}
#Override
public ListDetails getItem(int position) {
return products.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int po, View convertView, final ViewGroup parent) {
try {
ViewHolder holder = null;
Day = "";
final ListDetails product = products.get(po);
//final int abc = po;
/*LayoutInflater li = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);*/
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.offerlist_new, parent,
false);
final View v= convertView;
// convertView.requestLayout();
holder.productNameTxt = (TextView) convertView
.findViewById(R.id.name);
holder.productPriceTxt = (TextView) convertView
.findViewById(R.id.listview_description);
holder.distance = (TextView) convertView
.findViewById(R.id.listview_distane);
/*holder.timedist = (TextView) convertView
.findViewById(R.id.timedist);*/
/*holder.Ratingsno = (TextView) convertView
.findViewById(R.id.Ratingsno);*/
/*holder.Postedon = (TextView) convertView
.findViewById(R.id.Postedon);*/
holder.favoriteImg = (ImageView) convertView
.findViewById(R.id.fav_checkbox);
holder.rb = (RatingBar) convertView
.findViewById(R.id.ratingbar);
holder.timer = (TextView) convertView.findViewById(R.id.time);
holder.categoryname = (TextView) convertView
.findViewById(R.id.Categoryname);
holder.listimage = (ImageView) convertView
.findViewById(R.id.list_image);
/*holder.distancesection = (TableLayout) convertView
.findViewById(R.id.distancesection);*/
/*holder.MapImage = (ImageView) convertView
.findViewById(R.id.imgmap);*/
holder.move = (TextView) convertView
.findViewById(R.id.listview_description3);
holder.move.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
removeListItem(v,po) ;
} catch (Exception e) {
e.printStackTrace();
PostLogcatErrors ple = new PostLogcatErrors();
ple.PostLogcatErorrs(e);
}
}
});
String text = "<font color=#222222>" + product.getShopName()
+ "</font>"
+ "<small><font color=#0091EA> ( </font></small>"
+ " <small><font color=#0091EA>" + product.getAreaName()
+ "</font></small>"
+ "<small><font color=#0091EA> ) </font></small>";
holder.productNameTxt.setText(Html.fromHtml(text));
// holder.productNameTxt.setText(product.getShopName() + " " + "( "
// + Html.fromHtml("<font color='#0091EA'>" + product.getAreaName()
// + "</font>") + " )");
holder.productPriceTxt.setText(product.getDeal() + "");
holder.rb.setRating(Float.valueOf(product.getRatingAvg()));
//holder.Ratingsno.setText(product.getTotalRatings() + " Ratings");
//holder.timedist.setText(product.getTime());
holder.distance.setText(String.valueOf(product.getDistance())
+ " Km");
holder.categoryname.setText(product.getCategoryName());
//holder.listimage.setImageUrl(product.getListImage(), imageLoader);
Picasso.with(context).load(product.getListImage()).into(holder.listimage);
if (checkFavoriteItem(product)) {
holder.favoriteImg.setImageResource(R.drawable.checked);
holder.favoriteImg.setTag(context
.getString(R.string.red_favcolor));
} else {
holder.favoriteImg.setImageResource(R.drawable.unchecked);
holder.favoriteImg.setTag(context
.getString(R.string.grey_favcolor));
}
/*holder.Postedon.setText("Posted On" + " "
+ product.getPostedDate());*/
final TextView tv = holder.timer;
CountDownTimer cdt = counters.get(tv);
if(cdt!=null)
{
cdt.cancel();
cdt=null;
}
cdt = new CountDownTimer(Long.parseLong(product.getOfferEndTime()), 1000)
{
#Override
public void onTick(long millisUntilFinished)
{
int minutes = 0;
int seconds = 0;
String sDate = "";
if(millisUntilFinished > DateUtils.MINUTE_IN_MILLIS)
{
minutes = (int) (millisUntilFinished / DateUtils.MINUTE_IN_MILLIS);
}
millisUntilFinished -= (minutes*DateUtils.MINUTE_IN_MILLIS);
if(millisUntilFinished > DateUtils.SECOND_IN_MILLIS)
{
seconds = (int) (millisUntilFinished / DateUtils.SECOND_IN_MILLIS);
}
sDate += " "+"00"+":"+String.format("%02d",minutes)+":"+String.format("%02d",seconds);
tv.setText(sDate.trim());
}
#Override
public void onFinish() {
tv.setText("Finished");
final int abc = po;
final Animation animation = AnimationUtils.loadAnimation(
context, android.R.anim.slide_in_left);
v.startAnimation(animation);
Handler handle = new Handler();
handle.postDelayed(new Runnable() {
public void run() {
products.remove(abc);
ListOnGoing.productListAdapter = new ProductListAdapter(
LoadActivity.activity, products);
ListOnGoing.swipelisview
.setAdapter(ListOnGoing.productListAdapter);
ListOnGoing.productListAdapter.notifyDataSetChanged();
}
}, 1000);
}
};
counters.put(tv, cdt);
cdt.start();
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
} catch (Exception e) {
e.printStackTrace();
PostLogcatErrors ple = new PostLogcatErrors();
ple.PostLogcatErorrs(e);
}
return convertView;
}
/* Checks whether a particular product exists in SharedPreferences */
public boolean checkFavoriteItem(ListDetails checkProduct) {
boolean check = false;
List<ListDetails> favorites = sharedPreference.getFavorites(context);
if (favorites != null) {
for (ListDetails product : favorites) {
/*
* if (product.equals(checkProduct)) { check = true; break; }
*/
if (product.getOfferID().equals(checkProduct.getOfferID())) {
check = true;
break;
}
}
}
return check;
}
public void cancelAllTimers()
{
Set<Entry<TextView, CountDownTimer>> s = counters.entrySet();
Iterator it = s.iterator();
while(it.hasNext())
{
try
{
Map.Entry pairs = (Map.Entry)it.next();
CountDownTimer cdt = (CountDownTimer)pairs.getValue();
cdt.cancel();
cdt = null;
}
catch(Exception e){}
}
it=null;
s=null;
counters.clear();
}
}
If abc is declared as a field of your class (e. g. private int abc), you are assigning po to abc each time getView gets called. Later, when you call
products.remove(abc);
You are removing an element with index of the last assigned value of abc, which most probably is index of the last element.
Replace the above line with
products.remove(po);
or change
abc = po;
to
final int abc = po;
Also try doing a similar thing with the following line:
holder = null;
I have created a custom Adapter for list which different items and each item has a button to invite. The item should flip horizontally when the respective invite button is clicked and that is working fine. The problem is that when I click invite button of first item then invite button of 4th item is also clicked. I am attaching the code hee
package rovoltlabs.coffeechat.adapters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import rovoltlabs.coffeechat.R;
import rovoltlabs.coffeechat.animation.AnimationFactory;
import rovoltlabs.coffeechat.animation.AnimationFactory.FlipDirection;
import rovoltlabs.coffeechat.volley.utils.Const;
import rovoltslabs.coffeechat.app.AppController;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewAnimator;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.StringRequest;
public class MyCustomAdapter extends BaseAdapter implements OnClickListener {
Context contexts;
List<String> name = new ArrayList<String>();
List<String> ids = new ArrayList<String>();
List<String> slots = new ArrayList<String>();
List<String> heading = new ArrayList<String>();
List<String> showtime = new ArrayList<String>();
List<Bitmap> img = new ArrayList<Bitmap>();
List<ViewHolder> myview = new ArrayList<ViewHolder>();
private String tag_json_obj = "jobj_req";
private LayoutInflater mLayoutInflater;
View row;
ViewHolder holder;
public MyCustomAdapter(Context context, List<String> name,
List<Bitmap> img, List<String> heading, List<String> slots,
List<String> id) {
super();
this.contexts = context;
this.name = name;
this.img = img;
this.heading = heading;
this.slots = slots;
this.ids = id;
mLayoutInflater = ((Activity) contexts).getLayoutInflater();
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return name.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
// TODO Auto-generated method stub
// check to see if the reused view is null or not, if is not null then
// reuse it
if (view == null) {
holder = new ViewHolder();
view = mLayoutInflater.inflate(R.layout.item, null);
holder.name = (TextView) view.findViewById(R.id.Name);
holder.fname = (TextView) view.findViewById(R.id.flipName);
holder.msg = (EditText) view.findViewById(R.id.fsend);
holder.heading = (TextView) view.findViewById(R.id.ddheading);
holder.distance = (TextView) view.findViewById(R.id.Distance);
holder.image = (ImageView) view.findViewById(R.id.imagecoffee);
holder.invite = (Button) view.findViewById(R.id.inviteButton);
holder.send = (Button) view.findViewById(R.id.fsendButton);
holder.time = (TextView) view.findViewById(R.id.timefree);
holder.viewAnimator = (ViewAnimator) view
.findViewById(R.id.viewFlipper);
myview.add(holder);
holder.v = view;
} else {
holder = (ViewHolder) view.getTag();
}
view.setTag(holder);
holder.invite.setOnClickListener(this);
holder.send.setOnClickListener(this);
holder.name.setText(name.get(position).split("\n")[0]);
holder.fname.setText(name.get(position).split("\n")[0]);
holder.heading.setText(heading.get(position));
String temp = "";
int sl = Integer.parseInt(slots.get(position));
if (sl % 2 == 0) {
temp = "" + ((sl / 2) - 1) + ":30 - " + ((sl / 2)) + ":00";
} else {
temp = "" + ((sl / 2)) + ":00-" + ((sl / 2)) + ":30";
}
holder.time.setText(temp);
holder.distance.setText(name.get(position).split("\n")[1] + " m");
holder.image.setImageBitmap(img.get(position));
holder.invite.setTag(position);
holder.send.setTag(position);
return view;
}
private static class ViewHolder {
protected TextView name;
protected TextView heading;
protected TextView distance, time;
protected ImageView image;
protected Button invite, send;
protected View v;
protected ViewAnimator viewAnimator;
protected TextView fname;
protected EditText msg;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (v.getId() == R.id.inviteButton) {
AnimationFactory.flipTransition(
myview.get((Integer) v.getTag()).viewAnimator,
FlipDirection.LEFT_RIGHT);
} else if (v.getId() == R.id.fsend) {
SharedPreferences pref = contexts.getApplicationContext()
.getSharedPreferences("MyPref", 0);
String slotsss = "{\"slots\":[" + slots.get((Integer) v.getTag())
+ "]}";
final Map<String, String> params = new HashMap<String, String>();
params.put("slot", slotsss);
Log.e("invite slots", slotsss);
params.put("to", ids.get((Integer) v.getTag()));
params.put("from", pref.getString("id", "N/A"));
params.put("message", myview.get((Integer) v.getTag()).msg
.getText().toString());
StringRequest jsonObjReq = new StringRequest(Method.POST,
Const.URL_INVITE, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("Slots Response: ", response.toString());
Toast.makeText(contexts, "invited" + response,
Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d("invite Error:",
"Error: " + error.getMessage());
}
}) {
/**
* Passing some request headers
* */
#Override
protected Map<String, String> getParams() {
return params;
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq,
tag_json_obj);
}
}
}
The View objects are recycling and you're using the same ViewHolder object (and other UI components) for both positions. The view being clicked has had its tag updated to the position desired, but the animation object is the same as another position due to the recycling.
I have developed and launched an Android application. It works fine on my Android phone, but it crashes on several devices.
*BugSense gives me the following error:*
0 java.lang.NullPointerException
1 at android.widget.ArrayAdapter.init(ArrayAdapter.java:310)
2 at android.widget.ArrayAdapter.(ArrayAdapter.java:128)
3 **at com.challenger.app.ChallengeAdapter.(ChallengeAdapter.java:27)**
4 at com.challenger.app.AllChallenges.fitChallenges(AllChallenges.java:142)
5 at com.challenger.app.AllChallenges$1.onSuccess(AllChallenges.java:108)
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;
public class AllChallenges extends Fragment {
Button loginButton;
ListView listView2, listView1;
TextView textView;
int category = 0;
View view;
List<Challenge> challenge_data;
public AllChallenges(int cat) {
category = cat;
}
public AllChallenges() {
// TODO Auto-generated constructor stub
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
if(getActivity()!=null){
load();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
view = inflater.inflate(R.layout.allchallenges, container, false);
if(getActivity()!=null){
load();
}
return view;
}
public void load() {
loadOld();
if (!AppSettings.refreshed[category + 1]) {
update();
}
}
public void loadOld() {
Log.d("Challenge", "Updating " + category);
JSONArray a = AppSettings.loadChallenges(category, getActivity());
if (a != null) {
fitChallenges(makeArray(a));
}
}
public void update() {
Log.d("Challenge", "getChallenges/" + category);
RequestParams a = new RequestParams();
if (AppSettings.logged) {
a.put("fb_id", AppSettings.facebookId);
a.put("fb_authkey", AppSettings.facebookAuthToken);
}
NetworkClient.receiveJSON("getChallenges/" + category, a,
new JsonHttpResponseHandler() {
#Override
public void onSuccess(JSONArray chalList) {
Log.d("Challenge", "Downloaded " + category);
AppSettings.saveChallenges(category, chalList,
getActivity());
fitChallenges(makeArray(chalList));
AppSettings.refreshed[category + 1] = true;
}
});
}
public Challenge[] makeArray(JSONArray list) {
challenge_data = new ArrayList<Challenge>();
try {
for (int i = 0; i < list.length(); i++) {
JSONObject chal = (JSONObject) list.get(i);
String[] arr = {};
if (chal.has("friends"))
arr = JSONArrToArr(chal.getJSONArray("friends"));
Log.e("Boolean", chal.getString("active"));
challenge_data.add(new Challenge(chal.getInt("id"), chal
.getString("title"), chal.getInt("category"), chal
.getInt("taken_by"), arr, chal.getBoolean("active"),
chal.getString("text"), chal.getInt("streak"), chal
.getInt("percentage")));
}
return challenge_data.toArray(new Challenge[challenge_data.size()]);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public void fitChallenges(Challenge[] chalArray) {
**ChallengeAdapter adapter = new ChallengeAdapter(getActivity(),
R.layout.list_row, chalArray);** //
listView1 = (ListView) view.findViewById(R.id.listView1);
listView1.setAdapter(adapter);
OnItemClickListener listener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Log.i("listener", "am ID" + id + "position " + position);
int n = (int) id;
String title = challenge_data.get(n).toStringArray()[1];
Log.i("listener", "am ID" + id + "position " + position
+ " title " + title);
int people = challenge_data.get(n).peopleInt;
String category = challenge_data.get(n).toStringArray()[0];
String description = challenge_data.get(n).toStringArray()[5];
int streak = challenge_data.get(n).streak;
int percentage = challenge_data.get(n).percentage;
int chal_id = challenge_data.get(n).id;
boolean active = challenge_data.get(n).active;
((AllChallengesPager) getActivity()).showDetailed(chal_id,
title, "" + people, category, active, description, ""
+ streak, "" + percentage);
}
};
listView1.setOnItemClickListener(listener);
}
public String[] JSONArrToArr(JSONArray arr) {
String[] newArr = {};
try {
List<String> list = new ArrayList<String>();
for (int i = 0; i < arr.length(); i++) {
list.add(arr.getString(i));
}
newArr = list.toArray(new String[list.size()]);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newArr;
}}
public class ChallengeAdapter extends ArrayAdapter<Challenge> {
Context context;
int layoutResourceId;
Challenge data[] = null;
Typeface a;
public ChallengeAdapter(Context context, int layoutResourceId,
Challenge[] data) {
**super(context, layoutResourceId, data);** //in this line code crashes
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
a = Typeface.createFromAsset(context.getAssets(),
"fonts/roboto_condensed.ttf");
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ChallengeHolder holder = null;
Challenge challenge = data[position];
if (row == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ChallengeHolder();
holder.imgIcon = (ImageView) row.findViewById(R.id.list_image);
holder.txtTitle = (TextView) row.findViewById(R.id.challenge);
holder.txtPeople = (TextView) row.findViewById(R.id.peopleNumber);
holder.friendThumbs = (LinearLayout) row
.findViewById(R.id.friendThumbs);
row.setTag(holder);
} else {
holder = (ChallengeHolder) row.getTag();
}
holder.friendThumbs.removeAllViews();
for (int i = 0; i < challenge.friendIds.length; i++) {
holder.friendThumbs.addView(createIcon(challenge.friendIds[i],
context));
}
holder.txtTitle.setText(challenge.title);
holder.txtTitle.setTypeface(a);
holder.imgIcon.setImageResource(challenge.icon);
holder.txtPeople.setText(challenge.peopleString);
return row;
}
static class ChallengeHolder {
public LinearLayout friendThumbs;
ImageView imgIcon;
TextView txtTitle;
TextView txtPeople;
}
public ImageView createIcon(String friendID, Context cont) {
ImageView icon = new ImageView(context);
LinearLayout.LayoutParams par = new LinearLayout.LayoutParams(
(int) cont.getResources().getDimension(R.dimen.fbIconSize),
(int) cont.getResources().getDimension(R.dimen.fbIconSize));
par.setMargins(0, 0, 15, 0);
icon.setLayoutParams(par);
Log.e("ID " + friendID, "log");
final String myurl = AppSettings.profilePictureUrl(friendID);
icon.setImageResource(R.drawable.default_fb_icon_small);
((MyApplication) ((Activity) context).getApplication())
.loadImageSimple(myurl, icon);
return icon;
}
}
I guess that the cause of this problem is context equal to null got from the method getActivity, but don't know how to deal with this problem. Could anyone explain how to solve the problem?
I think onActivityCreated method override and implement for this code, and its working fine may be...
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(getActivity()!=null){
load();
}
}
And Fragment lifecyle must read for this doc Documentation
Most likely your Fragment is detached from your activity at this stage as this is called in an external thread JsonHttpResponseHandler.
You have a good explanation here:
https://stackoverflow.com/a/11536337/891479
You should not call
if(getActivity()!=null){
load();
}
in onCreateView.
onViewCreated is called after onCreateView and as per the docs
The fragment's view hierarchy is not however attached to its parent
at this point.
I think if I remember correctly its better to use getActivity().getApplicationContext()
good day, i am having a bit of a problem here. i am using and async task to display images from external or internal storage.Now it works but the problem is, it is very slow and slightly jerky in scrolling. I have no idea why? please any solution or an idea how to do this.
import java.io.IOException;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
public class Wallpaper extends Activity implements OnItemClickListener{
/*Instance variables*/
private GridView grid;
private ImageAdapter imageAdapter;
private Display display;
Cursor cursor;
boolean inInternalStorage = false;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.wallpaper_images);
display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
setupViews();
setProgressBarIndeterminateVisibility(true);
loadImages();
}
#Override
protected void onStop(){
super.onStop();
}
/*methods called from AsyncTask as appropriate when its querying and processing the images from the MediaStore*/
private void loadImages() {
final Object data = getLastNonConfigurationInstance();
if(data == null){
new LoadImagesFromSDCard().execute();
}else {
final LoadedImage[] photos = (LoadedImage[])data;
if(photos.length == 0){
new LoadImagesFromSDCard().execute();
}
for(LoadedImage photo:photos){
addImage(photo);
}
}
}
private void addImage(LoadedImage... value) {
for(LoadedImage photo: value){
imageAdapter.addPhotos(photo);
imageAdapter.notifyDataSetChanged();
}
}
private void setupViews() {
grid = (GridView)findViewById(R.id.gridview);
grid.setNumColumns(display.getWidth()/95);
grid.setClipToPadding(false);
imageAdapter = new ImageAdapter(getApplicationContext());
grid.setAdapter(imageAdapter);
grid.setOnItemClickListener(this);
}
protected void onDestroy() {
super.onDestroy();
final GridView gridview = grid;
final int count = grid.getChildCount();
ImageView v = null;
for (int i = 0; i < count; i++) {
v = (ImageView) grid.getChildAt(i);
((BitmapDrawable) v.getDrawable()).setCallback(null);
}
unbindDrawables(findViewById(R.id.gridview));
System.gc();
}
/*public Object onRetainNonConfigurationInstance(){
final GridView gridview = grid;
final int count = grid.getChildCount();
final LoadedImage[] list = new LoadedImage[count];
for(int i = 0; i < count; i++){
final ImageView v = (ImageView)grid.getChildAt(i);
list[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
}
return list;
}*/
/*utility method called that prevents screen from crashing when screen orientation changes*/
private void unbindDrawables(View view){
if(view.getBackground() != null){
view.getBackground().setCallback(null);
}
if(view instanceof ViewGroup){
for(int i = 0; i < ((ViewGroup) view).getChildCount(); i++){
unbindDrawables(((ViewGroup)view).getChildAt(i));
}
try{
((ViewGroup)view).removeAllViews();
}catch(Exception e){
e.printStackTrace();
}
}
}
/*AsyncTask thats queries the MediaStore for images and creates thumbnail images from bitmaps*/
class LoadImagesFromSDCard extends AsyncTask<Object, LoadedImage, Object> {
#Override
protected Object doInBackground(Object... params) {
Cursor cursor;
Bitmap bitmap = null;
Bitmap newbitmap = null;
Uri uri = null;
String [] img = {MediaStore.Images.Media._ID};
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)){
cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, img,
MediaStore.Images.Media.DATA + " like ? " , new String[]{ "%dcim%"}, null);
} else {
cursor = getContentResolver().query(MediaStore.Images.Media.INTERNAL_CONTENT_URI, img, null, null, null);
inInternalStorage = true;
}
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
int size = cursor.getCount();
if(size == 0){
Toast.makeText(getApplicationContext(), "There are no Images on the sdcard", Toast.LENGTH_SHORT).show();
}else {
}
for(int i = 0; i < size; i++){
cursor.moveToPosition(i);
int ImageId = cursor.getInt(column_index);
if(inInternalStorage == true){
uri = Uri.withAppendedPath(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "" + ImageId);
}else {
uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + ImageId);
}
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=4;
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
if(bitmap != null){
newbitmap = Bitmap.createScaledBitmap(bitmap, 100, 100, true);
bitmap.recycle();
}
if(newbitmap != null){
publishProgress(new LoadedImage(newbitmap));
}
}catch(IOException e){
}
}
cursor.close();
return null;
}
#Override
public void onProgressUpdate(LoadedImage... value){
addImage(value);
}
#Override
protected void onPostExecute(Object result) {
setProgressBarIndeterminateVisibility(false);
}
}
private static class LoadedImage {
Bitmap mBitmap;
LoadedImage(Bitmap bitmap) {
mBitmap = bitmap;
}
public Bitmap getBitmap() {
return mBitmap;
}
}
/*Image Adapter to populate grid view of images*/
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<LoadedImage> photos = new ArrayList<LoadedImage>();
public ImageAdapter(Context context){
this.mContext = context;
}
public void addPhotos(LoadedImage photo){
photos.add(photo);
}
#Override
public int getCount() {
return photos.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
System.gc();
ImageView image;
ViewHolder holder;
if(convertView == null){
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.image_list,null);
holder = new ViewHolder();
holder.image = (ImageView)convertView.findViewById(R.id.image_list_id);
convertView.setTag(holder);
} else{
holder = (ViewHolder)convertView.getTag();
}
holder.image.setLayoutParams(new GridView.LayoutParams(100, 100));
holder.image.setImageBitmap(photos.get(position).getBitmap());
return convertView;
}
}
static class ViewHolder {
ImageView image;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Cursor cursor = null;
int image_column_index = 0;
String[] proj = {MediaStore.Images.Media.DATA};
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)){
cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,proj, MediaStore.Images.Media.DATA + " like ? ", new String[]{"%dcim%"},null);
}else{
cursor = managedQuery(MediaStore.Images.Media.INTERNAL_CONTENT_URI,proj,null, null,null);
}
cursor.moveToPosition(position);
image_column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
String info = cursor.getString(image_column_index);
Intent imageviewer = new Intent(getApplicationContext(), ViewImage.class);
imageviewer.putExtra("pic_name", info);
startActivity(imageviewer);
}
}
i think what i am after is a way to allow doBackground() to run for a while before i call publishProgress(). just like how the gallery app in android does.
Any ideas on why this could be slow or how to solve this problem will be greatly appreciated as i have been stuck on how to improve the perfomance for a while now.
The biggest bottleneck will be accessing the images from the device (internal or external). Therefore, you'll want to have as many images in memory as possible (within reason of course). You can do this in a number of ways:
Load perhaps 18 images first (as you said, prebuffer before displaying). Check to make sure the number of images doesn't exceed whatever number you choose though.
Create a 'thumbs.db' type file which will store 100x100 px thumbnails of the bitmaps. This will allow much faster reading since you'd only need to read in one file then extract each bitmap. If the user clicks an image, then request it from the storage. This method requires more work, but will be able to load the thumbnails really fast. You'd probably have to design your own simple file headers, such as:
<file header (size of file, number of images)>
<image header (img id, size in bytes)>
<image bitmap data>
<image header (img id, size in bytes)>
<image bitmap data>
<image header (img id, size in bytes)>
<image bitmap data>
...