This seems to be a common question but I haven't been able to implement any of the solutions I have found. I have a Listview with a custom adapter that displays a thumbnail and text field in a row. The thumbnails are from a folder that I previously created and put the pictures I take from my app.
Here is my list activity:
private LayoutInflater mInflater;
private Vector<RowData> data;
private CustomAdapter adapter;
private RowData rd;
static File path = Environment.getExternalStorageDirectory();
static File fnames = new File(path, "MyImages");
static String[] title = fnames.list();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blog);
mInflater = (LayoutInflater) getSystemService(
Activity.LAYOUT_INFLATER_SERVICE);
setListName();
data = new Vector<RowData>();
for(int i=0;i<title.length;i++){
try {
rd = new RowData(i,title[i]);
} catch (ParseException e) {
e.printStackTrace();
}
data.add(rd);
}
getListView().setTextFilterEnabled(true);
getListView().setScrollingCacheEnabled(false);
}
public void onRestart()
{
super.onRestart();
setListName();
}
private Vector<RowData> setListName()
{
data = new Vector<RowData>();
String[] title = fnames.list();
//get the databases textblog
DatabaseHandler db = new DatabaseHandler(this);
List<TextBlog> textBlogs = db.getAllText();
int positionRaw = textBlogs.size();
for (int i=0;i<textBlogs.size(); i++) {
rd = new RowData(i, textBlogs.get(i).getText());
data.add(rd);
}
for(int i=0;i<title.length;i++) {
try {
rd = new RowData(positionRaw,title[i]);
positionRaw++;
} catch (ParseException e) {
e.printStackTrace();
}
data.add(rd);
}
adapter = new CustomAdapter(this, R.layout.list,R.id.title, data);
setListAdapter(adapter);
getListView().setTextFilterEnabled(true);
adapter.notifyDataSetChanged();
return data;
}
//Create thumbnail from file picture
private Bitmap decodeFile(File f) {
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while (o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
//Set row object
private class RowData
{
protected int mId;
protected String mTitle;
RowData(int id,String title){
mId=id;
mTitle = title;
}
#Override
public String toString() {
return mId+" "+mTitle+" ";
}
and here is my custom adaptor:
public class CustomAdapter extends ArrayAdapter<RowData>
{
public CustomAdapter(Context context, int resource, int textViewResourceId,
List<RowData> objects)
{
super(context, resource, textViewResourceId, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
TextView title = null;
ImageView thumb=null;
RowData rowData= getItem(position);
if(null == convertView) {
convertView = mInflater.inflate(R.layout.list, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
holder = (ViewHolder) convertView.getTag();
title = holder.gettitle();
title.setText(rowData.mTitle);
thumb=holder.getImage();
File file = new File(path + "/MyImages/" + rowData.mTitle);
//Check what kind of file is it to add thumbnail
//Way too slow use asynchronous task
if (rowData.mTitle.substring(rowData.mTitle.lastIndexOf('.') + 1).equalsIgnoreCase("mp4") == true)
{
Bitmap thumbVideo = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
thumb.setImageBitmap(thumbVideo);
}
else if (rowData.mTitle.substring(rowData.mTitle.lastIndexOf('.') + 1).equalsIgnoreCase("3gpp") == true)
{
thumb.setImageDrawable(getResources().getDrawable(R.drawable.voice));
}
else
{
thumb.setImageBitmap(decodeFile(file));
}
return convertView;
}
private class ViewHolder {
private View mRow;
private TextView title = null;
private ImageView thumb=null;
public ViewHolder(View row) {
mRow = row;
}
public TextView gettitle() {
if(null == title) {
title = (TextView) mRow.findViewById(R.id.title);
}
return title;
}
public ImageView getImage() {
if (null == thumb) {
thumb = (ImageView) mRow.findViewById(R.id.img);
}
return thumb;
}
}
}
}
I am quiet sure it's because of the thumbnails creation and I have to implement it in a AsynchTask, but I tried witout any success.
Can anyone suggest where I'm going wrong, or at list give me a tips?
You are trying to implement here the ViewHolder pattern, but your implementation looks wrong.
The idea of this pattern is to reduce the call to findViewById()which has an impact on your performance. Only if the row is null (convertView) you should call findViewById(), otherwise reuse the previous view saved with the setTag()
Lets take a look at your code:
if(null == convertView){
convertView = mInflater.inflate(R.layout.list, null);
holder = new ViewHolder();
convertView.setTag(holder);
}
// .......
title = holder.gettitle();
// .........
thumb=holder.getImage();
Notice that holder.getTitle(), and holder.getImage() are called after the if statement. This means they will be called every time regardless if the convertView is null or not.
Now, taking a look at these getters we see that they contain code that calls findViewById();
Ex. for the getTitle()
public TextView gettitle() {
if(null == title){
title = (TextView) mRow.findViewById(R.id.title);
}
return title;
}
So, basically, you don't use here ViewHolder pattern, just some mixed code, and in the end the findViewById() is called every time which reduces the performance of ListView.
To do it correctly you should call findViewById() only when the convertView is null.
Ex:
if(null==convertView){
convertView = mInflater.inflate(R.layout.list, null);
holder = new ViewHolder();
// Getting a refernce to the views with findViewById()
title = holder.gettitle();
thumb=holder.getImage();
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
// Then you set the appropriate values to your views through the holder:
holder.title.setText("");
holder.thumb.setImageBitmap(...);
This is the correct way to implement ViewHolder pattern
(PS: You'll need to change the access modifier for the title, thumb,... to public.)
Related
I want that this 200 Pictures are in every row of the ListView.
Where I have to copy this code which collect the pictures from the internet in my CustomAdapter?
for(int i = 1; i <= 200; i++){
final int ii = i;
final ImageView imageView = new ImageView(CustomListView.this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
//linearLayout.addView(imageView,lp);
Thread thread = new Thread(){
#Override
public void run(){
final Bitmap bm = getBitmapFromURL("http://ruthe.de/cartoons/strip_"+getPictureName(ii)+".jpg");
runOnUiThread(new Runnable() {
#Override
public void run() {
if(bm !=null){
imageView.setImageBitmap(bm);
}
else {
//linearLayout.removeView(imageView);
}
}
});
}
};thread.start ();
}
This is my CustomAdapter:
public class CustomAdapter extends BaseAdapter implements View.OnClickListener {
/*********** Declare Used Variables *********/
private Activity activity;
private ArrayList data;
private static LayoutInflater inflater=null;
public Resources res;
ListModel tempValues=null;
int i=0;
/************* CustomAdapter Constructor *****************/
public CustomAdapter(Activity a, ArrayList d,Resources resLocal) {
/********** Take passed values **********/
activity = a;
data=d;
res = resLocal;
/*********** Layout inflator to call external xml layout () ***********/
inflater = ( LayoutInflater )activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/******** What is the size of Passed Arraylist Size ************/
public int getCount() {
if(data.size()<=0)
return 1;
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
/********* Create a holder Class to contain inflated xml file elements *********/
public static class ViewHolder{
public TextView text;
public TextView text1;
public TextView textWide;
public ImageView image;
}
/****** Depends upon data size called for each row , Create each ListView row *****/
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
ViewHolder holder;
if(convertView==null){
/****** Inflate tabitem.xml file for each row ( Defined below ) *******/
vi = inflater.inflate(R.layout.tabitem, null);
/****** View Holder Object to contain tabitem.xml file elements ******/
holder = new ViewHolder();
holder.text = (TextView) vi.findViewById(R.id.text);
holder.text1=(TextView)vi.findViewById(R.id.text1);
holder.image=(ImageView)vi.findViewById(R.id.image);
/************ Set holder with LayoutInflater ************/
vi.setTag( holder );
}
else
holder=(ViewHolder)vi.getTag();
if(data.size()<=0)
{
holder.text.setText("No Data");
}
else
{
/***** Get each Model object from Arraylist ********/
tempValues=null;
tempValues = ( ListModel ) data.get(position);
/************ Set Model values in Holder elements ***********/
holder.text.setText(tempValues.getCompanyName());
holder.text1.setText( tempValues.getUrl() );
holder.image.setImageResource(
res.getIdentifier(
"com.androidexample.customlistview:drawable/"+tempValues.getImage(),null,null));
/******** Set Item Click Listner for LayoutInflater for each row *******/
vi.setOnClickListener(new OnItemClickListener( position ));
}
return vi;
}
#Override
public void onClick(View v) {
Log.v("CustomAdapter", "=====Row button clicked=====");
}
/********* Called when Item click in ListView ************/
private class OnItemClickListener implements View.OnClickListener{
private int mPosition;
OnItemClickListener(int position){
mPosition = position;
}
#Override
public void onClick(View arg0) {
CustomListView sct = (CustomListView)activity;
/**** Call onItemClick Method inside CustomListViewAndroidExample Class ( See Below )****/
sct.onItemClick(mPosition);
}
}
//My own code
public static Bitmap getBitmapFromURL(String src) {
try {URL url = new URL(src);
return BitmapFactory.decodeStream(url.openConnection().getInputStream());
}
catch(Exception e){
e.printStackTrace();
}
return null;
} //PICTURE BITMAP
public String getPictureName (int i){
String in = ""+i+"";
if(in.length() == 1){
return "000"+in;
}
else if(in.length() == 2){
return "00"+in;
}
else if(in.length() == 3){
return "0"+in;
}
else{
return in;
}
}
I searched on the whole internet but I dont found something which explains how to get pictures from the Internet into every row of a ListView...
PICASsO allows for hassle-free image loading in your application—often in one line of code!
for the library check this link http://square.github.io/picasso/
and at the bottom of page you can download jar file and just paste it in the libs folder
Picasso.with(context).load("YOUR IMAGE URL").into(imageView);
int your getView method
do it like
holder.image=(ImageView)vi.findViewById(R.id.image);
and then
Picasso.with(context).load("YOUR IMAGE URL").into(holder.image);
Take a look at the Picasso library. It makes it extremely easy.
http://square.github.io/picasso/
To use it, simply find your ImageView with the standard findViewById, then use the following code:
Picasso.with(context).load("www.google.com/images/1").into(imageView);
Simply input the URL and the ImageView, and Picasso will async load the image and put it in the imageview.
Im currently using it to show a list of over 400 images in a listview, works perfectly.
Except for the thread you can use the bitmap object inside the adapter itself and initialize the image view with the bitmap object, using position integer instead of (ii).
Hi i have found a workaround for my app: i have create a class type:
public class myClass {
....
...
private Bitmap imguser;
.. and into costructor i have added objects for async task like Future and i send image name
received from server side....
public myClass(..., ..,..,String userid, ...){
Future<Bitmap> futureimguser;
ExecutorService executor = Executors.newCachedThreadPool();
getImgFromSite getimguserfromsite = new getImgFromSite(userid,"imguser");
futureico = executor.submit(geticofromsite);
futureimguser = executor.submit(getimguserfromsite)
.......
this.imguser = futureimguser.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
this.icopoi = futureico.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executor.shutdown();
next i have a method like below which loads images from my site.
private final class getImgFromSite implements Callable<Bitmap> {
String imgsrc = new String();
String imgtipo = new String();
public getImgFromSite(String srcimg,String imgtipo) {
this.imgsrc = srcimg;
this.imgtipo = imgtipo;
}
#Override
public Bitmap call() throws Exception {
String imgpath;
if(imgtipo.compareTo("imguser") == 0){
imgpath = "http://mysite/assets/imgcomics/"+imgsrc+".jpg";
}
else{
imgpath = "http://mysite/"+imgsrc;
}
Bitmap myBitmap;
URL url = new URL(imgpath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
myBitmap= BitmapFactory.decodeStream(input);
return myBitmap;
}
}
Hope that i have help you!
im try to make listview with dynamic images, using asyntask its download image and set into listview. my problem is while scroll down images get randomly changed..
class ps1 extends ArrayAdapter<String> {
Context context;
String[] images1;
List mList;
String[] namearray;
String[] rating;
static class ViewHolder {
ImageView localImageView1;
ImageView localImageView2;
ImageView localImageView3;
}
ps1(Context paramContext, String[] paramArrayOfString1, String[] paramArrayOfString2, String[] paramArrayOfString3) {
super(paramContext, R.layout.list2, R.id.imageView1, paramArrayOfString1);
this.context = paramContext;
this.images1 = paramArrayOfString3;
this.namearray = paramArrayOfString1;
this.rating = paramArrayOfString2;
}
public View getView(int paramInt, View paramView, ViewGroup paramViewGroup) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(context.LAYOUT_INFLATER_SERVICE);
ViewHolder viewHolder = new ViewHolder();
if (paramView == null) {
paramView = inflater.inflate(R.layout.list2, paramViewGroup, false);
}
viewHolder.localImageView1 = (ImageView) paramView
.findViewById(R.id.imageView1);
viewHolder.localImageView2 = (ImageView) paramView
.findViewById(R.id.imageView2);
viewHolder.localImageView3 = (ImageView) paramView
.findViewById(R.id.imageView3);
viewHolder.localImageView1.setScaleType(ImageView.ScaleType.FIT_XY);
viewHolder.localImageView2.setScaleType(ImageView.ScaleType.FIT_XY);
viewHolder.localImageView3.setScaleType(ImageView.ScaleType.FIT_XY);
viewHolder.localImageView1.setTag(this.namearray[paramInt]);
new LoadImage().execute(viewHolder.localImageView1);
viewHolder.localImageView2.setTag(this.rating[paramInt]);
new LoadImage().execute(viewHolder.localImageView2);
viewHolder.localImageView3.setTag(this.images1[paramInt]);
new LoadImage().execute(viewHolder.localImageView3);
return paramView;
}
}
class LoadImage extends AsyncTask<Object, Void, Bitmap> {
private ImageView imv;
private Bitmap download_Image(String paramString) {
Bitmap localBitmap = null;
try {
Object localObject = null;
localBitmap = BitmapFactory
.decodeStream(((HttpURLConnection) new URL(paramString)
.openConnection()).getInputStream());
localObject = localBitmap;
if (localObject != null) {
return localBitmap;
}
} catch (Exception e) {
}
return localBitmap;
}
protected Bitmap doInBackground(Object... paramVarArgs) {
this.imv = ((ImageView) paramVarArgs[0]);
Log.d("fsdf", (String) this.imv.getTag());
return download_Image((String) this.imv.getTag());
}
protected void onPostExecute(Bitmap paramBitmap) {
this.imv.setImageBitmap(paramBitmap);
}
}
I have also experienced the same . I am also searching for a right solution . As far as i have searched , i came to know that ListView clears the previous view while scrolling down and re-loads it when you scroll back . So while scrolling up and down, your images may get re-cycled and mis-aligned . ( I am also waiting for the correct solution ) .
But i have tackled it using SmartImageView , which is a library that directly downloads the image and sets it to the ImageView . It will maintain the images in cache and so you could get the right images .
Comparatively this was faster too .
Try this snippet code which i have used in application and it's working fine in my application and i am sure it will work at your end.
In my condition i am retrieving images and some data from server and maintain all images on list scrolling fine.
class OfferCustomListAdapter extends ArrayAdapter<String>
{
private Context context;
Boolean OddNumber;
ArrayList<String> getDealID = new ArrayList<String>();
ArrayList<String> getInAdpterUNamedlist = new ArrayList<String>();
ArrayList<String> getShopNData = new ArrayList<String>();
ArrayList<String> getUserFav = new ArrayList<String>();
ArrayList<String> getTotalAmt = new ArrayList<String>();
ArrayList<String> getDealImage = new ArrayList<String>();
ArrayList<Boolean> getBoolnState = new ArrayList<Boolean>();
//String Oflist[] ;
int favCount=0;
public OfferCustomListAdapter(Context context,ArrayList<String> dealIdlist, ArrayList<Boolean> AddBoolnList, ArrayList<String> dealNamelist,ArrayList<String> ShopNList,ArrayList<String> UserFave,ArrayList<String> TotalAmt,ArrayList<String> ImageList) {
super(context, android.R.layout.simple_list_item_1,dealNamelist);
this.context=context;
//Oflist = getFolwerUNamelis;
getDealID = dealIdlist;
getInAdpterUNamedlist = dealNamelist;
getShopNData = ShopNList;
getUserFav = UserFave;
getTotalAmt = TotalAmt;
getDealImage = ImageList;
getBoolnState = AddBoolnList;
}
#Override
public View getView(final int pos, View view, ViewGroup parent) {
final ViewHolder holder;
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(this.context);
//view = inflater.inflate(R.layout.offer_custom_list, parent,false);
view = inflater.inflate(R.layout.reservatin_row, parent,false);
holder = new ViewHolder();
//holder.FollowrName = (TextView) view.findViewById(R.id.OfferNameTxt);
holder.DealName = (TextView) view.findViewById(R.id.tv_name);
holder.ShopName = (TextView) view.findViewById(R.id.tv_address);
holder.FavBtn = (ImageView) view.findViewById(R.id.Ofr_FavBtn);
holder.listLayout = (LinearLayout) view.findViewById(R.id.OfferListLayout);
holder.profile_image = (ImageView)view.findViewById(R.id.profile_img);
holder.OfferAmtBtn =(Button)view.findViewById(R.id.TotalOfrBtn);
//holder.FavBtn = (ImageView) view.findViewById(R.id.offerFavBtn);
holder.FavBtn.setTag(pos);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
if ( pos % 2 == 0 ){
System.out.println("You entered an even number. "+pos % 2);
holder.listLayout.setBackgroundResource(R.drawable.offer_list_bg);
}else{
System.out.println("You entered an odd number.");
holder.listLayout.setBackgroundResource(R.drawable.special_offer_bg);
}
/*if(getUserFav.get(pos).equals("0")){
//BolArraylist.add(false);
holder.FavBtn.setBackgroundResource(R.drawable.fav_btn);
}else{
//BolArraylist.add(true);
holder.FavBtn.setBackgroundResource(R.drawable.fav_active_btn);
}*/
holder.DealName.setText(getInAdpterUNamedlist.get(pos));
holder.ShopName.setText(getShopNData.get(pos));
holder.OfferAmtBtn.setText("$"+getTotalAmt.get(pos));
imgLoader.DisplayImage(getDealImage.get(pos), holder.profile_image);
holder.FavBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (isNetworkAvailable()) {
if(!userid.equals("")){
Offer_ID = getDealID.get(pos);
GUsrFavState = getUserFav.get(pos);
if(GUsrFavState.equals("0")){
GUsrFavState="1";
getUserFav.remove(pos);
getUserFav.add(pos, "1");
holder.FavBtn.setBackgroundResource(R.drawable.fav_active_btn);
getBoolnState.set(pos, true);
new Call_OfferFavWS().execute();
}else{
GUsrFavState="0";
holder.FavBtn.setBackgroundResource(R.drawable.fav_btn);
getUserFav.remove(pos);
getUserFav.add(pos, "0");
getBoolnState.set(pos, false);
new Call_OfferFavWS().execute();
}
}else{
Intent CallSignIn = new Intent(DollarMainActivity.this,SingInActivity.class);
startActivity(CallSignIn);
}
} else {
Toast alrtMsg = Toast.makeText(DollarMainActivity.this, "No network connection available !!!", Toast.LENGTH_LONG);
alrtMsg.setGravity(Gravity.CENTER, 0, 0);
alrtMsg.show();
}
}
});
if(getBoolnState.get(pos)){
holder.FavBtn.setBackgroundResource(R.drawable.fav_active_btn);
}else{
holder.FavBtn.setBackgroundResource(R.drawable.fav_btn);
}
return view;
}
class ViewHolder {
public TextView DealName,ShopName;
public ImageView FavBtn, profile_image;
public LinearLayout listLayout;
public Button OfferAmtBtn;
}
}
Hope it will help you.
if you need any help pls let me know.
i have a gridview like a listview. It work correctly first run, but when press back and return the activity that have gridView, get some errors...
logCat: android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=761 (# cursors opened by this proc=761)
i look at question like that, solution is always about cursor. I close cursor, when populate items info.. but it didnt work...
my gridView code:
private void refreshList(String sql)
{
gridArray = new ArrayList<Stock>();
final Cursor cursor = _SQLite.RawQueryTry(sql, null);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
if (cursor != null)
{
if (cursor.moveToFirst())
{
for (int i = 0; i < cursor.getCount(); i++)
{
String stockName = cursor.getString(cursor.getColumnIndex("STOK_ADI"));
String stockNo = cursor.getString(cursor.getColumnIndex("STOK_NO"));
String stockCode = cursor.getString(cursor.getColumnIndex("STOK_KODU"));
String stockEntity = cursor.getString(cursor.getColumnIndex("BIRIM"));
String stockKdvOranı = cursor.getString(cursor.getColumnIndex("KDV_ORANI"));
String stockRatio = TableUtils.getFieldValue("KATSAYI", "BIRIM", stockEntity, "STOKBIRI");
String stockAmount = cursor.getString(cursor.getColumnIndex("MIKTAR"));
gridArray.add(new Stock(stockName, stockNo, stockCode, stockKdvOranı, stockEntity, stockAmount, stockRatio, processNo));
cursor.moveToNext();
}
}
}
cursor.close();
gridAdapter = new AdapterStockGridListView(this, R.layout.stockgridlistitems, gridArray);
gridView.setAdapter(gridAdapter);
}
my adapter class is here:
public class AdapterStockGridListView extends ArrayAdapter<Stock>
{
Context context;
int id;
ArrayList<Stock> stock = new ArrayList<Stock>();
public AdapterStockGridListView(Context context, int id, ArrayList<Stock> stock)
{
super(context, id, stock);
this.id = id;
this.context = context;
this.stock = stock;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
RecordHolder holder = null;
if (row == null)
{
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(id, parent, false);
holder = new RecordHolder();
holder.txtTitle = (TextView) row.findViewById(R.id.stockName);
holder.txtStockNo = (TextView) row.findViewById(R.id.stockNo);
holder.txtStockCode = (TextView) row.findViewById(R.id.stockCode);
row.setTag(holder);
}
else
{
holder = (RecordHolder) row.getTag();
}
Stock item = stock.get(position);
holder.txtTitle.setText(item.getStockName());
holder.txtStockNo.setText(item.getStockNo());
holder.txtStockCode.setText(item.getStockCode());
return row;
}
}
static class RecordHolder
{
TextView txtTitle;
TextView txtStockNo;
TextView txtStockCode;
}
This is because you are trying to access closed cursor. So remove this line
cursor.close();
And to manage cursor properly write this line in your activity or fragment
In Activity
startManagingCursor(pass Your Cursor object here);
In Fragment
getActivity().startManagingCursor(pass Your Cursor object here);
override this method in adapter class and also print the size of array may be it has only one vale
#Override
public int getCount() {
return stock.size();
}
I have a ListView inside an Activity and each of its item is customized to have some TextViews along with a DropDownList item and an ImageView. Inside an OnScrollListener() implementation each item of a listView gets populated using an ArrayAdapter populating text views with values taken from an arrayList and ImageView with the .jpeg file stored on SD card. Following is the screenSHot of listView Item
The problem arises when the .jpeg file from sdCard is converted to a bitmap (i.e. BitmapFactory.decodeFile(fileName) ) and then gets assigned to an image View using setImageBitmap(Bitmap bmp). As the setting bitmap image to an image view is a lengthy process it cannot keep pace with the scroll listener implementation and the ImageView of different ListView rows gets populated with the image it was assigned to any row above. Can anybody please suggest some workout to cater this issue specifically the assignment of images from SD Card to an imageView. Its not like my listView item is overLoaded with controls that is why i am facing this problem. I also have tried it with single ImageView item inside each row and it behaves the same way. Your suggestion to improvise this are welcome and surely will be of great help. Thank you :-)
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
AssetDetailHolder assetDetailholder = null;
try {
if (row == null) {
LayoutInflater inflator = ((Activity) context)
.getLayoutInflater();
row = inflator.inflate(layoutResourceID, parent, false);
assetDetailholder = new AssetDetailHolder();
assetDetailholder.itemPosition = position;
assetDetailholder.txtVwlineCOde = (TextView) row
.findViewById(R.id.lineCodeValue_ad);
assetDetailholder.txtvwLocation = (TextView) row
.findViewById(R.id.locationValue_ad);
assetDetailholder.txtvwLocationDetail = (TextView) row
.findViewById(R.id.detailLocationValue_ad);
assetDetailholder.txtvwInventoryNo = (TextView) row
.findViewById(R.id.InventoryNoValue_ad);
assetDetailholder.spnrconditionCode = (Spinner) row
.findViewById(R.id.spinner_ad);
assetDetailholder.txtvwAssetName = (TextView) row
.findViewById(R.id.AssetNameValue_ad);
assetDetailholder.subNoThumbnail = (ImageView) row
.findViewById(R.id.IV_subNoThumbnail);
row.setTag(assetDetailholder);
} else {
assetDetailholder = (AssetDetailHolder) row.getTag();
assetDetailholder.itemPosition = position;
}
AssetDetail assetDetail = assetsDetailList[position];
new ThumbnailTask(position, assetDetailholder, assetDetail, context)
.execute();
if (assetDetail.assetLineCodeDesc.equals("")) {
assetDetailholder.txtVwlineCOde
.setText(assetDetail.strLineCOde);
} else {
assetDetailholder.txtVwlineCOde.setText(assetDetail.strLineCOde
+ "(" + assetDetail.assetLineCodeDesc + ")");
}
if (assetDetail.assetLocationNameDesc.equals("")) {
assetDetailholder.txtvwLocation
.setText(assetDetail.strLocationName);
} else {
assetDetailholder.txtvwLocation
.setText(assetDetail.strLocationName + "("
+ assetDetail.assetLocationNameDesc + ")");
}
assetDetailholder.txtvwLocationDetail
.setText(assetDetail.strLocationDetail);
if (assetDetail.strInventoryNumber.contains("-")) {
assetDetailholder.txtvwInventoryNo
.setText(assetDetail.strInventoryNumber.split("-")[0]);
} else {
assetDetailholder.txtvwInventoryNo
.setText(assetDetail.strInventoryNumber);
}
assetDetailholder.txtvwAssetName.setText(assetDetail.assetName);
String conditionCodeString = assetDetail.assetConditionCode;
if (conditionCodeString != "" || conditionCodeString != null) {
try {
int conditionCodeInteger = Integer
.parseInt(conditionCodeString);
assetDetailholder.spnrconditionCode
.setSelection(conditionCodeInteger);
} catch (Exception e) {
assetDetailholder.spnrconditionCode.setSelection(0);
}
} else {
assetDetailholder.spnrconditionCode.setSelection(0);
}
// String thumbnailDir = Common
// .getSubNoDirectory(context, assetDetail);
// if (new File(thumbnailDir).isDirectory()) {
//
// File thumbnailFile = new File(Common.getSubNoImgFilePath(
// thumbnailDir, assetDetail, SubNo_ImageSample.A));
//
// if (thumbnailFile.exists()) {
// assetDetailholder.subNoThumbnail
// .setImageBitmap(BitmapFactory
// .decodeFile(thumbnailFile.getAbsolutePath()));
// }
// }
} catch (Exception e) {
e.printStackTrace();
}
return row;
}
static class AssetDetailHolder {
TextView txtVwlineCOde;
TextView txtvwLocation;
TextView txtvwLocationDetail;
TextView txtvwInventoryNo;
TextView txtvwAssetName;
Spinner spnrconditionCode;
ImageView subNoThumbnail;
public int itemPosition;
}
private static class ThumbnailTask extends AsyncTask<Void, Void, Void> {
private int mPosition;
private AssetDetailHolder mHolder;
private Context cntxt;
private AssetDetail assetItem;
private Bitmap thumbnailBmp;
public ThumbnailTask(int position, AssetDetailHolder holder,
AssetDetail asset, Context context) {
mPosition = position;
mHolder = holder;
assetItem = asset;
cntxt = context;
}
#Override
protected Void doInBackground(Void... params) {
String thumbnailDir = Common.getSubNoDirectory(cntxt, assetItem);
if (new File(thumbnailDir).isDirectory()) {
File thumbnailFile = new File(Common.getSubNoImgFilePath(
thumbnailDir, assetItem, SubNo_ImageSample.A));
if (thumbnailFile.exists()) {
thumbnailBmp = BitmapFactory.decodeFile(thumbnailFile
.getAbsolutePath());
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (mHolder.itemPosition == mPosition && thumbnailBmp != null) {
mHolder.subNoThumbnail.setImageBitmap(thumbnailBmp);
}
// super.onPostExecute(result);
}
}
http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
This will be hopefull to you :P
I have a set a variable in my Base Adapter class, now I want to get(pass) this variable in my related Activity. I am not getting how to do this.
Here is my code.
public class TourDescAdapter extends BaseAdapter {
private List<Descriptions> descriptList;
private LayoutInflater mInflater;
ViewHolder holder;
#SuppressWarnings("unused")
private OnClickListener clickListener;
Activity context;
//TourDescription tourDesc;
ArrayList<HashMap<String, Object>> obj = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> discountedTourDetails = null;
String price = null, prodId = null;
String promoTourname, tourName;
public TourDescAdapter(List<Descriptions> descriptList,
TourDescription activity) {
this.context = activity;
this.descriptList = descriptList;
mInflater = LayoutInflater.from(activity);
clickListener = (OnClickListener) activity;
}
#Override
public int getCount() {
return this.descriptList.size();
}
#Override
public Object getItem(int position) {
return this.descriptList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.tourlist, null);
/****
* Creates a ViewHolder and store references to the two children
* views we want to bind data to
****/
holder = new ViewHolder();
holder.rlayout = (RelativeLayout) convertView
.findViewById(R.id.tourlayout);
holder.title = (TextView) convertView
.findViewById(R.id.tourtitletext);
holder.desc = (TextView) convertView.findViewById(R.id.tourdes);
holder.amountButton = (Button) convertView
.findViewById(R.id.amtBtn);
holder.pinButton = (Button) convertView.findViewById(R.id.pinBtn);
holder.arrowButton = (Button)convertView.findViewById(R.id.arrowBtn);
holder.serialText = (EditText)convertView.findViewById(R.id.pinText);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.title.setText((String) descriptList.get(position)
.getImageTitle());
holder.desc.setText((String) descriptList.get(position)
.getImageDescription());
((ImageView) holder.rlayout.getChildAt(0)).setImageBitmap(BitmapFactory
.decodeFile((RaconTours.PATH + RaconTours.city + File.separator
+ TourDescription.currentTour.getObjtourName()
+ File.separator + descriptList.get(position)
.getImagePath().split("/")[2]).replace(" ", "_")));
if (position == 0) {
SharedPreferences settings = context.getSharedPreferences("downloadDetails", 0);
String isTourDownloaded = settings.getString(TourDescription.currentTour.getObjtourName(), "");
if (isTourDownloaded.equals("true")) {
//if (!(TourDescription.downloadFile.exists())||TourDescription.downloadFile.exists() == false ) {
//if (TourDescription.currentTour.getIsTourDownloaded() == true) {
//holder.pinButton.setVisibility(View.INVISIBLE);
//holder.arrowButton.setVisibility(View.INVISIBLE);
//holder.serialText.setVisibility(View.INVISIBLE);
}
holder.amountButton.setVisibility(View.VISIBLE);
holder.amountButton.setText("Start");
} else {
File promoPlistPath = new File(RaconTours.PATH + "promocode.txt");
checkPromoCode(promoPlistPath);
if (discountedTourDetails != null) {
tourName = (String) discountedTourDetails.get("promoTour");
price = (String) discountedTourDetails.get("discountPrice");
prodId = (String) discountedTourDetails.get("disProId");
holder.amountButton.setVisibility(View.VISIBLE);
// Setting the background color
holder.title
.setBackgroundColor(Color.parseColor("#993333"));
// Setting the Title color
holder.title.setTextColor(Color.WHITE);
// Centering the title
holder.title.setGravity(Gravity.LEFT);
// setting the city
((TextView) holder.rlayout.getChildAt(1))
.setText(RaconTours.city);
((TextView) holder.rlayout.getChildAt(1))
.setVisibility(View.VISIBLE);
// setting the Tour Amount
holder.amountButton.setText("$" +price);
//promoPlistPath.delete();
} else {
// Enabling the two buttons
holder.amountButton.setVisibility(View.VISIBLE);
// Setting the background color
holder.title
.setBackgroundColor(Color.parseColor("#993333"));
// Setting the Title color
holder.title.setTextColor(Color.WHITE);
// Centering the title
holder.title.setGravity(Gravity.LEFT);
// setting the city
((TextView) holder.rlayout.getChildAt(1))
.setText(RaconTours.city);
((TextView) holder.rlayout.getChildAt(1))
.setVisibility(View.VISIBLE);
// setting the Tour Amount
holder.amountButton.setText(TourDescription.currentTour
.getObjPrice());
}
}
} else {
holder.amountButton.setVisibility(View.INVISIBLE);
holder.pinButton.setVisibility(View.INVISIBLE);
holder.arrowButton.setVisibility(View.INVISIBLE);
holder.serialText.setVisibility(View.INVISIBLE);
holder.title.setBackgroundColor(Color.WHITE);
holder.title.setTextColor(Color.BLACK);
holder.title.setGravity(Gravity.CENTER_HORIZONTAL);
((TextView) holder.rlayout.getChildAt(1))
.setVisibility(View.INVISIBLE);
}
return convertView;
}
#SuppressWarnings("unchecked")
private void checkPromoCode(File promoPlistPath) {
if (promoPlistPath.exists()) {
try {
ObjectInputStream inStream = new ObjectInputStream(
new FileInputStream(promoPlistPath));
obj = (ArrayList<HashMap<String, Object>>) inStream
.readObject();
for (HashMap<String, Object> tmpObj : obj) {
promoTourname = (String) tmpObj.get("promoTour");
if (promoTourname.equals(TourDescription.currentTour.getObjtourName())) {
discountedTourDetails = tmpObj;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ViewHolder {
Button pinButton;
Button amountButton;
RelativeLayout rlayout;
TextView title;
TextView desc;
Button arrowButton;
EditText serialText;
}
}
Here
prodId = (String) discountedTourDetails.get("disProId");
I want to pass prodId to related activity.
Note: Base Adapter is called from the activity
adapter = new TourDescAdapter(currentTour.getListOfDescriptions(), this);
setListAdapter(adapter);
Any one can tell me how to do this?
Couldn't you just use String iGotTheString = adapter.prodId?