Spinner with sub-spinner not working as expected - java

I have two spinners, such that my second spinner changes options that it can offer according to the item selected in the first spinner. Easy?
Example: If I select 'a' in main spinner, the sub spinner should show 'a1' as option. If I select 'b' in main spinner, the sub spinner should show 'b1','b2' as options. If I select 'c' in main spinner, the sub spinner should show 'c1','c2','c3' as options.
I use a library called SearchableSpinner but that does not matter as it works just like the Android spinner.
public class PostComplaint extends AppCompatActivity {
String[] problems_main = {"a","b","c"};
String[][] problems_sub = {{"a1"},{"b1","b2"},{"c1","c2","c3"}};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_complaint);
spinner_main = (SearchableSpinner)findViewById(R.id.spinner_main);
spinner_sub = (SearchableSpinner) findViewById(R.id.spinner_sub);
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, problems_main);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_main.setAdapter(spinnerAdapter);
spinnerAdapter.notifyDataSetChanged();
spinner_main.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setSubSpinner(position);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
Toast.makeText(PostComplaint.this, "Nothing selected", Toast.LENGTH_SHORT).show();
}
});
}
void setSubSpinner(int i){
String[] myArray = problems_sub[i]; //Note: problems_sub is a two dimensional array
ArrayAdapter<String> spinnerAdapter_sub = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, myArray);
spinnerAdapter_sub.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_sub.setAdapter(spinnerAdapter_sub);
spinnerAdapter_sub.notifyDataSetChanged();
}
Problem: Whichever item I click on the main spinner for the first time, according to that the sub spinner is selected. Then if I change the main spinner, the sub spinner is not changing.
The question is open for suggestions. Comment if it is not understandable.

The error is coming because of the following function in the SearchableSpinner Class:
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ArrayAdapter adapter = (ArrayAdapter) getAdapter();
if (null != adapter) {
if (_items.size() == 0) {
for (int i = 0; i < adapter.getCount(); i++) {
_items.add(adapter.getItem(i));
}
}
SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
(_items);
searchableListDialog.setOnSearchableItemClickListener(this);
searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
}
}
return true;
}
The condition if(_items.size() == 0) becomes true only the first time you click on the sub spinner and hence it gets initialized correctly and you will see correct values. However, once you have clicked on the sub spinner, _item.size() will never be zero and thus, the updated sub spinner values will never be rendered.
I suggest you use the default Android Spinner or fork the repository and fix the error and use the same.
EDIT
You can try using this class:
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.toptoche.searchablespinnerlibrary.SearchableListDialog;
import java.util.ArrayList;
import java.util.List;
public class CustomSearchableSpinner extends Spinner implements View.OnTouchListener,
SearchableListDialog.SearchableItem {
private Context _context;
private List _items;
private boolean isDataSetChanged;
public CustomSearchableSpinner(Context context) {
super(context);
this._context = context;
this.isDataSetChanged = true;
init();
}
public CustomSearchableSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
this._context = context;
this.isDataSetChanged = true;
init();
}
public CustomSearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this._context = context;
this.isDataSetChanged = true;
init();
}
private void init() {
_items = new ArrayList();
setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
ArrayAdapter adapter = (ArrayAdapter) getAdapter();
if (null != adapter) {
if (isDataSetChanged) {
if(_items.size() != 0) {
_items = new ArrayList();
}
for (int i = 0; i < adapter.getCount(); i++) {
_items.add(adapter.getItem(i));
}
isDataSetChanged = false;
}
SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
(_items);
searchableListDialog.setOnSearchableItemClickListener(this);
searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
}
}
return true;
}
#Override
public void onSearchableItemClicked(Object item, int position) {
setSelection(_items.indexOf(item));
}
public void notifyDataChanged(Boolean hasDataChanged) {
this.isDataSetChanged = hasDataChanged;
}
}
Also, update your layout file and PostComplaint Class to use CustomSearchableSpinner in place of Searchable Spinner. It may not be the best approach, but it works.
EDIT 2
You will need to call spinnerAdapter_sub.notifyDataChanged(true) after you call spinnerAdapter_sub.notifyDataSetChanged();.

