J'ai une simple vue de liste avec un adaptateur. Je crée 10+ éléments de la liste dynamiquement. Puis je fais défiler vers le haut et vers le bas, encore et encore et encore..... Je peux voir que la mémoire disponible ne cesse de diminuer...
Où dois-je libérer et quoi ? Note - il y a une imageview - mais dans mon test je n'ai pas utilisé d'images donc c'est View.GONE.
De plus, avec quel outil puis-je profiler l'utilisation de la mémoire sur Android ? J'ai trouvé votre kit, mais comment le configurer pour Android (je lance l'application sur l'appareil) ?
La classe Activité
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();
}
}
La classe d'adaptateur
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;
}
}