There are two weird glitches in my app
When using Listview, when I scroll down fast and up again, the first Item changes.
I didn't implement anything that would cause this, is it a glitch with
Listview?
When updating the Listview, it fetches the data and when it goes to update it, it does the first 12 items right, then repeats them them again, then the first six again (for the total number of dorms)
I can't find the a reason it repeated at 12 specifically here's my code
MainActivity class:
public class MainActivity extends AppCompatActivity {
private Button btnGetData;
private final String URL = "https://www.laundryalert.com/cgi-bin/urba7723/LMPage?Login=True";
private List<DormMachines> dorms;
private BaseAdapterDorm dormsAdapter;
private ListView dormsList;
private ProgressDialog mProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set click listener for button
btnGetData = (Button) findViewById(R.id.btnContent);
btnGetData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new GetContent().execute();
}
}); dorms = new ArrayList<DormMachines>();
dormsList = (ListView) findViewById(R.id.myListView);
dormsAdapter = new BaseAdapterDorm(dorms, this);
dormsList.setAdapter(dormsAdapter);
setupListViewListener();
}
private void setupListViewListener() {
dormsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
dorms.remove(position);
dormsAdapter.notifyDataSetChanged();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
private class GetContent extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setTitle("Getting Content");
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
dorms.clear();
try {
Document doc = Jsoup.connect(URL).get();
Element table = doc.getElementById("tableb");
Elements rows = table.getElementsByTag("tr");
// Removes table headers and whitespace at end
rows.remove(0);
rows.remove(0);
rows.remove(30);
for(Element row : rows) {
int index = 0;
DormMachines dorm = new DormMachines();
for (Element rowData : row.getElementsByTag("td")) {
switch (index) {
case 1:
// Dorm Name
dorm.dormName = rowData.text();
break;
case 2:
// Washers Free
dorm.washersFree = Integer.parseInt(rowData.text());
break;
case 3:
// Dryers Free
dorm.dryersFree = Integer.parseInt(rowData.text());
break;
case 5:
// Washers in Use
dorm.washersInUse = Integer.parseInt(rowData.text());
break;
case 7:
// Dryers In Use
dorm.dryersInUse = Integer.parseInt(rowData.text());
break;
default:
break;
}
index++;
}
dorms.add(dorm);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
dormsAdapter.notifyDataSetChanged();
mProgressDialog.dismiss();
}
}
}
BaseAdapterDorm class:
public class BaseAdapterDorm extends BaseAdapter {
private List<DormMachines> list;
private LayoutInflater layoutInflater;
public BaseAdapterDorm(List<DormMachines> list, Context context) {
this.list = list;
this.layoutInflater =(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
DormViewHolder dormViewHolder;
if(view == null) {
view = layoutInflater.inflate(R.layout.listview_dorm_item, parent, false);
dormViewHolder = new DormViewHolder();
dormViewHolder.textViewDormName = (TextView) view.findViewById(R.id.list_item_dorm_item_name);
dormViewHolder.textViewWasherAvail = (TextView) view.findViewById(R.id.list_item_washers_avail);
dormViewHolder.textViewWasherOccupied = (TextView) view.findViewById(R.id.list_item_washer_occupied);
dormViewHolder.textViewDryersAvail = (TextView) view.findViewById(R.id.list_item_dryers_avail);
dormViewHolder.textViewDryersOccupied = (TextView) view.findViewById(R.id.list_item_dryers_occupied);
dormViewHolder.textViewDormName.setText(list.get(position).dormName);
dormViewHolder.textViewWasherAvail.setText(""+list.get(position).washersFree);
dormViewHolder.textViewWasherOccupied.setText(""+list.get(position).washersInUse);
dormViewHolder.textViewDryersAvail.setText(""+list.get(position).dryersFree);
dormViewHolder.textViewDryersOccupied.setText(""+list.get(position).dryersInUse);
}
return view;
}
static class DormViewHolder {
TextView textViewDormName;
TextView textViewWasherAvail;
TextView textViewWasherOccupied;
TextView textViewDryersAvail;
TextView textViewDryersOccupied;
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:padding="8sp"
tools:context="com.sergiodlz.jsoupexample.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Get data"
android:id="#+id/btnContent"/>
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="0sp"
android:id="#+id/myListView"
android:layout_weight="1">
</ListView>
</LinearLayout>
The rest is on Github
ListAdapters recycle their views (these views being the "entries" in the list). The number of views is arbitrary as far as we are usually concerned, but in this instance it is probably 12.
The idea is this... Once that arbitrary number of views has been created ( meaning all views have hit this if(view == null){...create/initialize} ), then every time you get a view at position Y, you will need to replace the contents of the view at position Y, otherwise you will see the content of the original entry that got slapped on that view.
Now to fix your problem, do something like this:
public View getView(int position, View view, ViewGroup parent) {
DormViewHolder dormViewHolder;
if(view == null) {
view = layoutInflater.inflate(R.layout.listview_dorm_item, parent, false);
dormViewHolder = new DormViewHolder();
dormViewHolder.textViewDormName = (TextView) view.findViewById(R.id.list_item_dorm_item_name);
dormViewHolder.textViewWasherAvail = (TextView) view.findViewById(R.id.list_item_washers_avail);
dormViewHolder.textViewWasherOccupied = (TextView) view.findViewById(R.id.list_item_washer_occupied);
dormViewHolder.textViewDryersAvail = (TextView) view.findViewById(R.id.list_item_dryers_avail);
dormViewHolder.textViewDryersOccupied = (TextView) view.findViewById(R.id.list_item_dryers_occupied);
// Set the View Tag with the ViewHolder to save View properties.
view.setTag(dormViewHolder);
}
else
{
// Recycle the view (all View properties already set).
dormViewHolder = (DormViewHolder) view.getTag();
}
dormViewHolder.textViewDormName.setText(list.get(position).dormName);
dormViewHolder.textViewWasherAvail.setText(""+list.get(position).washersFree);
dormViewHolder.textViewWasherOccupied.setText(""+list.get(position).washersInUse);
dormViewHolder.textViewDryersAvail.setText(""+list.get(position).dryersFree);
dormViewHolder.textViewDryersOccupied.setText(""+list.get(position).dryersInUse);
return view;
}
This is a well known issue in android, to overcome this you need to use viewholder inside your list view. The reason why it happens is because the list view recycles the views which causes this to happen
Related
This question already has answers here:
getLayoutInflater() in fragment
(5 answers)
Closed 4 years ago.
I'm trying to code an app that downloads data of some events from an online MySQL database and writes it into my android app. Right now, what i'm trying to do is just testing if downloading the name of the event works, but i keep getting this error:
java.lang.NoSuchMethodError: No virtual method getLayoutInflater()Landroid/view/LayoutInflater; in class Lcom/suspicio/appfisio_business/FrammentoCorsi; or its super classes (declaration of 'com.suspicio.appfisio_business.FrammentoCorsi' appears in /data/app/com.suspicio.appfisio_business-1/split_lib_slice_8_apk.apk)
at com.suspicio.appfisio_business.FrammentoCorsi$EventoAdapter.getView(FrammentoCorsi.java:204)
which points to the line:
listViewItem = getLayoutInflater().inflate(R.layout.frammento_corsi, null, true);
Here's my code (it's a fragment):
FrammentoCorsi.java:
public class FrammentoCorsi extends Fragment {
public static final int CODE_GET_REQUEST = 1024;
public static final int CODE_POST_REQUEST = 1025;
public FrammentoCorsi() { //Vuoto
}
boolean isUpdating = false;
View rootView;
List<Evento> eventoList;
ListView listView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.frammento_corsi, container, false);
listView = (ListView) rootView.findViewById(R.id.listViewEventi);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
eventoList = new ArrayList<>();
readEventi();
}
private void readEventi() {
PerformNetworkRequest request = new PerformNetworkRequest(Api.URL_READ_EVENTI, null, CODE_GET_REQUEST);
request.execute();
}
private void refreshEventoList(JSONArray eventi) throws JSONException {
//clearing previous heroes
eventoList.clear();
//traversing through all the items in the json array
//the json we got from the response
for (int i = 0; i < eventi.length(); i++) {
//getting each hero object
JSONObject obj = eventi.getJSONObject(i);
//adding the hero to the list
eventoList.add(new Evento(
obj.getInt("id"),
obj.getString("titolo"),
obj.getString("inizio"),
obj.getString("fine"),
obj.getInt("categoria"),
obj.getString("link"),
obj.getString("luogo")
));
}
//creating the adapter and setting it to the listview
EventoAdapter adapter = new EventoAdapter(eventoList);
listView.setAdapter(adapter);
}
//inner class to perform network request extending an AsyncTask
public class PerformNetworkRequest extends AsyncTask<Void, Void, String> {
//the url where we need to send the request
String url;
//the parameters
HashMap<String, String> params;
//the request code to define whether it is a GET or POST
int requestCode;
ProgressBar barra = (ProgressBar) getView().findViewById(R.id.progressBar);
//constructor to initialize values
PerformNetworkRequest(String url, HashMap<String, String> params, int requestCode) {
this.url = url;
this.params = params;
this.requestCode = requestCode;
}
//when the task started displaying a progressbar
#Override
protected void onPreExecute() {
super.onPreExecute();
barra.setVisibility(View.VISIBLE);
}
//this method will give the response from the request
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
barra.setVisibility(View.INVISIBLE);
try {
JSONObject object = new JSONObject(s);
if (!object.getBoolean("error")) {
Toast.makeText(getActivity().getApplicationContext(), object.getString("message"), Toast.LENGTH_SHORT).show();
refreshEventoList(object.getJSONArray("eventi"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
//the network operation will be performed in background
#Override
protected String doInBackground(Void... voids) {
RequestHandler requestHandler = new RequestHandler();
if (requestCode == CODE_POST_REQUEST)
return requestHandler.sendPostRequest(url, params);
if (requestCode == CODE_GET_REQUEST)
return requestHandler.sendGetRequest(url);
return null;
}
}
class EventoAdapter extends ArrayAdapter<Evento> {
List<Evento> eventoList;
//constructor to get the list
public EventoAdapter(List<Evento> eventoList) {
super(getActivity(), R.layout.frammento_corsi, eventoList);
this.eventoList = eventoList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listViewItem = convertView;
if (listViewItem == null) {
listViewItem = getLayoutInflater().inflate(R.layout.frammento_corsi, null, true);
}
//getting the textview for displaying name
TextView textViewName = listViewItem.findViewById(R.id.nomeeventocalendario);
//the update and delete textview
//ImageView textViewUpdate = listViewItem.findViewById(R.id.notifica);
//ImageView textViewDelete = listViewItem.findViewById(R.id.link);
final Evento evento = eventoList.get(position);
textViewName.setText(evento.getTitolo());
return listViewItem;
}
}
}
And its resource file frammento_corsi.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.suspicio.appfisio_business.FrammentoCorsi">
<ListView
android:id="#+id/listViewEventi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/nomeeventocalendario"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:visibility="gone"/>
</FrameLayout>
Can you help me out?
Thanks in advance!
Use this
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
listViewItem = layoutInflater.inflate(R.layout.frammento_corsi, null ,true);
Instead of this
listViewItem = getLayoutInflater().inflate(R.layout.frammento_corsi, null, true);
I'm very new to android and I was given a prewritten app that I must improve. One thing I have to do is add a delete button to each item in a ListView.
Here is the XML for my ListView element:
LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal" >
<ImageView
android:id="#+id/li_map_image"
android:layout_width="50dp"
android:layout_height="match_parent"
android:contentDescription="thumbnail" />
<TextView
android:id="#+id/li_map_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:paddingLeft="8dp"
android:textSize="16sp" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/delete"
android:focusableInTouchMode="true"
android:background="#drawable/red_x"
android:layout_gravity="center|left"
android:onClick="deleteMap"></ImageButton>
Basically, I want the user to click the delete icon if they want to delete a row in the ListView. Also, this should delete the item's data from the database. I'm very confused about how to implement this because I don't know how I will know which delete button they are clicking. Also, when I added the ImageButton to the ListView code, it tells me to make the onClick method in main (should it be in main?); but how will I be able to delete data from the database? Also, Main Activity has a Fragment which obtains the ListView code. This is the Fragment class:
public class MapListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
private static final int LOADER_ID = 1;
private static final String[] FROM = { Database.Maps.DATA,
Database.Maps.NAME };
private static final String[] CURSOR_COLUMNS = { Database.Maps.ID,
Database.Maps.DATA, Database.Maps.NAME };
private static final int[] TO = { R.id.li_map_image, R.id.li_map_name };
private SimpleCursorAdapter mAdapter;
// FIXME isn't this unnecessary?
public MapListFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// FIXME reverse the order so the newest sessions are at the top
mAdapter = new SimpleCursorAdapter(getActivity(),
R.layout.map_list_item, null, FROM, TO, 0);
mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor,
int columnIndex) {
if (view.getId() == R.id.li_map_image) {
((ImageView) view).setImageURI(Uri.parse(cursor
.getString(columnIndex)));
return true;
}
return false;
}
});
setListAdapter(mAdapter);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public void onListItemClick(ListView list, View v, int position, long id) {
final Intent nextIntent = new Intent(getActivity(),
ViewMapActivity.class);
nextIntent.putExtra(Utils.Constants.MAP_ID_EXTRA, id);
startActivity(nextIntent);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getActivity(), DataProvider.MAPS_URI,
CURSOR_COLUMNS, null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (loader.getId() == LOADER_ID)
mAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
I'm very lost as how to implement this delete feature. Any help will be much appreciated :)
here is a very good tutorial on how to put a clicklistener on a button inside listview.
follow this link
inside your adapter getView method, you need to put click listener on button like this
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.child_listview, null);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) convertView
.findViewById(R.id.childTextView);
viewHolder.button = (Button) convertView
.findViewById(R.id.childButton);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final String temp = getItem(position);
viewHolder.text.setText(temp);
viewHolder.button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
customListner.onButtonClickListner(position,temp);
}
}
});
return convertView;
}
Add Longclicklistner in Your Listview
try this , it may help you
Link
I have a row which is represented by an image, some text and a CheckBoxes. Whenever I'm trying to use the OnItemClickListener for the rows, the event won't fire up when clicking the CheckBoxes.
I also tried checkbox.onCheckedChangedListener but it gives me Null Pointer at findViewByID. I checked, the ID I am looking for is alright, no typos in there.
I'd like to make usage of this OnItemClickListener so later on I can play with the checkboxes. Any ideas?
Code:
ADAPTER:
public class FilterAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<String> mFilters;
private ArrayList<Integer> mPictures;
private Typeface Bebas, DroidSans;
public FilterAdapter(Context context, ArrayList<String> filters, ArrayList<Integer> pictures) {
this.mContext = context;
this.mFilters = filters;
this.mPictures = pictures;
}
#Override
public int getCount() {
return mFilters.size();
}
#Override
public Object getItem(int position) {
return mFilters.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)
mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.category_filter_item, null);
}
DroidSans = Typeface.createFromAsset(mContext.getAssets(), "fonts/DroidSans.ttf");
ImageView filter_img = (ImageView) convertView.findViewById(R.id.category_picture);
TextView filter_category = (TextView) convertView.findViewById(R.id.filter_category);
CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.check_box);
filter_category.setTypeface(DroidSans);
filter_category.setText(mFilters.get(position));
filter_img.setBackgroundResource(mPictures.get(position));
return convertView;
}
}
Class where using the Adapter:
public class CheckinFilters extends Fragment {
private ListView mListView;
private FilterAdapter filterAdapter;
private ArrayList<String> l = new ArrayList<String>();
private ArrayList<Integer> drawables = new ArrayList<Integer>();
private Typeface Bebas;
private ArrayList<Integer> checkboxes = new ArrayList<Integer>();
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
public CheckinFilters() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_checkin_filters, container, false);
l.add("Chill");
l.add("Eat");
l.add("Explore");
l.add("Move");
l.add("Party");
l.add("Whatever");
drawables.add(R.drawable.category_chill);
drawables.add(R.drawable.category_eat);
drawables.add(R.drawable.category_explore);
drawables.add(R.drawable.category_move);
drawables.add(R.drawable.category_party);
drawables.add(R.drawable.category_whatever);
mListView = (ListView) view.findViewById(R.id.filter_list);
filterAdapter = new FilterAdapter(view.getContext(), l, drawables);
mListView.setAdapter(filterAdapter);
sharedPreferences = getActivity().getPreferences(Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
Bebas = Typeface.createFromAsset(view.getContext().getAssets(), "fonts/BebasNeue.otf");
TextView mainHeader = (TextView) view.findViewById(R.id.filters_text);
mainHeader.setTypeface(Bebas);
SearchView filter_categories = (SearchView) view.findViewById(R.id.filter_categories);
int searchImgID = getResources().getIdentifier("android:id/search_button", null, null);
ImageView searchViewHint = (ImageView) filter_categories.findViewById(searchImgID);
searchViewHint.setImageResource(R.drawable.ab_icon_search);
int searchPlateID = filter_categories.getContext().getResources().getIdentifier("android:id/search_plate", null, null);
View searchPlateView = filter_categories.findViewById(searchPlateID);
if (searchPlateView != null) {
searchPlateView.setBackgroundResource(R.drawable.search_location_shape);
}
int searchViewID = filter_categories.getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
TextView textView = (TextView) filter_categories.findViewById(searchViewID);
textView.setTextColor(Color.GRAY);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.check_box);
return view;
}
private void save() {
sharedPreferences = getActivity().getPreferences(Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
editor.putInt("first", checkboxes.size());
for (int i = 0; i < checkboxes.size(); i++) {
editor.remove("Status_" + i);
editor.putInt("Status_" + i, checkboxes.get(i));
}
editor.commit();
}
private void load() {
sharedPreferences = getActivity().getPreferences(Context.MODE_PRIVATE);
int size = sharedPreferences.getInt("first", 0);
for (int i = 0; i < size; i++) {
checkboxes.add(sharedPreferences.getInt("Status_" + i, 0));
}
}
#Override
public void onPause() {
super.onPause();
save();
}
#Override
public void onResume() {
super.onResume();
load();
}
}
Layout I'm inflating for Adapter:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#ECF0F1">
<ImageView
android:id="#+id/category_picture"
android:layout_width="70dp"
android:layout_height="60dp"
android:background="#drawable/sm_profile"/>
<TextView
android:id="#+id/filter_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/category_picture"
android:padding="10dp"
android:text="Party"
android:textColor="#color/enloop_dark_gray"
android:textSize="18dp"/>
<CheckBox
android:id="#+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:focusable="false"
android:focusableInTouchMode="false"
android:padding="10dp"/>
</RelativeLayout>
</RelativeLayout>
Instead of using OnItemClickListener in CheckinFilters.java, you should add that code in getView() method of FilterAdapter. You are actually adding checkbox for every row but the id for all checkbox is same, so you can't apply customized code for every checkbox.
To be able to make use of all checkboxes you can put checkbox code in getView() method because it also contains an argument called position. So you can just get the position and apply OnItemClickListener to every single checkbox. That way it will work.
public class FilterAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<String> mFilters;
private ArrayList<Integer> mPictures;
private Typeface Bebas, DroidSans;
public FilterAdapter(Context context, ArrayList<String> filters, ArrayList<Integer> pictures) {
this.mContext = context;
this.mFilters = filters;
this.mPictures = pictures;
}
#Override
public int getCount() {
return mFilters.size();
}
#Override
public Object getItem(int position) {
return mFilters.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)
mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.category_filter_item, null);
}
DroidSans = Typeface.createFromAsset(mContext.getAssets(), "fonts/DroidSans.ttf");
ImageView filter_img = (ImageView) convertView.findViewById(R.id.category_picture);
TextView filter_category = (TextView) convertView.findViewById(R.id.filter_category);
CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.check_box);
filter_category.setTypeface(DroidSans);
filter_category.setText(mFilters.get(position));
filter_img.setBackgroundResource(mPictures.get(position));
if(position == 0) {
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked)
else {
}
}
});
}
//Similarly add OnClickListener to other checkboxes.
return convertView;
}
}
I have a ListViewwhich has a custom cell in it with 2 buttons, a label and an editText. I've got it so that when I click the button for the custom cell it does a log saying at what position the button has been pressed. However I can't work out how I make it so when I press the button, it changes the text in the textbox for that cell. I can't work out how to reference it at a position.
My XML is:
<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" >
<ListView
android:id="#+id/lvItems"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:drawSelectorOnTop="false" >
</ListView>
</RelativeLayout>
My Code:
class CustomAdapter extends BaseAdapter
{
#Override
public int getCount() {
return mDescription.size();
}
#Override
public Object getItem(int arg0) {
return null;
}
#Override
public long getItemId(int arg0) {
return 0;
}
#Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
LayoutInflater inf=getLayoutInflater();
View v=inf.inflate(R.layout.noncriticalasset, arg2,false);
TextView tv=(TextView)v.findViewById(R.id.txtOption);
final EditText et =(EditText)v.findViewById(R.id.tbAnswer);
Button btPlus=(Button)v.findViewById(R.id.btnPlus);
Button btMinus=(Button)v.findViewById(R.id.btnMinus);
btMinus.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
int position = listView
.getPositionForView((View) v.getParent());
Log.v("Position id", "" + position);
et.setText("Test Text");
notifyDataSetChanged();
} catch (Exception e) {
Log.e("error", "error" + e.getMessage());
}
}
});
tv.setText(mDescription.get(arg0).toString());
return v;
}
I tried referencing the textbox with just an et.setText() but it didn't work. Is there a way to say atPosisiton.et.setText etc?
Thanks a lot.
First of all I would insist you to use recycling pattern of ListView, which will work faster as it reduces the creation of the ListView row item views everytime when ListView scroll and re-uses the already created/instantiated view. And for maintaining the value of EditText/CheckBox you have to use setTag() for maintaining its position when ListView scrolls. I had written a blog post for the same here.
hi declare Button in Adapter not in get view and ViewHolder. like below
Button btPlus,btMinus;
ViewHolder holder ;
class ViewHolder {
int fieldPossition;
}
#Override
public View getView(int position, View v, ViewGroup arg2) {
holder = new ViewHolder();
LayoutInflater inf=getLayoutInflater();
v=inf.inflate(R.layout.noncriticalasset, arg2,false);
TextView tv=(TextView)v.findViewById(R.id.txtOption);
EditText et =(EditText)v.findViewById(R.id.tbAnswer);
btPlus=(Button)v.findViewById(R.id.btnPlus);
btMinus=(Button)v.findViewById(R.id.btnMinus);
fieldPossition = position;
btMinus.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
ViewHolder deleteHolder = (ViewHolder) v.getTag();
//
int pos = deleteHolder.fieldpossition;
Log.v("Position id", "" + position);
et.setText("Test Text");
notifyDataSetChanged();
} catch (Exception e) {
Log.e("error", "error" + e.getMessage());
}
}
});
tv.setText(mDescription.get(position).toString());
btMinus.setTag(holder);
return v;
}
thats it .
Actually the position you got is right,but with notifyDataSetChanged() called, ListView will use getView() method to replace all item views with new ones.
So,you should keep the clicked position somewhere ,and setup the EditText in getView().
EDIT Tested OK
LazyViewHolder.class
public class LazyViewHolder {
private EditText et;
private TextView text;
private Button btnSub;
public LazyViewHolder() {
// TODO Auto-generated constructor stub
}
LazyViewHolder(TextView textView,EditText ed,Button btn) {
super();
this.setEt(ed);
this.setText(textView);
this.setBtnSub(btn);
}
public EditText getEt() {
return et;
}
public void setEt(EditText et) {
this.et = et;
}
public TextView getText() {
return text;
}
public void setText(TextView text) {
this.text = text;
}
public Button getBtnSub() {
return btnSub;
}
public void setBtnSub(Button btnSub) {
this.btnSub = btnSub;
}
}
getView()in Custom Adapter
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
final TextView textView;
final EditText et;
final Button sub;
if (v == null) {
v = inflater.inflate(R.layout.row, null);
textView = (TextView) v.findViewById(R.id.tvLabel);
textView.setText("Hello"+position);
et = (EditText) v.findViewById(R.id.etWhatToFill);
sub = (Button) v.findViewById(R.id.btnSubmit);
v.setTag(new LazyViewHolder(textView, et, sub));
sub.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
textView.setText(et.getText().toString());
}
});
} else {
LazyViewHolder viewHolder = (LazyViewHolder) v.getTag();
sub = viewHolder.getBtnSub();
et=viewHolder.getEt();
textView = viewHolder.getText();
}
return v;
}
Please Find Detailed Explanation for ListView and CustomListView here
I'm trying to make a task manager, and I only have one problem. I have a listview that gets inflated. All the elements in the listview are correct. The problem is that when I select an item, the listview will select another item away. I've heard listviews repopulate the list as it scrolls down to save memory. I think this may be some sort of problem. Here is a picture of the problem.
If i had more apps loaded, then it would continue to select multiple at once.
Here is the code of my adapter and activity and XML associated
public class TaskAdapter extends BaseAdapter{
private Context mContext;
private List<TaskInfo> mListAppInfo;
private PackageManager mPack;
public TaskAdapter(Context c, List<TaskInfo> list, PackageManager pack) {
mContext = c;
mListAppInfo = list;
mPack = pack;
}
#Override
public int getCount() {
return mListAppInfo.size();
}
#Override
public Object getItem(int position) {
return mListAppInfo.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
TaskInfo entry = mListAppInfo.get(position);
if (convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
//System.out.println("Setting LayoutInflater in TaskAdapter " +mContext +" " +R.layout.taskinfo +" " +R.id.tmbox);
convertView = inflater.inflate(R.layout.taskinfo,null);
}
ImageView ivIcon = (ImageView)convertView.findViewById(R.id.tmImage);
ivIcon.setImageDrawable(entry.getIcon());
TextView tvName = (TextView)convertView.findViewById(R.id.tmbox);
tvName.setText(entry.getName());
convertView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
final CheckBox checkBox = (CheckBox)v.findViewById(R.id.tmbox);
if(v.isSelected())
{
System.out.println("Listview not selected ");
//CK.get(arg2).setChecked(false);
checkBox.setChecked(false);
v.setSelected(false);
}
else
{
System.out.println("Listview selected ");
//CK.get(arg2).setChecked(true);
checkBox.setChecked(true);
v.setSelected(true);
}
}
});
return convertView;
public class TaskManager extends Activity implements Runnable
{
private ProgressDialog pd;
private TextView ram;
private String s;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.taskpage);
setTitleColor(Color.YELLOW);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run()
{
//System.out.println("In Taskmanager Run() Thread");
final PackageManager pm = getPackageManager();
final ListView box = (ListView) findViewById(R.id.cBoxSpace);
final List<TaskInfo> CK = populate(box, pm);
runOnUiThread(new Runnable()
{
#Override
public void run()
{
ram.setText(s);
box.setAdapter(new TaskAdapter(TaskManager.this, CK, pm));
//System.out.println("In Taskmanager runnable Run()");
endChecked(CK);
}
});
handler.sendEmptyMessage(0);
}
Taskinfo.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal">
<ImageView
android:id="#+id/tmImage"
android:layout_width="48dp"
android:layout_height="48dp"
android:scaleType="centerCrop"
android:adjustViewBounds="false"
android:focusable="false" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tmbox"
android:lines="2"/>
</LinearLayout>
Taskpage.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="#+id/cBoxSpace"
android:layout_width="wrap_content"
android:layout_height="400dp"
android:orientation="vertical"/>
<TextView
android:id="#+id/RAM"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp" />
<Button
android:id="#+id/endButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="End Selected Tasks" />
</LinearLayout>
Any ideas for what reason mutliple items are selected with a single click would be GREATLY appreciated. I've been messing around with different implementations and listeners and listadapters but to no avail.
I think the point is you only save checking state in the view(v.setSelected).
And you reuse these view, so its checkbox is always not change its state.
You can create a state array to save every checking state of every TaskInfo, and check this array when you create a view.
for example
// default is false
ArrayList<Boolean> checkingStates = new ArrayList<Boolean>(mListAppInfo.size());
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
TaskInfo entry = mListAppInfo.get(position);
if (convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(R.layout.taskinfo,null);
}
ImageView ivIcon = (ImageView)convertView.findViewById(R.id.tmImage);
ivIcon.setImageDrawable(entry.getIcon());
TextView tvName = (TextView)convertView.findViewById(R.id.tmbox);
tvName.setText(entry.getName());
final CheckBox checkBox = (CheckBox)v.findViewById(R.id.tmbox);
checkBox.setChecked(checkingStates.get(position));
convertView.setSelected(checkingStates.get(position));
convertView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
if(v.isSelected())
{
System.out.println("Listview not selected ");
//CK.get(arg2).setChecked(false);
checkBox.setChecked(false);
v.setSelected(false);
checkingStates.get(position) = false;
}
else
{
System.out.println("Listview selected ");
//CK.get(arg2).setChecked(true);
checkBox.setChecked(true);
v.setSelected(true);
checkingStates.get(position) = true;
}
}
});
return convertView;
}
I'm not 100% sure what you are trying to do, but part of your problem might be related to the condition in your onClick method:
if(v.isSelected())
I think you want that to read
if(v.isChecked())
isSelected is inherited from View, and it means something different from isChecked
Also, the whether the CheckBox is checked or not is independent from your data model since it is a recycled view. Your CheckBox should be checked based on entry (I'm assuming your TextInfo class has an isChecked() method that returns a boolean:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
TaskInfo entry = mListAppInfo.get(position);
if (convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
//System.out.println("Setting LayoutInflater in TaskAdapter " +mContext +" " +R.layout.taskinfo +" " +R.id.tmbox);
convertView = inflater.inflate(R.layout.taskinfo,null);
}
ImageView ivIcon = (ImageView)convertView.findViewById(R.id.tmImage);
ivIcon.setImageDrawable(entry.getIcon());
TextView tvName = (TextView)convertView.findViewById(R.id.tmbox);
tvName.setText(entry.getName());
CheckBox checkBox = (CheckBox)v.findViewById(R.id.tmbox);
checkBox.setChecked(entry.isChecked());
}
I don't think you need the View.OnClickListener you are attaching to convertView. You should handle that in the OnItemClickListener attached to the ListView. Assuming your ListView is called listView and TaskInfo instances have setChecked and isChecked methods:
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
entry = mListAppInfo.get(position);
entry.setChecked(!entry.isChecked());
}
});
First of all don't set the list checked or unchecked on view position.
because view position means only visible items position in your listview but you would like to set checked or uncheked status on a particular list item.
That's why this problem arises in your code.
You have the need to set the items checked and unchecked on your custom arraylist getter setter like the code i have attached below:
package com.app.adapter;
public class CategoryDynamicAdapter {
public static ArrayList<CategoryBean> categoryList = new ArrayList<CategoryBean>();
Context context;
Typeface typeface;
public static String videoUrl = "" ;
Handler handler;
Runnable runnable;
// constructor
public CategoryDynamicAdapter(Activity a, Context context, Bitmap [] imagelist,ArrayList<CategoryBean> list) {
this.context = context;
this.categoryList = list;
this.a = a;
}
// Baseadapter to the set the data response from web service into listview.
public BaseAdapter mEventAdapter = new BaseAdapter() {
#Override
public int getCount() {
return categoryList.size();
}
#Override
public Object getItem(int position) {
return categoryList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
class ViewHolder {
TextView title,category,uploadedBy;
ImageView image;
RatingBar video_rating;
Button report_video ,Flag_video;
}
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewHolder vh = null ;
if(convertView == null) {
vh = new ViewHolder();
convertView = LayoutInflater.from(context).inflate (R .layout.custom_category_list_layout,null,false);
vh.title = (TextView) convertView .findViewById (R.id.title);
vh.image = (ImageView) convertView.findViewById(R.id.Imagefield);
convertView.setTag(vh);
}
else
{
vh=(ViewHolder) convertView.getTag();
}
try
{
final CategoryBean Cb = categoryList.get(position);
//pay attention to code below this line i have shown here how to select a listview using arraylist getter setter objects
String checkedStatus = Cb.getCheckedStringStaus();
if(checkdStatus.equal("0")
{
System.out.println("Listview not selected ");
//CK.get(arg2).setChecked(false);
checkBox.setChecked(false);
v.setSelected(false);
}
else ////checkdStatus.equal("1")
{
System.out.println("Listview selected ");
//CK.get(arg2).setChecked(true);
checkBox.setChecked(true);
v.setSelected(true);
}
catch (Exception e)
{
e.printStackTrace();
}