Related

Recycler View adapter not working properly when the list is big enough to scroll

I have a recycler view adapter like the code I provided. Everything works fine with the action bar delete function until the list is big enough to scroll.
When the list is big selecting multiple items and tapping delete is not deleting the exact selected items. Its deleting some other items. But like always after deleting when the list is doesn't need scroll no more its deleting exact selected items.
So what am I doing wrong here?
package com.itsred1.a1wallet;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
public class RVDirLisAda extends RecyclerView.Adapter<RVDirLisAda.MyViewHolder> {
private final Context m_con;
private final LayoutInflater lay_inf;
private final ArrayList<RVDat> arr_lis_his_dat;
private ArrayList<Integer> sel_pos_lis = new ArrayList<>();
private boolean mul_sel;
RVDirLisAda(Context context, ArrayList<RVDat> his_dat_arr_lis) {
m_con = context;
lay_inf = LayoutInflater.from(context);
this.arr_lis_his_dat = his_dat_arr_lis;
}
private ActionMode.Callback act_mod_cal_bac = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mul_sel = true;
menu.add("Delete");
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
for (int pos : sel_pos_lis) {
arr_lis_his_dat.remove(pos);
}
mode.finish();
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mul_sel = false;
sel_pos_lis.clear();
notifyDataSetChanged();
}
};
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View vie = lay_inf.inflate(R.layout.rv_dir_lis, parent, false);
return new MyViewHolder(vie);
}
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
holder.ini_row(position);
}
#Override
public int getItemCount() {
return arr_lis_his_dat.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
private final TextView tv_fil_nam;
MyViewHolder(View itemView) {
super(itemView);
tv_fil_nam = itemView.findViewById(R.id.tv_fil_nam);
}
void ini_row(final int pos){
if (sel_pos_lis.contains(pos)){
tv_fil_nam.setBackgroundColor(Color.LTGRAY);
} else {
tv_fil_nam.setBackgroundColor(Color.WHITE);
}
final String fil_nam = arr_lis_his_dat.get(pos).get_row1_col2();
final String tra_typ = arr_lis_his_dat.get(pos).get_tra_typ();
final String id = arr_lis_his_dat.get(pos).get_row2_col1();
tv_fil_nam.setText(fil_nam);
if(tra_typ.equals("folder")) {
tv_fil_nam.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ico_fol, 0, 0, 0);
} else if (tra_typ.equals("file")) {
tv_fil_nam.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ico_db,0,0,0);
}
tv_fil_nam.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if(!mul_sel){
((AppCompatActivity) v.getContext()).startSupportActionMode(act_mod_cal_bac);
}
sel_row(pos);
return true;
}
});
tv_fil_nam.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mul_sel){
sel_row(pos);
} else {
cal_bac(id, fil_nam, pos);
}
}
});
}
void sel_row(int pos) {
if (mul_sel) {
if (sel_pos_lis.contains(pos)) {
int i = sel_pos_lis.lastIndexOf(pos);
sel_pos_lis.remove(i);
tv_fil_nam.setBackgroundColor(Color.WHITE);
} else {
sel_pos_lis.add(pos);
tv_fil_nam.setBackgroundColor(Color.LTGRAY);
}
}
}
void cal_bac(String id, String tra_typ, int pos) {
CalBacCom cal_bac_com = null;
if (m_con instanceof CalBacCom) {
cal_bac_com = (CalBacCom) m_con;
}
if (cal_bac_com != null) {
cal_bac_com.ini_cal_bac (id, tra_typ, pos, "row_cli");
}
}
}
}
for (int pos : sel_pos_lis) {
arr_lis_his_dat.remove(pos);
}
This part of your code has an issue, when you remove some item at some position then the position of next items will change and other remove actions could fail and remove some other items.
You should remove options with a higher index first but it's not related to scrolling and big lists.
Inside your OnClickListeners you are referencing a position value that could change very quickly as you scroll up or down. This happens because your view holder is re-used to inflate new items that become visible thus avoiding new memory allocation, in the other words, the adapter takes the view holder from items that become "hidden" and reuse them on items that become "visible" while you scroll. Instead use the getAdapterPosition method inside those listeners. For example, instead of doing this...
tv_fil_nam.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mul_sel){
sel_row(pos);
} else {
cal_bac(id, fil_nam, pos);
}
}
});
do this...
tv_fil_nam.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mul_sel){
sel_row(getAdapterPosition());
} else {
cal_bac(id, fil_nam, getAdapterPosition());
}
}
});

