I got a problem in gridview scroll. I have make one custom gridview and insert widget in raw file and inflate them through view. I got proper result and proper data and everything is gone well but when I scroll gridview 3-4 times up down speedy it raises an OutOfMemoryException.
This app contain list of installed app list and icon
Here is my custome adapter's code:
package com.AppFavorits;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.AppFavorits.ImageLoad.ImageLoader;
public class GridViewAdapter extends BaseAdapter {
private Context activit;
LayoutInflater inflator;
public RelativeLayout imgvGridItem;
public TextView txtGridItemlabel;
public CheckBox chkbxGridItem;
ArrayList<PInfo> lstpinfo = new ArrayList<PInfo>();
public ImageLoader imageLoader;
public GridViewAdapter(Context m1, ArrayList<PInfo> lstpinfo) {
activit = m1;
inflator = LayoutInflater.from(m1);
this.lstpinfo = lstpinfo;
imageLoader=new ImageLoader(m1.getApplicationContext());
}
public static class ViewHolder {
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder view;
// LayoutInflater inflator = activit.getLayoutInflater();
view = new ViewHolder();
convertView = inflator.inflate(R.layout.gridviewrow, null);
imgvGridItem = (RelativeLayout) convertView
.findViewById(R.id.rlGreidItemicon);
txtGridItemlabel = (TextView) convertView
.findViewById(R.id.txtGridItemlabel);
chkbxGridItem = (CheckBox) convertView
.findViewWithTag(R.id.chkbxGridItem);
if ((lstpinfo.get(position).appname.toString()) != null){
Drawable d = lstpinfo.get(position).icon;
//new ImageLoad().execute();
imgvGridItem.addView(getimageviewimage(lstpinfo.get(position).icon));
txtGridItemlabel.setText(lstpinfo.get(position).appname.toString());
// convertView.setTag(view);
}
return convertView;
}
#Override
public int getCount() {
return lstpinfo.size();
}
#Override
public Object getItem(int position) {
return lstpinfo.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public RelativeLayout getimageviewimage(Drawable d) {
RelativeLayout seprator = new RelativeLayout(activit);
seprator.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
seprator.setGravity(Gravity.LEFT | Gravity.CENTER);
ImageView imgmap = new ImageView(activit);
imgmap.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
// imgmap.setBackgroundResource(R.drawable.a13);
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();
imageLoader.DisplayImage(bitmap, imgmap);
//imgmap.setImageBitmap(bitmap);
seprator.setPadding(5, 5, 15, 5);
seprator.addView(imgmap);
return seprator;
}
private class ImageLoad extends AsyncTask<Void, Void, Void> {
// private final ProgressDialog dialog = new ProgressDialog(tranning.this);
protected void onPreExecute() {
// this.dialog.setMessage("Please Wait...");
// this.dialog.show();
// put your code which preload with processDialog
}
#Override
protected Void doInBackground(Void... arg0) {
// put your code here
return null;
}
#Override
protected void onPostExecute(final Void unused) {
/*if (this.dialog.isShowing()) {
this.dialog.dismiss();
} */
}
}
}
I think there are something wrong with getview.
In getView() you are not reusing convertView, but always inflating new one with inflator. This requires more memory and makes your code slower. Also, check that you are not leaking images with imageLoader.
out of memory usually means that there is not enough memory to load the file. try closing everything else (or atleast a few other apps) and trying again.
Download code From Following link and use gridview instead of listview
Lazy Loading Example
Related
The gallery app. I made my adapter. I want to make it so that when you click on the image, it increases. I found a ready-made code, but it only shows a toast here. As I understand it, something needs to be added in the listener, but I don't know what. What do I need to add in the listener to make the picture bigger?
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.media.Image;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<Cell> galleryList;
private Context context;
public ImageView img;
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(Context context, ArrayList<Cell> galleryList) {
this.context = context;
this.galleryList = galleryList;
}
// Create new views (invoked by the layout manager)
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent,
int viewType) {
// create a new view
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cell, parent, false);
return new ViewHolder(view);
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(final ViewHolder viewHolder, #SuppressLint("RecyclerView") final int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
viewHolder.img.setScaleType(ImageView.ScaleType.CENTER_CROP);
setImageFromPath(galleryList.get(position).getPath(), viewHolder.img);
viewHolder.img.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//TODO something can happen if you click on the image
Toast.makeText(context, "" + galleryList.get(position), Toast.LENGTH_SHORT).show();
}
});
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public ImageView img;
public ViewHolder(View view) {
super(view);
img = view.findViewById(R.id.img);
}
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return galleryList.size();
}
private void setImageFromPath(String path, ImageView image) {
File imgFile = new File(path);
if (imgFile.exists()) {
Bitmap myBitmap = ImageHelper.decodeSampleBitmapFromPath(imgFile.getAbsolutePath(), 200, 200);
image.setImageBitmap(myBitmap);
}
}
}
I have built an overview of an order with a ReyclerView. Below you can see the code for the adapter class. My problem only occurs in the following place, if the user clicks on an element of ReyclerView, a popup with an expanded view should appear.
This popup also occurs. Unfortunately, as soon as I want to populate the TextView with the order code, the app supports and says null Attempt to invoke virtual method'void android.widget.TextView.setText (java.lang.CharSequence)' on a null object reference.
How can I avoid this null error so that it all works?
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class UserBestellAdapter extends RecyclerView.Adapter<UserBestellAdapter.ViewHolder> {
ArrayList<Bestellung> bestellung;
Context mContext;
Dialog epicDialog;
public UserBestellAdapter(Context context, ArrayList<Bestellung> list) {
mContext = context;
bestellung = list;
epicDialog = new Dialog(mContext);
}
#NonNull
#Override
public UserBestellAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.adapter_bestell, parent, false);
UserBestellAdapter.ViewHolder viewHolder = new UserBestellAdapter.ViewHolder(view);
return viewHolder;
}
#NonNull
#Override
public void onBindViewHolder(#NonNull UserBestellAdapter.ViewHolder holder, int position) {
//Gesamtpreis: holder.item_betrag.setText(String.valueOf(bestellung.get(position).getBetrag()));
// Datum: holder.item_datum.setText(bestellung.get(position).getDatum());
holder.item_items.setText(bestellung.get(position).getProdukte());
//holder.item_code.setText(bestellung.get(position).getBestellnummer());
String bestellid =bestellung.get(position).getBestellnummer() + "";
holder.item_code.setText(bestellid);
holder.item_betrag.setText(Double.toString(bestellung.get(position).getSumme()));
holder.item_datum.setText(bestellung.get(position).getDatum());
holder.layout_user_bestellung.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TextView order_overview_number = epicDialog.findViewById(R.id.order_overview_number);
order_overview_number.setText();
epicDialog.setContentView(R.layout.order_popup_waiting);
epicDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
Button btn_order_overview_finish = (Button) epicDialog.findViewById(R.id.btn_order_overview_finish);
/*
btn_order_overview_finish.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
epicDialog.dismiss();
}
});*/
epicDialog.show();
}
});
}
#Override
public int getItemCount() {
return bestellung.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView item_items, item_betrag, item_datum, item_code;
private ConstraintLayout layout_user_bestellung;
public ViewHolder(#NonNull View itemView) {
super(itemView);
item_items = itemView.findViewById(R.id.items);
item_betrag = itemView.findViewById(R.id.betrag);
item_datum = itemView.findViewById(R.id.datum);
item_code = itemView.findViewById(R.id.code);
layout_user_bestellung = itemView.findViewById(R.id.layout_user_bestellung);
}
}
}
Your Dialog is initialized with new Dialog(context) but in your onClick Method you expect that your epicDialog has a TextVew with the id order_overview_number.
This will always return null and thus order_overview_number.setText() thows a NPE.
To reference a view of a Dialog the Dialog needs a layout which contains that view, similar to fragments and activities.
This may have further information for you:
How to create a Custom Dialog box in android?
https://developer.android.com/guide/topics/ui/dialogs
I have had a basic Gridview sample from Google's documentation, which worked perfectly.
I also have some code that provides result as ArrayList with Bitmaps of last created pictures in Android's external storage (Permissions in manifest are granted) and that code also worked just fine on other project.
When I merged that concepts into one simple app code isn't working at all, activity remains empty till app crashes. However I noticed something interesting: There's a for loop which has defined number of iterations by int capacity but in Logcat I can see that number of iterations in this loop surpassing declared int value, basically that's reason why app crashes (outOfBoundsException).
So i Have those 2 problems and sitting on that for couple of hours... here is my code:
MainActivity.java
package com.example.patryk.hellogridview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridview = findViewById(R.id.gridview);
gridview.setAdapter(new ImageAdapter(this));
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(MainActivity.this, "" + position,
Toast.LENGTH_SHORT).show();
}
});
}
PhotosReader.java
package com.example.patryk.hellogridview;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.provider.MediaStore;
import android.util.Log;
import java.util.ArrayList;
public class PhotosReader {
private int capacity = 5;
private ArrayList<Bitmap> photos = new ArrayList<Bitmap>(capacity);
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public void setPhotos(ArrayList<Bitmap> photos) {
this.photos = photos;
}
public PhotosReader() {
}
public ArrayList<Bitmap> getPhotos(Context context) {
String[] projection = new String[]{
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DATA,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.MIME_TYPE
};
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null,
null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
cursor.moveToFirst();
for(int i = 1; i<=capacity; i++){
photos.add(BitmapFactory.decodeFile(cursor.getString(1)));
cursor.moveToNext();
Log.d("photos.add", "iteration");
}
return photos;
}
public Bitmap getPhotosBitmap(ArrayList photos, int position){
Bitmap bm = (Bitmap) photos.get(position);
return bm;
}
}
ImageAdapter.java
package com.example.patryk.hellogridview;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return 0;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
PhotosReader PR = new PhotosReader();
imageView.setImageBitmap(PR.getPhotosBitmap(PR.getPhotos(mContext), position));
return imageView;
}
}
This function inside ImageAdapter should not return 0. It should return the number of images that you want to show in the grid so should return capacity in your case. GridView assumes that there are 0 things to show
public int getCount() {
return 0;
}
change this to
public int getCount() {
return capacity;
}
Actually the correct way to do this would be to pass the PhotoReader object from the ImageAdapter constructor using ImageAdapter(context,photoReader) and then use photoReader.getCapacity() in getCount() function
I would like the user to get the option once the chosen image is clicked to set the image as their wallpaper or to save it to their SD card.
This is my first time doing this so I need some guidance. I have looked at other questions similar to this one but everyone uses different methods to the one I have done to set up displaying the images.
Thanks in advance, here's the code:
AdapterView for Displayimagesin:
package com.question;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
public class AdapterViewADV extends BaseAdapter {
private Context mContext;
public Integer[] mThumbIds = {
R.drawable.Image1,
R.drawable.Image2,
R.drawable.Image3,
R.drawable.Image4,
R.drawable.Image5,
R.drawable.Image6
};
public AdapterViewADV(Context c){
mContext = c;
}
#Override
public int getCount() {
return mThumbIds.length;
}
#Override
public Object getItem(int position) {
return mThumbIds[position];
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = null;
if(convertView == null){
imageView = new ImageView(mContext);imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(NO_SELECTION, NO_SELECTION));
convertView = imageView;
}else{
imageView = (ImageView)convertView;
}
imageView.setImageResource(mThumbIds[position]);
return convertView;
}
}
Class displaying images in:
package com.question;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.Toast;
public class Displayimagesin extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_battlefield4);
GridView gridView = (GridView) findViewById(R.id.grid_view);
// Instance of ImageAdapter Class
gridView.setAdapter(new AdapterViewADV(this));
gridView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(Displayimagesin.this, "Wallpaper set",
Toast.LENGTH_SHORT).show();
}
});
}
}
set wallpaper by calling WallpaperManager .
get a reference to your image to Bitmap.
something like this
WallpaperManager wm=WallpaperManager.getInstance(this);
wm.setBitmap(bitmap);
and in manifest file add permission
android.permission.SET_WALLPAPER
hope it helps.
Try to use WallpaperManager to set wallpaper
WallpaperManager myWallpaperManager=WallpaperManager.getInstance(getApplicationContext());
myWallpaperManager.setResource(mThumbIds[curruntPosition]);
I have a simple list view with adapter.
I create 10+ listviewitems dynamically. Then I scroll up and down again and again and again....
I can see that available memory keeps going down...
Where do I need to free and what?
Note - there is an imageview - but in my test I have not used any images so it is View.GONE.
Also - with which tool can I profile the memory usage on the android. I have found yourKit,but how do I configure it for the android (I run the application on the device)/
The Activity class
package org.BJ.Food4All.Activities.NewRecipe;
import org.BJ.Food4All.R;
import org.BJ.Food4All.Recipe;
import org.BJ.Food4All.Recipe.Instruction;
import org.BJ.Food4All.Activities.RecipeBook.RecipeInstructionsListViewAdapter;
import org.BJ.Food4All.Activities.RecipeBook.SharedData;
import org.BJ.Food4All.utils.CameraUtil;
import org.BJ.Food4All.utils.ImageUploadItem;
import android.app.ListActivity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.EditText;
public class Instructions extends ListActivity implements OnClickListener
{
private final static String mTAG = "Instructions";
private EditText mInstructionEditText = null;
private RecipeInstructionsListViewAdapter mListViewAdapter = null;
private Recipe mEditRecipe = PrivateResources.GetRecipe();
private CameraUtil mCameraUtil = new CameraUtil(this);
private int mSelectedEntryIndex = -1;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.new_recipe_instruction_tab);
mInstructionEditText = (EditText)findViewById(R.id.newRecipeInstructionEditTextId);
View addInstructionButton = findViewById(R.id.naddInstructionButtonId);
// Sanity check
if(mInstructionEditText == null || addInstructionButton == null)
{
Log.e(mTAG, "NULL pointers");
// secure exit
finish();
}
// Set up click listeners for all the buttons
addInstructionButton.setOnClickListener(this);
mListViewAdapter = new RecipeInstructionsListViewAdapter(this, R.layout.recipes_instruction_list_single_view_entry, mEditRecipe.GetInstructions());
setListAdapter(mListViewAdapter);
registerForContextMenu(getListView());
}
public void onClick(View v)
{
switch(v.getId())
{
case R.id.naddInstructionButtonId:
AddInstructionToRecipe(v);
break;
default:
Log.e(mTAG, "Invalid ID:" + v.getId());
// secure exit
finish();
}
}
private void AddInstructionToRecipe(View v)
{
String instructionText = mInstructionEditText.getText().toString();
if(instructionText == null)
{
return;
}
Instruction newInstruction = new Instruction( mEditRecipe.GetInstructions().size() + 1, // Index
instructionText, // The instruction
null,
true);
if( mEditRecipe.AddInstruction(newInstruction) != true)
{
// TODO - ERROR
}
else
{
mListViewAdapter.notifyDataSetChanged();
}
}
/*
* (non-Javadoc)
* #see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)
*/
#Override
public void onCreateContextMenu(ContextMenu menu,
View v,
ContextMenuInfo menuInfo)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.instructions_ctx_menu, menu);
super.onCreateContextMenu(menu, v, menuInfo);
}
/*
* (non-Javadoc)
* #see android.app.Activity#onContextItemSelected(android.view.MenuItem)
*/
#Override
public boolean onContextItemSelected(MenuItem item)
{
super.onContextItemSelected(item);
AdapterView.AdapterContextMenuInfo menuInfo;
menuInfo = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
mSelectedEntryIndex = menuInfo.position;
switch(item.getItemId())
{
case R.id.deleteId:
mEditRecipe.RemoveInstruction(mSelectedEntryIndex);
mListViewAdapter.notifyDataSetChanged();
return true;
case R.id.takePictureId:
mCameraUtil.TakePicture();
return true;
}
return false;
}
/*
* (non-Javadoc)
* #see android.app.Activity#onActivityResult(int, int, android.content.Intent)
*/
#Override
protected void onActivityResult(int requestCode,
int resultCode,
Intent data)
{
// String imageLocation = mCameraUtil.onActivityResult(requestCode, resultCode, data);
Bitmap imageBitmap = mCameraUtil.onActivityResult(requestCode, resultCode, data);
// TODO - switch to parameter passed in the intent!!!! like TakePicture(index);
// mEditRecipe.GetInstructions().get( mSelectedEntryIndex ).SetBitmap( imageBitmap ); //SetInstructionImageLocation(imageLocation);
mSelectedEntryIndex = -1;
// Update the listviewitem with the picture
mListViewAdapter.notifyDataSetChanged();
}
}
The adapter class
package org.BJ.Food4All.Activities.RecipeBook;
import java.util.ArrayList;
import org.BJ.Food4All.R;
import org.BJ.Food4All.Recipe.Instruction;
import org.BJ.Food4All.utils.GlobalDefs;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class RecipeInstructionsListViewAdapter extends ArrayAdapter<Instruction>
{
private Context mContext;
private ArrayList<Instruction> mItems;
private LayoutInflater mInflater;
public RecipeInstructionsListViewAdapter(Context context, int textViewResourceId, ArrayList<Instruction>items)
{
super(context, textViewResourceId, items);
mContext = context;
mItems = items;
mInflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position,
View convertView,
ViewGroup parent)
{
ViewHolder holder = new ViewHolder();
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.recipes_instruction_list_single_view_entry, null);
}
if(super.getItem(position) != null)
{
holder.instructionIndex = (TextView) convertView.findViewById( R.id.listUp_RecipeInstructionNumberTextBoxId);
holder.instructionText = (TextView) convertView.findViewById( R.id.listUp_RecipeInstructionTextTextBoxId);
holder.instructionImage = (ImageView)convertView.findViewById( R.id.listUp_RecipeInstructionImageViewId);
Typeface tf = Typeface.createFromAsset(mContext.getAssets(), "Eras_Bold.ttf");
holder.instructionIndex.setTypeface(tf);
holder.instructionIndex.setTextSize(30);
holder.instructionIndex.setTextColor(GlobalDefs.GetHeadlineColor());
holder.instructionIndex.setText( Integer.toString(mItems.get(position).getIndex()));
tf = Typeface.createFromAsset(mContext.getAssets(), "Arial.ttf");
holder.instructionText.setTypeface(tf);
holder.instructionText.setTextSize(14);
holder.instructionText.setTextColor(Color.BLACK);
holder.instructionText.setText(mItems.get(position).getText());
Bitmap imageBitmap = mItems.get(position).GetBitmap();
// String imageLocation = mItems.get(position).GetInstructionImageLocation();
if(imageBitmap != null)
{
holder.instructionImage.setImageBitmap(imageBitmap);// setImageURI( Uri.parse(imageLocation ));
holder.instructionImage.setVisibility(View.VISIBLE);
}
else
{
holder.instructionImage.setVisibility(View.GONE);
}
convertView.setTag(holder);
convertView.setLayoutParams(new ListView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
else
{
}
return convertView;
}
#Override
public boolean isEnabled(int position)
{
return true;
}
static class ViewHolder
{
TextView instructionIndex;
TextView instructionText;
ImageView instructionImage;
}
}
I'm not sure if it is correct to classify this as a bug, but every time you use Typeface.createFromAsset if creates a new font asset and does not release it. See this.
What you can do is load the typefaces when you load your app and reference them statically. I put my typefaces in Application.
public class YourApp extends android.app.Application {
public void onCreate() {
super.onCreate();
// typeface caching
initializeTypefaces();
}
public static class Fonts {
public static Typeface THEOREM;
}
private void initializeTypefaces(){
Fonts.THEOREM = Typeface.createFromAsset(getAssets(), "fonts/theorem.otf");
}
}
And then I do this in my adapter:
textView.setTypeface(YourApp.Fonts.THEOREM);
You can go here to see how to use Application in Android.
Lastly, it looks like your still creating your ViewHolder every time instead of only when convertView is null. I would review this video to get the whole picture. http://www.google.com/events/io/2010/sessions/world-of-listview-android.html
Here is an example of how I use the ViewHolder method:
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null || convertView.getTag() == null){
convertView = inflater.inflate(R.layout.list_item, parent, false);
holder = new ViewHolder();
holder.text1 = (TextView)convertView.findViewById(R.id.list_item_text1);
holder.text2 = (TextView)convertView.findViewById(R.id.list_item_text2);
holder.text1.setTypeface(YourApp.Fonts.THEOREM); // only happens once when recycling!
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.text1.setText("someText");
holder.text2.setText("someText");
return convertView;
}
You can try to free the resources if convertView != null. if it is you could find your Views and null them. You could also try to get the Bitmap of your ImageView and recycle it.
you could also add your ViewHolder as a member to your RecipeInstructionsListViewAdapter and instantiate it once in constructor.