When I am trying to use the drop down list of a spinner, the option doesn't select, I was investigating in Google and I think I am configuring the spinner correctly for cities but maybe I have forgotten something in the adapter. I am using a CustomAdapter.
My fragment is:
In the Fragment call I have this code:
ArrayList<ItemPair> data1 = IAndroid.getAllCities();
Spinner spCity = (Spinner) rootView.findViewById(R.id.spPoblacion);
spCity.setAdapter(new ItemPairListAdapter(inflater.getContext(), data1));
At the moment I don't have the select click item associated, I only set all items in dropdownlist.
My fragment.xml is:
<Spinner
android:id="#+id/spProvincia"
android:layout_width="wrap_content"
android:clickable="true"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/textView1" />
My Custom Adapter is:
package info.android.adapter;
import info.android.MainActivity;
import info.android.R;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
public class ItemPairListAdapter extends BaseAdapter implements SpinnerAdapter {
private Context context;
private ArrayList<info.android.model.ItemPair> navProOffers;
public ItemPairListAdapter(Context context, ArrayList<info.android.model.ItemPair> navProOffers) {
this.context = context;
this.navProOffers = navProOffers;
}
#Override
public int getCount() {
return navProOffers.size();
}
#Override
public info.android.model.ItemPair getItem(int position) {
return navProOffers.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.fragment_row_itempair, null);
}
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
});
TextView txtKey = (TextView) convertView.findViewById(R.id.txtKey);
TextView txtValue = (TextView) convertView.findViewById(R.id.txtValue);
info.android.model.ItemPair ip = getItem(position);
if (ip != null)
{
if (ip.Key != null) txtKey.setText(ip.Key);
if (ip.Value != null) txtValue.setText(ip.Value);
}
convertView.setTag(ip.Key);
return convertView;
}
}
My ItemPair class is:
package info.android.model;
public class ItemPair {
public String Key;
public String Value;
}
What is wrong? What do I need to simulate the click behaviour and afterwards receive my item?
I removed click listener in the getView, answered it for G.T.
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.fragment_row_itempair, null);
}
TextView txtKey = (TextView) convertView.findViewById(R.id.txtKey);
TextView txtValue = (TextView) convertView.findViewById(R.id.txtValue);
info.android.model.ItemPair ip = getItem(position);
if (ip != null)
{
if (ip.Key != null) txtKey.setText(ip.Key);
if (ip.Value != null) txtValue.setText(ip.Value);
}
convertView.setTag(ip.Key);
return convertView;
}
Related
So I am working on a list view, and I want to implement a delete button. But for some reason, whenever I press the delete button on any list item whatsoever, the last item in the list gets deleted automatically. I tried out almost everything, but I am unable to understand how I can know the index of the item where the button was clicked so I can easily just delete that particular item.
This is the code :
// full subtask adapter code
package com.example.taskmasterv3;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
public class SubtaskAdapter extends ArrayAdapter<subtask> {
private final Context context;
private ArrayList<subtask> values;
public SubtaskAdapter(Context context, ArrayList<subtask> list) {
//since your are using custom view,pass zero and inflate the custom view by overriding getview
super(context, 0 , list);
this.context = context;
this.values = list;
}
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
//check if its null, if so inflate it, else simply reuse it
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.subtask_item, parent, false);
}
//use convertView to refer the childviews to populate it with data
TextView tvSubtaskName = convertView.findViewById(R.id.tvSubtaskName);
ImageView ivPri = convertView.findViewById(R.id.ivPri);
ImageView ivTime = convertView.findViewById(R.id.ivTime);
ImageView ivDelete = convertView.findViewById(R.id.ivDelete);
tvSubtaskName.setText(values.get(position).getSubtaskName());
if (values.get(position).isPriHigh()) {
ivPri.setImageResource(R.drawable.priority_high);
} else if (values.get(position).isPriMed()) {
ivPri.setImageResource(R.drawable.priority_med);
} else if (values.get(position).isPriLow()) {
ivPri.setImageResource(R.drawable.priority_low);
}
if (values.get(position).isTimeMore()) {
ivTime.setImageResource(R.drawable.time_symbol_more);
} else if (values.get(position).isTimeMed()) {
ivTime.setImageResource(R.drawable.time_symbol_med);
} else if (values.get(position).isTimeLess()) {
ivTime.setImageResource(R.drawable.time_symbol_less);
}
// Delete button for subtasks (NOT WORKING)
ivDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SubtaskAdapter.this.remove(SubtaskAdapter.this.getItem(position));
notifyDataSetChanged();
}
});
//return the view you inflated
return convertView;
}
//to keep adding the new subtasks try the following
public void addANewSubTask(subtask newSubTask){
ArrayList<subtask> newvalues = new ArrayList<>(this.values);
newvalues.add(newSubTask);
this.values = newvalues;
notifyDataSetChanged();
}
}
ivDelete.setOnClickListener(new View.OnClickListener() {
Change that to:
ivDelete.setOnClickListener(new View.OnClickListener() {
ivDelete.setTag(position);
public void onClick(View v) {
Change to:
public void onClick(View v) {
// int position = v.getTag();
int position = (Integer)v.getTag();
Try to use below code :
ivDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
values .remove(position);
notifyDataSetChanged();
//SubtaskAdapter.this.remove(SubtaskAdapter.this.getItem(position));
//notifyDataSetChanged();
}
});
My code has an ExpandableListView and each child (schedule) can be deleted via a delete button in the child. I want to use a functionality of "Edit" TextView so that if the user clicks on "Edit" the Delete Buttons will be visible. I tried it on my custom adapter MainAdapter but gives me crashes. Could anyone help me?
MainAdapter.java
package com.example.easyplan;
import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import java.util.HashMap;
import java.util.List;
public class MainAdapter extends BaseExpandableListAdapter {
private Context _context;
private List<String> listPlan; // header titles
// child data in format of header title, child title
private HashMap<String, List<String>> listScheduleMap;
ImageButton scheduleDeleteBtn;
public MainAdapter(Context context, List<String> listDataHeader,
HashMap<String, List<String>> listChildData) {
this._context = context;
this.listPlan = listDataHeader;
this.listScheduleMap = listChildData;
}
#Override
public Object getChild(int groupPosition, int childPosititon) {
return this.listScheduleMap.get(this.listPlan.get(groupPosition))
.get(childPosititon);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public View getChildView(final int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final String childText = (String) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.schedule_group, null);
}
TextView txtListChild = (TextView) convertView
.findViewById(R.id.scheduleGroup);
scheduleDeleteBtn = convertView.findViewById(R.id.scheduleDeleteBtn);
scheduleDeleteBtn.setVisibility(View.INVISIBLE);
scheduleDeleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
List<String> plan = listScheduleMap.get(listPlan.get(groupPosition));
plan.remove(childPosition);
notifyDataSetChanged();
}
});
txtListChild.setText(childText);
return convertView;
}
#Override
public int getChildrenCount(int groupPosition) {
return this.listScheduleMap.get(this.listPlan.get(groupPosition))
.size();
}
#Override
public Object getGroup(int groupPosition) {
return this.listPlan.get(groupPosition);
}
#Override
public int getGroupCount() {
return this.listPlan.size();
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.plan_group, null);
}
TextView lblListHeader = (TextView) convertView
.findViewById(R.id.planGroup);
lblListHeader.setTypeface(null, Typeface.BOLD);
lblListHeader.setText(headerTitle);
return convertView;
}
#Override
public boolean hasStableIds() {
return false;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public void setDeleteVisibility(boolean visible){
for(int j = 0; j < getGroupCount(); j ++){
for(int i = 0; i<getChildrenCount(i); i++ ){
if(visible){
scheduleDeleteBtn.setVisibility(View.VISIBLE);
}else{
scheduleDeleteBtn.setVisibility(View.INVISIBLE);
}
}
}
}
}
PlansFragment.java
package com.example.easyplan;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageButton;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* A simple {#link Fragment} subclass.
*/
public class PlansFragment extends Fragment {
TextView editText;
MainAdapter mainAdapter;
ExpandableListView planExplandable;
List<String> listPlanName;
HashMap<String, List<String>> listSchedules;
TextView textView;
static int count = 0;
View view;
public PlansFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_plans_fragment, container, false);
listPlanName = new ArrayList<String>();
listSchedules = new HashMap<String, List<String>>();
// get the listview
planExplandable = (ExpandableListView) view.findViewById(R.id.plansExpandable);
textView = view.findViewById(R.id.scheduleGroup);
editText = view.findViewById(R.id.planEditText);
// preparing list data
// prepareListData();
createAPlan(3);
createAPlan(1);
createAPlan(3);
createAPlan(4);
mainAdapter = new MainAdapter(getActivity(), listPlanName, listSchedules);
// setting list adapter
planExplandable.setAdapter(mainAdapter);
//mainAdapter.setDeleteVisibility(false);
/* editText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mainAdapter.setDeleteVisibility(true);
}
});*/
return view;
}
public HashMap<String, String> getData(){
return null;
}
private void createAPlan(int sch){
listPlanName.add("Plan#"+(count+1));
List<String> schedules = new ArrayList<String>();
if(sch > 0 ){
for (int i = 1; i <= sch; i++){
schedules.add("Schedule#" + i);
}
}
listSchedules.put(listPlanName.get(count),schedules);
count++;
}
}
The child's xml has
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.8">
<TextView
android:id="#+id/scheduleGroup"
android:layout_width="355dp"
android:layout_height="wrap_content"
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:textColor="#android:color/black" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.2">
<ImageButton
android:id="#+id/scheduleDeleteBtn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:srcCompat="#drawable/delete_icon"
android:visibility="visible"
android:clickable="true"
></ImageButton>
</LinearLayout>
Inside your fragment use setOnItemClickListener() method on your listView and in overriden method make use of getFirstVisiblePosition() to subtract from the position where you will find the position of that view. then set the visibility.
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
listPosition = position - planExplandable.getFirstVisiblePosition();
if (planExplandable.getChildAt(listPosition).findViewById(R.id.yourview).getVisibility() == View.INVISIBLE) {
//Write your logic here
planExplandable.getChildAt(listPosition).findViewById(R.id.yourview).setVisibility(View.VISIBLE);
}
}
If this won't help then please paste your crash log.
I'm trying to create nested listviews in multiple fragments using adapter. I'm able to create it in single activity but I couldn't do it in fragments using adapter. Refer second fragment as fragment2 and second list as listview2.
package com.example.admin.volleyrequestandresponse.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.example.admin.volleyrequestandresponse.R;
import com.example.admin.volleyrequestandresponse.activities.NavigationActivity;
import com.example.admin.volleyrequestandresponse.fragments.HomeFragment;
import java.util.ArrayList;
public class HomeFragmentAdapter extends BaseAdapter {
private ArrayList<String> stringArray;
private ArrayList<String> integerArray;
int[] logos;
Context context;
NavigationActivity navigationActivity;
public HomeFragmentAdapter(Context context, ArrayList<String> stringArray, ArrayList<String> integerArray, int[] logos) {
this.context = context;
this.stringArray = stringArray;
this.integerArray = integerArray;
this.logos = logos;
navigationActivity = new NavigationActivity();
}
#Override
public int getCount() {
return integerArray.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.home_adapter, null);
holder = new ViewHolder();
holder.imageview = (ImageView) convertView.findViewById(R.id.indeximg);
holder.txtTitle = (TextView) convertView.findViewById(R.id.indexname);
holder.text = (TextView) convertView.findViewById(R.id.indexvalue);
holder.relativeLayout = (RelativeLayout) convertView.findViewById(R.id.home_adapter);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.imageview.setImageResource(logos[position]);
holder.txtTitle.setText(stringArray.get(position));
holder.text.setText(integerArray.get(position));
return convertView;
}
private class ViewHolder {
RelativeLayout relativeLayout;
TextView text;
TextView txtTitle;
ImageView imageview;
}
}
Fragment code to call the adapter
homeFragmentAdapter = new HomeFragmentAdapter(getActivity(),index_string,index_values,index_logo);
listview_HomeFragment.setAdapter(homeFragmentAdapter);
So what I want to do is have a different image for each list item in my App. I've been attempting to do this for a little while now and have no idea what I'm doing.
Here's what I'm trying to do:
How do I go about this? Here's my current code:
package net.androidbootcamp.gamesandcoffee;
import android.app.ListActivity;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class MainActivity extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[ ] attraction = {"Games", "Coffee Shops"};
setListAdapter(new ArrayAdapter<String>(this, R.layout.activity_main, R.id.games, attraction));
}
protected void onListItemClick(ListView l, View v, int position, long id) {
switch (position) {
case 0:
startActivity(new Intent(MainActivity.this, games.class));
break;
case 1:
startActivity(new Intent(MainActivity.this, coffee.class));
break;
}
}
}
and my XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/games"
android:textSize="20sp"
android:text="#+id/games"
android:drawableLeft="#drawable/games"/>
</RelativeLayout>
For that you have to create a custom adapter, where you can customize all the ListView items.
public class ListAdapter extends ArrayAdapter<Item> {
public ListAdapter(Context context, int imageViewResourceId) {
super(context, imageViewResourceId);
}
public ListAdapter(Context context, int resource, List<Item> items) {
super(context, resource, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.itemlistrow, null);
}
Item p = getItem(position);
if (p != null) {
ImageView iv = (ImageView ) v.findViewById(R.id.id);
if (iv != null) {
iv .setImageResource(R.id.xyz);
}
}
return v;
}
}
load the image resource id's to the array and pass to the list adapter in this way
int[] images = {R.drawables.firstimg,R.drawables.secondimg};
setListAdapter(new CustomAdapter(this,images, attraction));
Crate CustomAdapter Class
public class CustomAdapter extends BaseAdapter{
private Context context;
int[] images;
String[] textdata;
public CustomAdapter(Context context, int[] images,String[] textdata) {
this.context = context;
this.images=images;
this.textdata=textdata;
}
#Override
public Object getItem(int position) {
return textdata.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = null;
if (convertView == null){
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = layoutInflater.inflate(R.layout.drawer_listitem,parent,false);
}else {
row = convertView;
}
TextView name = (TextView) row.findViewById(R.id.draweritemtext);
ImageView image = (ImageView) row.findViewById(R.id.draweritemimage);
name.setText(textdata[position]);
image.setImageResource(images[position]);
return row;
}
#Override
public int getCount() {
return textdata.size();
}
}
Following these two video tutorials, geared towards beginners, I was able to arrive to my desired result. Thank you those who contributed, but none of the answers or resources provided were geared towards beginners that lack experience.
These are the videos I watched
Android Studio Tutorial - 18 - ListView with Custom Adapter part-1
Android Studio Tutorial - 19 - ListView with Custom Adapter part-2
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.