How to update listview during search

This is my app when I start it:
When I click one of the item in the list view it will open a new activity and display some data.
When I search for something it looks like this:
And when I click an item in the list it starts a new activity. But the activity it starts is not accurate.
Here's my code:
HomeActivity.class
package com.thesis.herbalmedicines.activity;
import java.util.ArrayList;
import java.util.Arrays;
import android.app.Activity;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;
import android.widget.Toast;
public class HomeActivity extends BaseActivity implements
SearchView.OnQueryTextListener {
ListView lv;
SearchView search;
String[] herb_names, sample_arr; //= ["Boils","",""];//, iso_codes;
TypedArray herb_pics;
ArrayList<Home> homelist;
HomeAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLayoutInflater().inflate(R.layout.home_layout, frameLayout);
mDrawerList.setItemChecked(position, true);
setTitle(listArray[position]);
android.app.ActionBar ab = getActionBar();
ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor("#50B222"));
ab.setBackgroundDrawable(colorDrawable);
lv = (ListView) findViewById(R.id.list_view);
search = (SearchView) findViewById(R.id.search_view);
herb_names = getResources().getStringArray(R.array.herb_names);
//iso_codes = getResources().getStringArray(R.array.iso_Code);
herb_pics = getResources().obtainTypedArray(R.array.herb_pics);
homelist = new ArrayList<Home>();
for (int i = 0; i < herb_names.length; i++) {
Home home = new Home(herb_names[i], //iso_codes[i],
herb_pics.getResourceId(i, -1));
homelist.add(home);
}
adapter = new HomeAdapter(getApplicationContext(), homelist);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (position == 0) {
Intent a = new Intent(HomeActivity.this, Boils.class);
startActivity(a);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
else if (position == 1) {
Intent b = new Intent(HomeActivity.this, Cystitis.class);
startActivity(b);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
else if (position == 2) {
Intent c = new Intent(HomeActivity.this, Asthma.class);
startActivity(c);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
else if (position == 3) {
Intent d = new Intent(HomeActivity.this, Feet.class);
startActivity(d);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
});
search.setOnQueryTextListener(this);
}
#Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
}
Home.java
package com.thesis.herbalmedicines.activity;
public class Home {
String name;
int pics;
Home(String name, int pics) {
this.name = name;
this.pics = pics;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPics() {
return pics;
}
public void setPics(int pics) {
this.pics = pics;
}
}
HomeAdapter.java
package com.thesis.herbalmedicines.activity;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;
public class HomeAdapter extends BaseAdapter implements Filterable {
Context context;
ArrayList<Home> homelist;
ArrayList<Home> mStringFilterList;
ValueFilter valueFilter;
HomeAdapter(Context context, ArrayList<Home> homelist) {
this.context = context;
this.homelist = homelist;
mStringFilterList = homelist;
}
#Override
public int getCount() {
return homelist.size();
}
#Override
public Object getItem(int position) {
return homelist.get(position);
}
#Override
public long getItemId(int position) {
return homelist.indexOf(getItem(position));
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
TextView name_tv = (TextView) convertView.findViewById(R.id.name);
ImageView iv = (ImageView) convertView.findViewById(R.id.pic);
Home home = homelist.get(position);
name_tv.setText(home.getName());
iv.setImageResource(home.getPics());
}
return convertView;
}
#Override
public Filter getFilter() {
if (valueFilter == null) {
valueFilter = new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
ArrayList<Home> filterList = new ArrayList<Home>();
for (int i = 0; i < mStringFilterList.size(); i++) {
if ((mStringFilterList.get(i).getName().toUpperCase())
.contains(constraint.toString().toUpperCase())) {
Home home = new Home(mStringFilterList.get(i)
.getName(), mStringFilterList.get(i)
.getPics());
filterList.add(home);
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = mStringFilterList.size();
results.values = mStringFilterList;
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
homelist = (ArrayList<Home>) results.values;
notifyDataSetChanged();
}
}
}
Add a field that holds the class to be loaded inside the Home class. (The id field is optional)
public class Home {
int id;
String name;
int pics;
Class clazz;
Home(int id, String name, int pics, Class clazz) {
this.id = id;
this.name = name;
this.pics = pics;
this.clazz = clazz;
}
// getters and setters
}
During initialization of the homelist add the id,
// the classed to load
Class[] classes = {
Boils.class,
Cystitis.class,
Asthma.class,
Feet.class
};
for (int i = 0; i < herb_names.length; i++) {
Home home = new Home(i, herb_names[i], herb_pics.getResourceId(i, -1), classes[i]);
homelist.add(home);
}
Inside the setOnItemClickListener,
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Home item = (Home) adapter.getItem(position);
Intent d = new Intent(HomeActivity.this, item.getClazz());
startActivity(d);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
});
Couple of changes should be made in your adapter as well.
Inside the getView you are forcing the convertView to null. It is bad for performance. (Consider using a ViewHolder too)
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, null);
}
TextView name_tv = (TextView) convertView.findViewById(R.id.name);
ImageView iv = (ImageView) convertView.findViewById(R.id.pic);
Home home = homelist.get(position);
name_tv.setText(home.getName());
iv.setImageResource(home.getPics());
return convertView;
}
Inside publishResults you are creating a new reference for the dataset. You should update the existing dataset.
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
homelist.clear();
homelist.addAll((ArrayList<Home>) results.values);
notifyDataSetChanged();
}
Set adpter to listview on every onSerch
Why do you use position to navigate to different activity ?
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (position == 0) {
Intent a = new Intent(HomeActivity.this, Boils.class);
startActivity(a);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
else if (position == 1) {
Intent b = new Intent(HomeActivity.this, Cystitis.class);
startActivity(b);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
else if (position == 2) {
Intent c = new Intent(HomeActivity.this, Asthma.class);
startActivity(c);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
else if (position == 3) {
Intent d = new Intent(HomeActivity.this, Feet.class);
startActivity(d);
/** Fading Transition Effect */
HomeActivity.this.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
});
search.setOnQueryTextListener(this);
}
This will always reset your position whenever you adapter refresh from search result.
To do this in better way. Just create custom listener like following in your adapter.
Public interface ListViewClick{
void onListClick(Object type)
}
Register your receiver in activity and pass type of activity to launch from adapter
private ListViewClick callback;
HomeAdapter(Context context, ArrayList<Home> homelist,ListViewClick callback) {
this.context = context;
this.homelist = homelist;
mStringFilterList = homelist;
this.callback = callback;
}
and on click listener of convertView pass callback.onListClick(//type of activity to launch).
Just keep reference of 'type of activity to launch in Home enitity'. so you can recognize which activity is ti be launch when clicking on particular row of list view.

calling BaseAdapter's notifyDataSetChanged() inside CustomAdapter not refreshing ListView

I have ArrayList<MyObject> data which is populated on the ListView using a CustomAdapter.
I've implemented View.OnClickListener in the CustomAdapter class and clicking a button deletes the particular row. After deleting the row, both from database and from the data object using data.remove(i) inside the Custom Adapter, I call notifyDataSetChanged().
Problem is that it does not refresh teh ListView.
I'm using a tabbed activity with fragment. So, when go to some distant tab and come back to this tab, it refreshes the ListView and the deleted item does not show anymore.
Why is the ListView not refreshing immediately when i call notifyDataSetChanged() but changing when i move to another fragment and back?
My CustomAdapter class is as follows:
public class CustomAdapter extends BaseAdapter implements View.OnClickListener {
private LayoutInflater mInflater;
Context context;
private ArrayList<MyObject> data;
public CustomAdapter(Context context, ArrayList<MyObject> data) {
mInflater = LayoutInflater.from(context);
this.data = data;
this.context = context;
}
.....
.....
.....
.....
.....
#Override
public void onClick(View v) {
DataBaseHelper db = new DataBaseHelper(context);
int id = data.get((Integer) v.getTag()).id;
//use getTag() to get the position, set position in tag before adding listener.
switch (v.getId()){
case R.id.txtName:
Toast.makeText(context, "Show Details" + v.getTag(), Toast.LENGTH_SHORT).show();
break;
case R.id.btnRemove:
db.removePaper(id); // works fine
data.remove(v.getTag()); // works fine
notifyDataSetChanged(); // PROBLEM HERE: Does not refresh listview
break;
case R.id.btnFavorite:
Toast.makeText(context, "Favorite" + v.getTag(), Toast.LENGTH_SHORT).show();
break;
}
}
}
I had a similar issue some time ago, I fixed it extending ArrayAdapter<MyObject> instead of BaseAdapter and overriding some methods:
public class CustomAdapter extends ArrayAdapter<MyObject> {
private List<MyObject> list = new ArrayList<MyObject>();
public CustomAdapter(Context context, int resource) {
super(context, resource);
}
#Override
public void add(MyObject obj) {
this.list.add(obj);
super.add(obj);
}
#Override
public void remove(MyObject obj) {
int i = getPosition(obj);
if(i >= 0)
list.remove(i);
super.remove(obj);
}
#Override
public void clear() {
this.list.clear();
super.clear();
}
#Override
public MyObject getItem(int position) {
return this.list.get(position);
}
#Override
public int getPosition(MyObject obj) {
for(int i = 0; i < list.size(); i++) {
if(list.get(i).equals(obj))
return i;
}
return -1;
}}
Then call these methods instead of calling directly methods of your List.

Trying to set custom BaseAdapter to listview

I am trying to accomplish this: http://blog.uncommons.org/2011/05/09/embedding-admob-adverts-in-android-listviews/.
I am stuck at setting the custom BaseAdapter I simply don't know what to put in the BASEADAPTER variable below.
Here is my adapter
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;
/**
* List adapter decorator that inserts adverts into the list.
* #author Daniel Dyer
*/
public class AdvertisingAdapter extends BaseAdapter
{
private static final String ADMOB_PUBLISHER_ID = "---------------";
private final Activity activity;
private final BaseAdapter delegate;
private int resource;
private ArrayList<String> objects;
public AdvertisingAdapter(Activity activity, int resource, BaseAdapter delegate,
ArrayList<String> stories) {
// TODO Auto-generated constructor stub
this.resource = resource;
this.activity = activity;
this.delegate = delegate;
this.objects = stories;
delegate.registerDataSetObserver(new DataSetObserver()
{
#Override
public void onChanged()
{
notifyDataSetChanged();
}
#Override
public void onInvalidated()
{
notifyDataSetInvalidated();
}
});
}
public int getCount()
{
return delegate.getCount() + 1;
}
public Object getItem(int i)
{
return delegate.getItem(i - 1);
}
public long getItemId(int i)
{
return delegate.getItemId(i - 1);
}
public View getView(int position, View convertView, ViewGroup parent)
{
if ((position % 10) == 0)
{
if (convertView instanceof AdView)
{
return convertView;
}
else
{
AdView adView = new AdView(activity, AdSize.BANNER, ADMOB_PUBLISHER_ID);
// Disable focus for sub-views of the AdView to avoid problems with
// trackpad navigation of the list.
for (int i = 0; i < adView.getChildCount(); i++)
{
adView.getChildAt(i).setFocusable(false);
}
adView.setFocusable(false);
// Default layout params have to be converted to ListView compatible
// params otherwise there will be a ClassCastException.
float density = activity.getResources().getDisplayMetrics().density;
int height = Math.round(AdSize.BANNER.getHeight() * density);
AbsListView.LayoutParams params
= new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
height);
adView.setLayoutParams(params);
adView.loadAd(new AdRequest());
return adView;
}
}
else
{
return delegate.getView(position - 1, convertView, parent);
}
}
#Override
public int getViewTypeCount()
{
return delegate.getViewTypeCount() + 1;
}
#Override
public int getItemViewType(int position)
{
return position == 0 ? delegate.getViewTypeCount()
: delegate.getItemViewType(position - 1);
}
#Override
public boolean areAllItemsEnabled()
{
return false;
}
#Override
public boolean isEnabled(int position)
{
return position != 0 && delegate.isEnabled(position - 1);
}
}
And in my main activity here is where I'm trying to set my custom base adapter. What should the BASEADAPTER parameter be?
mListView.setAdapter(new AdvertisingAdapter(this,
android.R.layout.simple_list_item_1, BASEADAPTER, stories));
Its depend what you trying to show or display in listview, normally application context and desire data is to be passed to BaseAdapter constructor. For details info read BaseAdapter and even check Android ListView detailed tutorial.

Android Limited Multi Select Preference, why no checkmark?

I'm trying to create a custom preference for an Android application that limits the number of items the user can select. Once the limit is reached the unselected items should be disabled and only the currently selected items are enabled.. If there are less items selected than the limit all items should be enabled.
Here are the two classes I've cobbled together. The code runs fine but no the CheckedTextView is not checked. As a result no state is maintained.
First the view class...
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ListView;
public class LimitedMultiChoiceView extends ListView
implements AdapterView.OnItemClickListener
{
private static final String SEPARATOR = "OV=I=XseparatorX=I=VO";
private static final String LIMITEDSELECTION="limitedSelection";
private static final String SUPERSTATE="superState";
private String mSelection = "";
public LimitedMultiChoiceView(Context context, CharSequence[] items, int limit)
{
this(context, null, 0, items, limit);
} // LimitedMultiChoiceView(Context context)
public LimitedMultiChoiceView(Context context, AttributeSet attrs, CharSequence[] items, int limit)
{
this(context, attrs, 0, items, limit);
} // LimitedMultiChoiceView(Context context, AttributeSet attrs)
public LimitedMultiChoiceView(Context context, AttributeSet attrs
, int defStyle, CharSequence[] items, int limit)
{
super(context, attrs, defStyle);
setAdapter(new ItemAdapter(context, android.R.layout.simple_list_item_multiple_choice, items, limit));
} // LimitedMultiChoiceView(Context context, AttributeSet attrs, int defStyle)
public String getSelection()
{
return mSelection;
} // String getSelection()
public void onItemClick(AdapterView<?> parent, View child, int position, long id)
{
// For now we don't need anything...
// we think the ItemAdapter manages what we need for each item.
} // void onItemClick(AdapterView<?> parent, View child, int position, long id)
#Override
public void onRestoreInstanceState(Parcelable toParce)
{
Bundle state=(Bundle)toParce;
super.onRestoreInstanceState(state.getParcelable(SUPERSTATE));
mSelection = state.getString(LIMITEDSELECTION);
} // void onRestoreInstanceState(Parcelable toParce)
#Override
public Parcelable onSaveInstanceState()
{
Bundle state=new Bundle();
state.putParcelable(SUPERSTATE, super.onSaveInstanceState());
state.putString(LIMITEDSELECTION, mSelection);
return(state);
} // Parcelable onSaveInstanceState()
public void setSelection(String value)
{
mSelection = value;
} // void setSelection(String value)
class ItemAdapter extends ArrayAdapter<CharSequence>
{
CharSequence[] mItems = null;
int mLimit = 1;
public ItemAdapter(Context context, int viewResId, CharSequence[] items, int limit)
{
super(context, viewResId, items);
mItems = items;
mLimit = limit;
} // ItemAdapter(Context context, int viewResId, CharSequence[] strings, int limit)
public boolean areAllItemsEnabled()
{
// Since we are in a limited selection list not all items can be
// selected so this always returns false, there is no calculating
// to do.
return false;
} // boolean areAllItemsEnabled()
public boolean isEnabled(int position)
{
boolean[] clickedIndexes = new boolean[this.getCount()];
boolean result = false;
int selectedCount = 0;
mSelection = "";
for (int item=0; item < clickedIndexes.length; item++ )
{
View itemView = this.getView(item, null, LimitedMultiChoiceView.this);
if (itemView instanceof CheckedTextView)
{
CheckedTextView check = (CheckedTextView)itemView;
// First we turn the check mark on or off...
if (item == position)
{
check.setChecked(!check.isChecked());
} // (item == position)
// Now we count how many are checked and mark our tracking array
if (check.isChecked())
{
clickedIndexes[item] = true;
mSelection += check.getText() + SEPARATOR;
}
else
{
clickedIndexes[item] = false;
} // (check.isChecked())
} // (itemView instanceof CheckedTextView)
if (clickedIndexes[item])
selectedCount++;
} // (int item=0; item< clickedIndexes.length; item++ )
if (selectedCount >= mLimit)
{
if (clickedIndexes[position])
{
result = true;
}
else
{
result = false;
} // (clickedIndexes[position])
}
else
{
result = true;
} // (selectedCount >= mLimit)
return result;
} // boolean isEnabled(int position)
} // class ItemAdapter extends ArrayAdapter<CharSequence>
} // class LimitedMultiChoiceView extends ListView
This is the preference class...
import android.content.Context;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.view.View;
public class ListPreferenceLimitedMultiSelect extends ListPreference
{
int mLimit = 3;
LimitedMultiChoiceView mList = null;
String mSelection = "";
public ListPreferenceLimitedMultiSelect(Context context)
{
this(context, null);
} // ListPreferenceLimitedMultiSelect(Context context)
public ListPreferenceLimitedMultiSelect(Context context, AttributeSet attr)
{
super(context, attr);
} // ListPreferenceLimitedMultiSelect(Context context, AttributeSet attr)
#Override
protected void onBindDialogView(View v)
{
super.onBindDialogView(v);
mList.setSelection(mSelection);
} // void onBindDialogView(View v)
#Override
protected View onCreateDialogView()
{
mList = new LimitedMultiChoiceView(getContext()
, this.getEntries(), mLimit);
return(mList);
} // View onCreateDialogView()
#Override
protected void onDialogClosed(boolean positiveResult)
{
super.onDialogClosed(positiveResult);
if (positiveResult)
{
if (callChangeListener(mList.getSelection()))
{
mSelection = mList.getSelection();
persistString(mSelection);
} // (callChangeListener(mList.getSelection()))
} // (positiveResult)
} // void onDialogClosed(boolean positiveResult)
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
{
mSelection =(restoreValue ? getPersistedString(mSelection) : (String)"");
} // void onSetInitialValue(boolean restoreValue, Object defaultValue)
} // class ListPreferenceLimitedMultiSelect extends ListPreference
Thanks,
\ ^ / i l l

Categories