I would like to append new items to a ListView to enable endless scrolling.
private ListAdapter adapter;
ArrayList < HashMap < String, String >> listViewList;
...
class GetItems extends AsyncTask < String, String, String > {
protected String doInBackground(String...args) {
...
for (int i = 0; i < items.length(); i++) {
...
HashMap < String, String > map = new HashMap < String, String > ();
map.put("name_1", name_1);
map.put("name_2", name_3);
map.put("name_3", name_3);
listViewList.add(map);
}
}
protected void onPostExecute(String file_url) {
adapter = new CustomAdapter(Activity.this, listViewList,
R.layout.single_item, new String[] {}, new int[] {});
setListAdapter(adapter);
}
}
GetItems class gets new items based on a page number you provide. I would like to append new items to existing ListView items on onPostExecute.
Any idea how to do it?
Check out this library on GitHub
https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews
EDIT according to your comment:
You need to forget about ListActivity and that you ever heard it exists, it's useless for what you are trying to do.
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class DemosAdapter extends BaseAdapter {
public List<DemoItem> listOfItems;
private View v;
private ViewWrapper wrapper;
private Context context;
public DemosAdapter(Context c, List<DemoItem> listOfItems) {
this.context = c;
this.listOfItems = listOfItems;
}
#Override
public int getCount() {
return listOfItems.size();
}
#Override
public DemoItem getItem(int i) {
return listOfItems.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
public void sort() {
Collections.sort(listOfItems, new Comparator<DemoItem>() {
#Override
public int compare(DemoItem item, DemoItem item2) {
return item.getName().compareTo(item2.getName());
}
});
}
public void addItems(List<DemoItem> listOfFreshItems){
listOfItems.addAll(listOfFreshItems);
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
DemoItem itm = listOfItems.get(position);
v = convertView;
if (v == null) {
LayoutInflater inflater = LayoutInflater.from(context);
v = inflater.inflate(R.layout.demo_item, null, false);
wrapper = new ViewWrapper(v);
v.setTag(wrapper);
}
else {
wrapper = (ViewWrapper) v.getTag();
}
wrapper.getTvDemoName().setText(itm.getName());
return v;
}
private class ViewWrapper {
private View base;
private TextView tvDemoName;
public ViewWrapper(View v) {
this.base = v;
}
public TextView getTvDemoName() {
if (tvDemoName == null) {
tvDemoName = (TextView) base.findViewById(R.id.tvDemoName);
}
return tvDemoName;
}
}
}
The first time you add data, do this
demosAdapter = new DemosAdapter(this, listOfDemos);
demosAdapter.sort();
lvListOfDemos.setAdapter(demosAdapter);
When you get new items, just call
adapter.addItems(List<DemoItem> newItems);
Actually you just need to call adapter.notifyDataSetChanged in onPostExecute.
But you should not instantiate adapter many times. It should be done just one so overall it would look like this
private ListAdapter adapter;
...
void onCreate(){ // assuming this is an activity
adapter = new CustomAdapter(Activity.this, listViewList,
R.layout.single_item, new String[] {}, new int[] {});
setListAdapter(adapter);
}
class GetItems extends AsyncTask<String, String, String> {
...
protected void onPostExecute(String file_url) {
adapter.notifyDataSetChanged();
}
}
Related
Trying to create a generic adapter for the RecyclerView.
Already explored other solutions:
RecyclerView generic adapter with DataBinding
Add click listener to Generic RecyclerView Adapter
https://github.com/ravirupareliya/Recyclerview-Generic-Adapter/blob/master/app/src/main/java/com/rrr/genericrecyclerview/adapter/RecyclerAdapter.java
However want to implement it in a bit different way.
Here is how my adapter looks like:
public abstract class GenericAdapter<T> extends RecyclerView.Adapter<BaseHolder<T>> {
private OnRecyclerItemClickListener mListener;
private List<T> mItems;
private final LayoutInflater mLayoutInflater;
public GenericAdapter(Context context) {
mLayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mItems = Collections.emptyList();
}
#Override
public BaseHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
// assume that viewType is a resource id returned by getItemViewType
// also other solutions are welcome
View view = mLayoutInflater.inflate(viewType, parent, false);
// TODO: how to create the view holder ??
}
#Override
public void onBindViewHolder(BaseHolder<T> holder, int position) {
T item = mItems.get(position);
holder.onBind(item, mListener);
}
#Override
public int getItemCount() {
return mItems != null ? mItems.size() : 0;
}
public void setItems(List<T> items) {
mItems = items;
notifyDataSetChanged();
}
public void setItemClickListener(OnRecyclerItemClickListener listener) {
mListener = listener;
}
}
This is a base view holder from which I want to extend all other holders:
public abstract class BaseHolder<T> extends RecyclerView.ViewHolder {
public BaseHolder(View itemView) {
super(itemView);
}
public abstract void onBind(T item, OnRecyclerItemClickListener listener);
}
The problem is in onCreateViewHolder method.
How do I create the view holder?
Should I somehow implement abstract BaseHolder or should I somehow change the adapter class declaration extends i.e. instead BaseHolder here RecyclerView.Adapter> should be some generic implementation of BaseHolder? I tried > but it doesn't work
Thanks in advance for any piece of advice
P.S. It's been a long time, but if someone is interested,
at the time I solved it and published in a Generic RecyclerView Adapter library.
It finally makes it quite easy to create adapters.
I am still using it in multiple production projects.
EDIT:
So the adapter finally looks like:
public abstract class GenericRecyclerViewAdapter<T, L extends BaseRecyclerListener, VH extends BaseViewHolder<T, L>> extends RecyclerView.Adapter<VH> {
#Override
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
// ...
}
Thus, ViewHolder creation is delegated to the adapter implementation, i.e.:
public class SimpleAdapter extends GenericRecyclerViewAdapter<User, OnRecyclerItemClickListener, UserViewHolder> {
// ...
#Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// or return here any specific ViewHolder according to the viewType
return new UserViewHolder(inflate(R.layout.item_user, parent), getListener());
}
}
And the ViewHolder is a:
public abstract class BaseViewHolder<T, L extends BaseRecyclerListener> extends RecyclerView.ViewHolder {
// ...
}
This is what I did in my "Generic Adapter":
You pass the Class of your holder which is corresponding to your current View like this:
public class FooHolder extends BaseHolder<Foo> {
... // your code with the constructor matching super goes here
}
Then in your adapter constructor you add a parameter as follows:
public GenericAdapter(Context context, Class<? extends BaseHolder> holderClass) {
...
this.holderClass = holderClass;
}
Then in your onCreateViewHolder method you can make an instance of that class like this:
#Override
public BaseHolder<T> onCreateViewHolder(ViewGroup parent, int viewType) {
...
viewHolder = (BaseHolder) holderClass.getConstructor(View.class).newInstance(view);
}
If you wants to use single generic adapter which have different-2 layouts items and different models for different screen, you need to try this :
Create a java class adapter "StoreListAdapter.java"
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collection;
/**
* Created by Deepak Sharma on 31/10/17.
*/
public class StoreListAdapter<T> extends RecyclerView.Adapter<StoreListAdapter.ViewHolder> implements Filterable {
private Collection<T> mItems;
private Context context;
private int mLayout;
IClickable iClickable;
private boolean isAnimationAllowed;
private StoreSearchFilter<T> mSearchFilter;
public StoreListAdapter(Context context)
{
this.context = context;
}
public void setData(Collection<T> items, boolean isAnimationAllowed)
{
mItems = items;
this.isAnimationAllowed = isAnimationAllowed;
}
public void setCallback(int layout, IClickable iClickable)
{
this.mLayout = layout;
this.iClickable = iClickable;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(mLayout, viewGroup, false);
iClickable.init(view);
StoreListAdapter.ViewHolder viewHolder = new StoreListAdapter.ViewHolder(view);
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
// viewHolder.itemView.getLayoutParams().width = width;
viewHolder.itemView.getLayoutParams().height = height+24;
return viewHolder;
}
#Override
public void onBindViewHolder(StoreListAdapter.ViewHolder viewHolder, int i) {
iClickable.execute(viewHolder, mItems.toArray()[i],viewHolder.getAdapterPosition());
if (isAnimationAllowed)
setAnimation(viewHolder.itemView, i);
}
#Override
public int getItemCount() {
return mItems.size()>0?mItems.size():0;
}
#Override
public Filter getFilter() {
if (mSearchFilter == null)
mSearchFilter = new StoreSearchFilter<T>((ArrayList<StoreModel>) mItems, new IFilteredList<T>() {
#Override
public void onListFiltered(ArrayList<T> list) {
setData(list, false);
notifyDataSetChanged();
}
});
return mSearchFilter;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mTextView;
//private CheckBox mCheckBox;
ViewHolder(View v) {
super(v);
mTextView = (TextView)v.findViewById(R.id.list_item);
}
}
public interface IClickable<T> {
public void init(View view);
public void execute(StoreListAdapter.ViewHolder holder, T object, int position);
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
/*if (position > lastPosition)
{*/
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
//lastPosition = position;
/*}*/
}
}
create a store model "StoreModel.java":
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Deepak Sharma on 31/10/17.
*/
public class StoreModel implements Parcelable {
private String storeName;
private int storeId;
private String storeAddress;
private String storePhone = "(310)816-2365";
private String storeCity;
private int prizesAvailable;
private double storeLatitude;
private double storeLongitude;
private List<Games> gamesList;
public StoreModel(int id,String sName, String add, String city, int prizes, double lat, double lon, ArrayList<Games> list)
{
this.storeId = id;
this.storeName = sName;
this.storeAddress = add;
this.storeCity = city;
this.prizesAvailable = prizes;
this.storeLatitude = lat;
this.storeLongitude = lon;
this.gamesList = list;
}
public String getStoreName() {
return storeName;
}
public void setStoreName(String storeName) {
this.storeName = storeName;
}
public String getStoreAddress() {
return storeAddress;
}
public void setStoreAddress(String storeAddress) {
this.storeAddress = storeAddress;
}
public String getStoreCity() {
return storeCity;
}
public void setStoreCity(String storeCity) {
this.storeCity = storeCity;
}
public int getPrizesAvailable() {
return prizesAvailable;
}
public void setPrizesAvailable(int prizesAvailable) {
this.prizesAvailable = prizesAvailable;
}
public double getStoreLatitude() {
return storeLatitude;
}
public void setStoreLatitude(double storeLatitude) {
this.storeLatitude = storeLatitude;
}
public double getStoreLongitude() {
return storeLongitude;
}
public void setStoreLongitude(double storeLongitude) {
this.storeLongitude = storeLongitude;
}
public List<Games> getGamesList() {
return gamesList;
}
public void setGamesList(List<Games> gamesList) {
this.gamesList = gamesList;
}
public String getStorePhone() {
return storePhone;
}
public void setStorePhone(String storePhone) {
this.storePhone = storePhone;
}
#Override
public boolean equals(Object obj) {
if (obj == this)
return true; //If objects equal, is OK
if (obj == null)
return false;
if (!(obj instanceof StoreModel))
return false;
if (obj instanceof StoreModel) {
StoreModel store = (StoreModel)obj;
return ((storeId == store.storeId) && (storeName.equalsIgnoreCase(store.storeName)));
// return (storeId == store.storeId) && y == store.y);
}
return false;
}
#Override
public int hashCode() {
return storeId;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.storeName);
dest.writeString(this.storeAddress);
dest.writeString(this.storePhone);
dest.writeString(this.storeCity);
dest.writeInt(this.prizesAvailable);
dest.writeDouble(this.storeLatitude);
dest.writeDouble(this.storeLongitude);
dest.writeList(this.gamesList);
}
protected StoreModel(Parcel in) {
this.storeName = in.readString();
this.storeAddress = in.readString();
this.storePhone = in.readString();
this.storeCity = in.readString();
this.prizesAvailable = in.readInt();
this.storeLatitude = in.readDouble();
this.storeLongitude = in.readDouble();
this.gamesList = new ArrayList<Games>();
in.readList(this.gamesList, Games.class.getClassLoader());
}
public static final Parcelable.Creator<StoreModel> CREATOR = new Parcelable.Creator<StoreModel>() {
#Override
public StoreModel createFromParcel(Parcel source) {
return new StoreModel(source);
}
#Override
public StoreModel[] newArray(int size) {
return new StoreModel[size];
}
};
}
Create a "store_item.xml" :
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coordinator_game_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/store_item_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="#android:color/transparent"
card_view:cardElevation="0dp"
android:layout_marginTop="#dimen/dp_five">
<TextView
android:id="#+id/txtStoreName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Store Name"
android:textSize="18sp" />
</android.support.v7.widget.CardView>
</android.support.design.widget.CoordinatorLayout>
Now in you Activity or Fragment class, call this method to set Adapter:
private void setBottomViewAdapter() {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerStore.setHasFixedSize(true);
// use a linear layout manager
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerStore.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mStoreList = new ArrayList<>();
mStoreList.add(new StoreModel(1001, "Von's", "9860 National Blvd., Los Angeles", "Culver City", 12, 28.624035, 77.365541, getGamesList(8)));
mStoreList.add(new StoreModel(1002, "Jack", "1311 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.622665, 77.364082, getGamesList(6)));
mStoreList.add(new StoreModel(1003, "Ian", "1430 S Fairfax Ave., Los Angeles", "Culver City", 8, 28.620899, 77.365258, getGamesList(2)));
mStoreList.add(new StoreModel(1004, "Jessica Alberto", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.623890, 77.374136, getGamesList(10)));
mStoreList.add(new StoreModel(1005, "Robert", "2545 National Blvd, Los Angeles", "Culver City", 6, 28.631175, 77.375661, getGamesList(4)));
mStoreList.add(new StoreModel(1006, "Clark", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.627153, 77.381809, getGamesList(11)));
mStoreList.add(new StoreModel(1007, "Jason", "9860 National Blvd., Los Angeles", "Culver City", 12, 28.626569, 77.371963, getGamesList(3)));
mStoreList.add(new StoreModel(1008, "Papon", "1372 Wilshire Blvd., Santa Monica", "Mid City", 10, 28.623155, 77.371677, getGamesList(2)));
mStoreList.add(new StoreModel(1009, "Von's", "2545 National Blvd, Los Angeles", "Culver City", 11, 28.611569, 77.38545, getGamesList(13)));
mStoreList.add(new StoreModel(1010, "Robert Downey Jr.", "1430 S Fairfax Ave., Los Angeles", "Culver City", 8, 28.623127, 77.369113, getGamesList(4)));
mStoreList.add(new StoreModel(1011, "Ben Affleck", "1335 Wilshire Blvd., Santa Monica", "Mid City", 4, 28.62373, 77.39452, getGamesList(12)));
mStoreListAdapter = new StoreListAdapter(getActivity());
boolean isAnimate = false;
mStoreListAdapter.setData(mStoreList, isAnimate);
mStoreListAdapter.setCallback(R.layout.store_item, new StoreListAdapter.IClickable() {
#Override
public void init(View view) {
// Toast.makeText(getActivity(), "Initialized", Toast.LENGTH_SHORT).show();
}
#Override
public void execute(StoreListAdapter.ViewHolder viewHolder, Object object, int position) {
final StoreModel model = (StoreModel) object;
View view = viewHolder.itemView;
StoreListAdapter.ViewHolder holder = viewHolder;
final CoordinatorLayout fabGameview = (CoordinatorLayout) view;
final CardView cardView = (CardView) fabGameview.findViewById(R.id.store_item_cardview);
TextView txtStoreName = (TextView) cardView.findViewById(R.id.txtStoreName);
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
boolean isAddedToBackStack = true;
StoreDetailsAndProductListFragment storeDetailsAndProductListFragment = new StoreDetailsAndProductListFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(ExtrasUtil.STORE, model);
storeDetailsAndProductListFragment.setArguments(bundle);
showOtherFragment(storeDetailsAndProductListFragment, getActivity().getFragmentManager(), isAddedToBackStack);
}
});
}
});
mRecyclerStore.setAdapter(mStoreListAdapter);
}
Create an interface :
import java.util.ArrayList;
/**
* Created by Deepak Sharma on 3/8/2017.
*/
public interface IFilteredList<T> {
public void onListFiltered(ArrayList<T> list);
}
Create a custom Filterable class StoreSearchFilter.java:
import android.widget.Filter;
import java.util.ArrayList;
import java.util.List;
public final class StoreSearchFilter<T> {
// private final Pattern pattern;
private ArrayList<StoreModel> mList;
private IFilteredList<T> callback;
public StoreSearchFilter(final String regex)
{
// pattern = Pattern.compile(regex);
}
public StoreSearchFilter(ArrayList<StoreModel> list, IFilteredList<T> listener)
{
this.mList = list;
this.callback = listener;
}
#Override
protected Filter.FilterResults performFiltering(CharSequence constraint) {
Filter.FilterResults results = new Filter.FilterResults();
if (constraint == null || constraint.length() == 0) {
results.values = mList;
results.count = mList.size();
}
else {
// Some search copnstraint has been passed
// so let's filter accordingly
ArrayList<StoreModel> filteredContacts = new ArrayList<StoreModel>();
if (mList!=null && mList.size()>0)
{
// We'll go through all the contacts and see
// if they contain the supplied string
for (StoreModel model : mList) {
// TODO Here search for the store name match
if (model.getStoreName().toUpperCase().contains(constraint.toString().toUpperCase())) {
// if `contains` == true then add it
// to our filtered list
filteredContacts.add(model);
}
// TODO Here search for the product name match
else {
List<Games> gameList = model.getGamesList();
if (gameList!=null && gameList.size()>0)
{
for (Games game : gameList) {
if (game.getProductName().toUpperCase().contains(constraint.toString().toUpperCase())) {
filteredContacts.add(model);
break;
}
}
}
}
}
}
// Finally set the filtered values and size/count
results.values = filteredContacts;
results.count = filteredContacts.size();
}
// Return our FilterResults object
return results;
}
#Override
protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
callback.onListFiltered((ArrayList<T>) results.values);
}
}
I am working on a android project where I have 2 Custom spinner
State
City
i am using below code to to populate the spinner with Custom list view.
xml code:
<com.infantstudio.CatholicMithrulu.Spinner.SearchableSpinnerState
android:id="#+id/spinner2"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:entries="#array/state"
app:hintTextState="Select"/>
SearchableListDialogState.class
package com.infantstudio.CatholicMithrulu.Spinner;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SearchView;
import com.infantstudio.CatholicMithrulu.R;
import java.io.Serializable;
import java.util.List;
public class SearchableListDialogState extends DialogFragment implements
SearchView.OnQueryTextListener, SearchView.OnCloseListener {
private static final String ITEMS = "items";
private ArrayAdapter listAdapter;
private ListView _listViewItems;
private SearchableListDialogState.SearchableItem _searchableItem;
private OnSearchTextChanged _onSearchTextChanged;
private SearchView _searchView;
private String _strTitle;
private String _strPositiveButtonText;
private DialogInterface.OnClickListener _onClickListener;
public SearchableListDialogState() {
}
public static SearchableListDialogState newInstance(List items) {
SearchableListDialogState multiSelectExpandableFragment = new
SearchableListDialogState();
Bundle args = new Bundle();
args.putSerializable(ITEMS, (Serializable) items);
multiSelectExpandableFragment.setArguments(args);
return multiSelectExpandableFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams
.SOFT_INPUT_STATE_HIDDEN);
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Getting the layout inflater to inflate the view in an alert dialog.
LayoutInflater inflater = LayoutInflater.from(getActivity());
// Crash on orientation change #7
// Change Start
// Description: As the instance was re initializing to null on rotating the device,
// getting the instance from the saved instance
if (null != savedInstanceState) {
_searchableItem = (SearchableItem) savedInstanceState.getSerializable("item");
}
// Change End
View rootView = inflater.inflate(R.layout.searchable_list_dialog, null);
setData(rootView);
AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
alertDialog.setView(rootView);
String strPositiveButton = _strPositiveButtonText == null ? "CLOSE" : _strPositiveButtonText;
alertDialog.setPositiveButton(strPositiveButton, _onClickListener);
String strTitle = _strTitle == null ? "Select Item" : _strTitle;
alertDialog.setTitle(strTitle);
final AlertDialog dialog = alertDialog.create();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams
.SOFT_INPUT_STATE_HIDDEN);
return dialog;
}
// Crash on orientation change #7
// Change Start
// Description: Saving the instance of searchable item instance.
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putSerializable("item", _searchableItem);
super.onSaveInstanceState(outState);
}
// Change End
public void setTitle(String strTitle) {
_strTitle = strTitle;
}
public void setPositiveButton(String strPositiveButtonText) {
_strPositiveButtonText = strPositiveButtonText;
}
public void setPositiveButton(String strPositiveButtonText, DialogInterface.OnClickListener onClickListener) {
_strPositiveButtonText = strPositiveButtonText;
_onClickListener = onClickListener;
}
public void setOnSearchableItemClickListener(SearchableItem searchableItem) {
this._searchableItem = searchableItem;
}
public void setOnSearchTextChangedListener(OnSearchTextChanged onSearchTextChanged) {
this._onSearchTextChanged = onSearchTextChanged;
}
private void setData(View rootView) {
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context
.SEARCH_SERVICE);
_searchView = (SearchView) rootView.findViewById(R.id.search);
_searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName
()));
_searchView.setIconifiedByDefault(false);
_searchView.setOnQueryTextListener(this);
_searchView.setOnCloseListener(this);
_searchView.clearFocus();
InputMethodManager mgr = (InputMethodManager) getActivity().getSystemService(Context
.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(_searchView.getWindowToken(), 0);
List items = (List) getArguments().getSerializable(ITEMS);
_listViewItems = (ListView) rootView.findViewById(R.id.listItems);
//create the adapter by passing your ArrayList data
listAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1,items);
//attach the adapter to the list
_listViewItems.setAdapter(listAdapter);
_listViewItems.setTextFilterEnabled(true);
_listViewItems.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
_searchableItem.onSearchableItemClicked(listAdapter.getItem(position), position);
getDialog().dismiss();
}
});
}
#Override
public boolean onClose() {
return false;
}
#Override
public boolean onQueryTextSubmit(String s) {
_searchView.clearFocus();
return true;
}
#Override
public boolean onQueryTextChange(String s) {
// listAdapter.filterData(s);
if (TextUtils.isEmpty(s)) {
// _listViewItems.clearTextFilter();
((ArrayAdapter) _listViewItems.getAdapter()).getFilter().filter(null);
} else {
((ArrayAdapter) _listViewItems.getAdapter()).getFilter().filter(s);
}
if (null != _onSearchTextChanged) {
_onSearchTextChanged.onSearchTextChanged(s);
}
return true;
}
public interface SearchableItem<T> extends Serializable {
void onSearchableItemClicked(T item, int position);
}
public interface OnSearchTextChanged {
void onSearchTextChanged(String strText);
}
}
SearchableSpinnerState.class
package com.infantstudio.CatholicMithrulu.Spinner;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.Toast;
import com.infantstudio.CatholicMithrulu.Adddata;
import com.infantstudio.CatholicMithrulu.R;
import java.util.ArrayList;
import java.util.List;
public class SearchableSpinnerState extends Spinner implements View.OnTouchListener,
SearchableListDialogState.SearchableItem {
String selectedItem;
//this string above will store the value of selected item.
public static final int NO_ITEM_SELECTED = -1;
private Context _context;
private List _items;
private SearchableListDialogState _searchableListDialog;
private boolean _isDirty;
private ArrayAdapter _arrayAdapter;
private String _strHintText;
private boolean _isFromInit;
public SearchableSpinnerState(Context context) {
super(context);
this._context = context;
init();
}
public SearchableSpinnerState(Context context, AttributeSet attrs) {
super(context, attrs);
this._context = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SearchableSpinnerState);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i) {
int attr = a.getIndex(i);
if (attr == R.styleable.SearchableSpinnerState_hintTextState) {
_strHintText = a.getString(attr);
}
}
a.recycle();
init();
}
public SearchableSpinnerState(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this._context = context;
init();
}
private void init() {
_items = new ArrayList();
System.out.println("items"+_items);
_searchableListDialog = SearchableListDialogState.newInstance
(_items);
_searchableListDialog.setOnSearchableItemClickListener(this);
setOnTouchListener(this);
_arrayAdapter = (ArrayAdapter) getAdapter();
if (!TextUtils.isEmpty(_strHintText)) {
ArrayAdapter arrayAdapter = new ArrayAdapter(_context, android.R.layout
.simple_list_item_1, new String[]{_strHintText});
_isFromInit = true;
setAdapter(arrayAdapter);
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (null != _arrayAdapter) {
// Refresh content #6
// Change Start
// Description: The items were only set initially, not reloading the data in the
// spinner every time it is loaded with items in the adapter.
_items.clear();
for (int i = 0; i < _arrayAdapter.getCount(); i++) {
_items.add(_arrayAdapter.getItem(i));
}
// Change end.
_searchableListDialog.show(scanForActivity(_context).getFragmentManager(), "TAG");
}
}
return true;
}
#Override
public void setAdapter(SpinnerAdapter adapter) {
if (!_isFromInit) {
_arrayAdapter = (ArrayAdapter) adapter;
if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
ArrayAdapter arrayAdapter = new ArrayAdapter(_context, android.R.layout
.simple_list_item_1, new String[]{_strHintText});
super.setAdapter(arrayAdapter);
} else {
super.setAdapter(adapter);
}
} else {
_isFromInit = false;
super.setAdapter(adapter);
}
}
//The method just below is executed when an item in the searchlist is tapped.This is where we store the value int string called selectedItem.
#Override
public void onSearchableItemClicked(Object item, int position) {
setSelection(_items.indexOf(item));
if (!_isDirty) {
_isDirty = true;
setAdapter(_arrayAdapter);
setSelection(_items.indexOf(item));
}
selectedItem= item.toString().trim();
Adddata.setValueSt(selectedItem);
// Toast.makeText(getContext(),"You selected "+selectedItem, Toast.LENGTH_LONG).show();
}
private Activity scanForActivity(Context cont) {
if (cont == null)
return null;
else if (cont instanceof Activity)
return (Activity) cont;
else if (cont instanceof ContextWrapper)
return scanForActivity(((ContextWrapper) cont).getBaseContext());
return null;
}
#Override
public int getSelectedItemPosition() {
if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
return NO_ITEM_SELECTED;
} else {
return super.getSelectedItemPosition();
}
}
#Override
public Object getSelectedItem() {
if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
return null;
} else {
return super.getSelectedItem();
}
}
}
The above code is working fine, but I need to change the array at run time . Array is declared in the xml file like this
android:entries="#array/state"
How can I modify this array at run time? Any help would be valuable.
--Thanks!
Create ArrayList and insert the entries that you are getting from API or add it.
List < String > list = new ArrayList < > ();
list.add("Male");
list.add("Female");
list.add("Others");
ArrayAdapter < String > dataAdapter = new ArrayAdapter < String > (this, android.R.layout.simple_spinner_item, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerGender.setAdapter(dataAdapter);
or
List<String> list= new ArrayList<>();
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerGender.setAdapter(dataAdapter);
onResposeSucessofAPI(List<String> list){
this.list = list;
dataAdapter.notifyDataSetChanged();
}
Create a arrayList of Strings
ArrayList<String> area = new ArrayList<>();
add values in area arrayList
area.add("value1");
area.add("value2");
Now set adapter
yourSpinner.setAdapter(new ArrayAdapter<String>(context
, android.R.layout.simple_list_item_1, area));
Anything declared in Resources, cannot be changed at Runtime
You must do it by java code
Am looking sample program which could dynamically populating Spinner item from server using Retrofit 1.9 but still I couldn't find any sample can someone share if there is any sample regarding this requirement or else share the method.
How it should be done as am new for android bit struggling to find a solution thanks in advance!
Here is my spinneritem class:
public class MySpinnerItem {
public MySpinnerItem(){
}
public MySpinnerItem(String text, Integer value) {
Text = text;
Value = value;
}
public String getText() {
return Text;
}
public void setText(String text) {
Text = text;
}
public Integer getValue() {
return Value;
}
public void setValue(Integer value) {
Value = value;
}
public String Text;
public Integer Value;
}
Here is my spinner adapter:
package first.service.precision.servicefirst;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
/**
* Created by 4264 on 25-11-2015.
*/
public class MySpinnerAdapter extends ArrayAdapter<MySpinnerItem> {
private Context context;
private List<MySpinnerItem> objects;
public MySpinnerAdapter(Context context, int resource, List<MySpinnerItem> objects) {
super(context, resource, objects);
this.context = context;
this.objects = objects;
}
#Override
public void add(MySpinnerItem object) {
this.objects.add(object);
}
#Override
public int getCount() {
return objects.size();
}
#Override
public MySpinnerItem getItem(int position) {
return objects.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView label = new TextView(context);
label.setText(objects.get(position).getText());
return label;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
TextView label = new TextView(context);
label.setText(objects.get(position).getText());
return label;
}
}
Here is the fragment where i set adapter for spinners:
package first.service.precision.servicefirst;
/**
* Created by 4264 on 23-11-2015.
*/
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import com.squareup.otto.Bus;
import java.util.ArrayList;
import java.util.List;
public class NewRequirements extends Fragment {
Bus bus;
MyListAdapter listAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
List<MySpinnerItem> SbuList = new ArrayList<MySpinnerItem>();
SbuList.add(new MySpinnerItem("Saravanan.R",1));
SbuList.add(new MySpinnerItem("Yogeshwaran",2));
SbuList.add(new MySpinnerItem("Sathesh",3));
SbuList.add(new MySpinnerItem("Barath",4));
SbuList.add(new MySpinnerItem("Deepak",5));
SbuList.add(new MySpinnerItem("Venkat",6));
SbuList.add(new MySpinnerItem("Meena",7));
SbuList.add(new MySpinnerItem("Ram",8));
SbuList.add(new MySpinnerItem("Jegan",9));
View view = inflater.inflate(R.layout.fragment_dialog_claim, container,
false);
final Button btnupdate;
btnupdate = (Button) view.findViewById(R.id.btnAdd);
final Spinner spSbuID = (Spinner) view.findViewById(R.id.spSbuID);
final Spinner spBuID = (Spinner) view.findViewById(R.id.spBuID);
final Spinner spSubBuID = (Spinner) view.findViewById(R.id.spSubBuID);
final Spinner spServiceCategoryID = (Spinner) view.findViewById(R.id.spServiceCategoryID);
final Spinner spServiceSubCategoryID = (Spinner) view.findViewById(R.id.spServiceSubCategoryID);
final EditText txtRequirements=(EditText)view.findViewById(R.id.txtRequirements);
MySpinnerAdapter myadapter = new MySpinnerAdapter(getActivity().getBaseContext(),android.R.layout.simple_spinner_dropdown_item,SbuList);
spSbuID.setAdapter(myadapter);
myadapter = new MySpinnerAdapter(getActivity().getBaseContext(),android.R.layout.simple_spinner_dropdown_item,SbuList);
spBuID.setAdapter(myadapter);
myadapter = new MySpinnerAdapter(getActivity().getBaseContext(),android.R.layout.simple_spinner_dropdown_item,SbuList);
spSubBuID.setAdapter(myadapter);
myadapter = new MySpinnerAdapter(getActivity().getBaseContext(),android.R.layout.simple_spinner_dropdown_item,SbuList);
spServiceCategoryID.setAdapter(myadapter);
myadapter = new MySpinnerAdapter(getActivity().getBaseContext(),android.R.layout.simple_spinner_dropdown_item,SbuList);
spServiceSubCategoryID.setAdapter(myadapter);
try{
Object o;
o = getFragmentManager().findFragmentByTag("add");
Log.v("FIND", o.toString());
}
catch (Exception ex) {
Log.v("FIND", ex.toString());
}
// add.notify();
btnupdate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LeadRequirementsView objLeadRequirementsView = new LeadRequirementsView();
MySpinnerItem item;
item = (MySpinnerItem)spSbuID.getSelectedItem();
objLeadRequirementsView.setSbuID(item.getValue());
objLeadRequirementsView.setSbuName(item.getText());
item = (MySpinnerItem)spBuID.getSelectedItem();
objLeadRequirementsView.setBuID(item.getValue());
objLeadRequirementsView.setBuName(item.getText());
item = (MySpinnerItem)spSubBuID.getSelectedItem();
objLeadRequirementsView.setSubBuID(item.getValue());
objLeadRequirementsView.setSubBuName(item.getText());
item = (MySpinnerItem)spServiceCategoryID.getSelectedItem();
objLeadRequirementsView.setServiceCategoryID(item.getValue());
objLeadRequirementsView.setServiceCategoryName(item.getText());
item = (MySpinnerItem)spServiceSubCategoryID.getSelectedItem();
objLeadRequirementsView.setServiceSubCategoryID(item.getValue());
objLeadRequirementsView.setServiceSubCategoryName(item.getText());
objLeadRequirementsView.setDescription(txtRequirements.getText().toString());
Add add;
add = (Add)getFragmentManager().findFragmentByTag("add");
add.updateListView(objLeadRequirementsView);
getActivity().getFragmentManager().popBackStack();
}
});
return view;
}
}
My doubt is i have done it using dummy data but i need to bind the json response from the server to my spinner how come i do this.
Below, is a sample for setting the spinner
Spinner spinner = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<String> adapter;
List<String> data;
data = new ArrayList<>();
for (int i = 0; i < 20; i++)
data.add("Data " + (i + 1));
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data);
spinner.setAdapter(adapter);
Here data is a dummy data , in your case it will be dummy data.
first create theretrofitapi interface
/**
* reCreated by goodlife on 1/11/2016.
*/
import java.util.List;
import retrofit.Callback;
import retrofit.client.Response;
import retrofit.http.Field;
import retrofit.http.FormUrlEncoded;
import retrofit.http.GET;
import retrofit.http.POST;
/**
* Created by Belal on 11/5/2015.
*/
public interface RetrofitInternetApi {
//#FormUrlEncoded, we have to write this if we want to send post data to the server.
//#POST, because we are using an HTTP Post request we have written this.
// Inside it we have the URL of the script that will be receiving the post request.
// Note that the URL is excluding the root URL. And we have defined the root URL in our MainActivity.
//#Field(“key”) String variable inside key we have to write what we have written inside $_POST[‘key’] in our script.
// And we have to specify it for all the values we are going to send.
//Callback<Response> callback it is also inside the retrofit library. It will receive the output from the server.
//But this is only an interface and the method is abstract.
//We will define the method inside fetchDepartmentName() method that is declared inside MainActivity.java.
#GET("/getDepartmentName.php")
public void getDepartmentName(Callback<List<DepartmentNoRealm>> response);
}
then create the function
private void fetchDepartmentName(){
//Creating a rest adapter
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(ROOT_URL)
.build();
//Creating an object of our api interface
RetrofitInternetApi retrofitInternetApi = restAdapter.create(RetrofitInternetApi.class);
//While the app fetched data we are displaying a progress dialog
final ProgressDialog loading = ProgressDialog.show(getActivity(), "Fetching Data", "Please wait...", false, false);
//Defining the method
retrofitInternetApi.getDepartmentName(new Callback<List<DepartmentNoRealm>>() {
#Override
public void success(List<DepartmentNoRealm> list, Response response) {
//Dismissing the loading progressbar
loading.dismiss();
Log.d("JSON LIST",list.toString());
//Storing the data in our list
departmentNoRealmList = list;
//Calling a method to show the list
showListinSpinner(); }
#Override
public void failure(RetrofitError error) {
//you can handle the errors here
}
});
}
then create a class model
package myafya.safaricom.co.ke.myafya.model.realm;
/**
* Created by 001557 on 1/13/2016.
*/
public class DepartmentNoRealm {
public int departmentID;
public String departmentName;
public String departmentURLimage;
public int getDepartmentID() {
return departmentID;
}
public void setDepartmentID(int departmentID) {
this.departmentID = departmentID;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public String getDepartmentURLimage() {
return departmentURLimage;
}
public void setDepartmentURLimage(String departmentURLimage) {
this.departmentURLimage = departmentURLimage;
}
}
now the code showList in Spinner
//Our method to show list
private void showListinSpinner(){
//String array to store all the book names
String[] items = new String[departmentNoRealmList.size()];
//Traversing through the whole list to get all the names
for(int i=0; i<departmentNoRealmList.size(); i++){
//Storing names to string array
items[i] = departmentNoRealmList.get(i).getDepartmentName();
}
//Spinner spinner = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter<String> adapter;
adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, items);
//setting adapter to spinner
spinnerDepartments.setAdapter(adapter);
//Creating an array adapter for list view
}
Then SHARE IT AND MAKE IT EASY
MY JSON WAS
[
{
"departmentID": "1",
"departmentName": "Enterprise Business Unit (EBU)",
"departmentURLimage": "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcSKOZmGNAA08NbHwRJrloAouWqs6r4x7BGXY4k-ULWiHuPEobHI"
},
{
"departmentID": "2",
"departmentName": "Consumer Business Unit (CBU)",
"departmentURLimage": "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQ0IAFhZ52KiG_0ck5VbBxweZWf_MEA9eRmgHAEr6CG-rUG_a2QEQ"
}
]
try {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
APIService service = retrofit.create(APIService.class);
Call<List<People>> call = service.getYear(user_id);
call.enqueue(new Callback<List<People>>()
{
#Override
public void onResponse(Response<List<People>> response, Retrofit retrofit) {
posts = response.body();
String[] s =new String[posts.size()];
for(int i=0;i<posts.size();i++)
{
s[i]= posts.get(i).getYear();
final ArrayAdapter a = new ArrayAdapter(getApplicationContext(), android.R.layout.simple_spinner_item, s);
a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//Setting the ArrayAdapter data on the Spinner
Branch.setAdapter(a);
}
}
#Override
public void onFailure(Throwable t) { }
});
} catch (Exception e) {
Log.d("onResponse", "There is an error");
}
}
I am having problem with fragments.I am developing an app like 360 security and i am having problem implementing fragments ,getting "Binary XML file line #1: Error inflating class fragment".
Here is my xml file.I have tried every solution please help me.
Thanks in advance.
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/item_list"
android:name="sabby.completesecurity.MainListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemListActivity"
tools:layout="#android:layout/list_content" />
This is my activity file:
package sabby.completesecurity;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.FrameLayout;
import android.widget.ImageView;
import sabby.completesecurity.R;
public class MainActivityCache extends FragmentActivity implements sabby.completesecurity.MainCallbacks {
private boolean mIsDualPane;
private boolean mIsArtShowed = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_cache);
mIsDualPane = findViewById(R.id.item_detail_container) != null;
//Show an art when no fragment is showed, we make sure no detail fragment is present.
if (mIsDualPane && getFragmentManager().findFragmentByTag(sabby.completesecurity.DetailFragment.FRAGMENT_TAG) == null) {
ImageView imageView = new ImageView(this);
imageView.setImageResource(R.mipmap.ic_launcher);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
((FrameLayout) findViewById(R.id.item_detail_container)).addView(imageView);
mIsArtShowed = true;
}
}
#Override
public void onItemSelected(String packageName) {
if (mIsDualPane) {
//Hide art when a fragment is showed.
if (mIsArtShowed) {
((FrameLayout) findViewById(R.id.item_detail_container)).removeAllViews();
mIsArtShowed = false;
}
getFragmentManager()
.beginTransaction()
.replace(R.id.item_detail_container, DetailFragment.getInstance(packageName), DetailFragment.FRAGMENT_TAG)
.commit();
} else {
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra(DetailFragment.EXTRA_PACKAGE_NAME, packageName);
startActivity(intent);
}
}
#Override
protected void onStart() {
super.onStart();
registerReceiver(receiver, getIntentFilter());
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(receiver);
}
private void showAboutDialog() {
new AlertDialog.Builder(this)
.setTitle("About")
.setView(getLayoutInflater().inflate(R.layout.about_dialog_message, null))
.setNegativeButton(android.R.string.ok, null)
.show();
}
/**
* Used to update the list if a package is added or removed.
*/
private IntentFilter getIntentFilter() {
IntentFilter filter = new IntentFilter();
filter.addDataScheme("package");
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
return filter;
}
enter code here
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MainListFragment mainListFragment = (MainListFragment) getFragmentManager().findFragmentById(R.id.item_list);
if (mainListFragment != null)
mainListFragment.loadList();
}
};
}
MainListFragment.java
package sabby.completesecurity;
import android.app.ActionBar;
import android.app.Activity;
import android.app.ListFragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.SectionIndexer;
import android.widget.Spinner;
import android.widget.TextView;
import sabby.completesecurity.utils.Utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
public class MainListFragment extends ListFragment implements AdapterView.OnItemClickListener, AdapterView.OnItemSelectedListener {
private static final int SORT_NAME = 0;
private static final int SORT_PKG = 1;
private static final int SORT_DOMAIN = 2;
private static final int SORT_INSTALLATION = 3;
private static final int SORT_SIZE = 4;
private static final String INSTANCE_STATE_SORT_BY = "sort_by";
private Adapter mAdapter;
private List<Item> mItemList = new ArrayList<Item>();
private int mOnSizeFinishedItemCount;
private PackageManager mPackageManager;
private ProgressDialog mProgressDialog;
private LayoutInflater mLayoutInflater;
private MainCallbacks mCallbacks;
private Context mContext;
private Async mAsyncLoader;
private Spinner mSpinner;
private boolean mSpinnerListenerAuthorized;
private SimpleDateFormat mSimpleDateFormat;
private int mSortBy = 0;
class Item {
ApplicationInfo applicationInfo;
String label;
Long date;
Long size = -1L;
}
private int mColorGrey1;
private int mColorGrey2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mProgressDialog = new ProgressDialog(mContext);
mProgressDialog.setTitle(R.string.loading_apps);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
//Used to prevent message not showing later
mProgressDialog.setMessage("");
mPackageManager = mContext.getPackageManager();
mSimpleDateFormat = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
mColorGrey1 = getResources().getColor(R.color.grey_1);
mColorGrey2 = getResources().getColor(R.color.grey_2);
ActionBar actionBar = getActivity().getActionBar();
actionBar.setDisplayShowCustomEnabled(true);
mSpinner = new Spinner(actionBar.getThemedContext());
SpinnerAdapter spinnerAdapter = new SpinnerAdapter(actionBar.getThemedContext(),
R.array.sort_spinner_items, android.R.layout.simple_list_item_1);
mSpinner.setAdapter(spinnerAdapter);
mSpinnerListenerAuthorized = false;
mSpinner.setOnItemSelectedListener(this);
ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
actionBar.setCustomView(mSpinner, layoutParams);
if (savedInstanceState != null)
setSortBy(savedInstanceState.getInt(INSTANCE_STATE_SORT_BY, -1), false);
}
#Override
public void onStart() {
super.onStart();
mSpinner.setSelection(mSortBy);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(INSTANCE_STATE_SORT_BY, mSortBy);
}
private void onTaskEnded(List<Item> list) {
RetainedFragment retainedFragment = (RetainedFragment) getFragmentManager().findFragmentByTag(RetainedFragment.FRAGMENT_TAG);
retainedFragment.setList(list);
mItemList = list;
mAdapter.notifyDataSetChanged();
if (getListView().getAdapter() == null)
setListAdapter(mAdapter);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getListView().setOnItemClickListener(this);
getListView().setFastScrollEnabled(true);
mAdapter = new Adapter();
RetainedFragment retainedFragment = (RetainedFragment) getFragmentManager()
.findFragmentByTag(RetainedFragment.FRAGMENT_TAG);
if (retainedFragment == null) {
retainedFragment = new RetainedFragment();
getFragmentManager()
.beginTransaction()
.add(retainedFragment, RetainedFragment.FRAGMENT_TAG)
.commit();
}
if (retainedFragment.getList() != null) {
onTaskEnded(retainedFragment.getList());
mOnSizeFinishedItemCount = mItemList.size();
//Notify spinner that size sort is available
SpinnerAdapter adapter = (SpinnerAdapter) mSpinner.getAdapter();
adapter.notifyDataSetChanged();
} else
loadList();
}
public void loadList() {
mAsyncLoader = new Async();
mAsyncLoader.execute();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (MainCallbacks) activity;
mContext = activity;
mLayoutInflater = activity.getLayoutInflater();
}
#Override
public void onDetach() {
super.onDetach();
if (mAsyncLoader != null)
mAsyncLoader.cancel(true);
mCallbacks = null;
mContext = null;
mLayoutInflater = null;
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (mCallbacks != null)
mCallbacks.onItemSelected(mItemList.get(i).applicationInfo.packageName);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_main_list, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
loadList();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if (mSpinnerListenerAuthorized)
setSortBy(i, true);
mSpinnerListenerAuthorized = true;
}
/**
* Sort main list if provided value is valid.
* #param sort Must be one of SORT_*
* #param checkViews Set if views have to be updated, eg. when restoring state, views aren't
* created yet, so value must be false
*/
public void setSortBy(int sort, boolean checkViews) {
if (sort >= SORT_NAME && sort <= SORT_SIZE) {
mSortBy = sort;
if (checkViews) {
checkFastScroll();
sortApplicationList(mItemList, mSortBy);
mAdapter.notifyDataSetChanged();
}
}
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
private void checkFastScroll() {
getListView().setFastScrollEnabled(mSortBy == SORT_NAME);
}
public void sortApplicationList(List<Item> list, final int sortBy) {
Collections.sort(list, new Comparator<Item>() {
#Override
public int compare(Item item1, Item item2) {
switch (sortBy) {
case SORT_NAME:
return item1.label.compareTo(item2.label);
case SORT_PKG:
return item1.applicationInfo.packageName.compareTo(item2.applicationInfo.packageName);
case SORT_DOMAIN:
boolean isSystem1 = (item1.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
boolean isSystem2 = (item2.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
return Utils.compareBooleans(isSystem1, isSystem2);
case SORT_INSTALLATION:
//Sort in decreasing order
return -item1.date.compareTo(item2.date);
case SORT_SIZE:
return -item1.size.compareTo(item2.size);
default:
return 0;
}
}
});
}
/**
* This method is called by each item when it has finished retrieving its size
* When all items have finished, we set size sort available in spinner, and invalidate
* main list to display sizes in UI.
*/
private void onItemFinishedSizeProcess() {
mOnSizeFinishedItemCount ++;
if (mOnSizeFinishedItemCount == mItemList.size()) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
SpinnerAdapter adapter = (SpinnerAdapter) mSpinner.getAdapter();
adapter.notifyDataSetChanged();
mAdapter.notifyDataSetChanged();
}
});
}
}
class Adapter extends BaseAdapter implements SectionIndexer {
class ViewHolder {
ImageView icon;
TextView label;
TextView packageName;
TextView version;
TextView isSystemApp;
TextView date;
TextView size;
IconAsyncTask iconLoader;
}
String sections = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#Override
public int getCount() {
return mItemList.size();
}
#Override
public Object getItem(int i) {
return mItemList.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
view = mLayoutInflater.inflate(R.layout.main_list_item, null);
holder = new ViewHolder();
holder.icon = (ImageView) view.findViewById(R.id.icon);
holder.label = (TextView) view.findViewById(R.id.label);
holder.packageName = (TextView) view.findViewById(R.id.packageName);
holder.version = (TextView) view.findViewById(R.id.version);
holder.isSystemApp = (TextView) view.findViewById(R.id.isSystem);
holder.date = (TextView) view.findViewById(R.id.date);
holder.size = (TextView) view.findViewById(R.id.size);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
holder.iconLoader.cancel(true);
}
view.setBackgroundColor(i % 2 == 0 ? mColorGrey2 : mColorGrey1);
Item item = mItemList.get(i);
ApplicationInfo info = item.applicationInfo;
try {
PackageInfo packageInfo = mPackageManager.getPackageInfo(info.packageName, 0);
holder.version.setText(packageInfo.versionName);
Date date = new Date(packageInfo.firstInstallTime);
holder.date.setText(mSimpleDateFormat.format(date));
} catch (PackageManager.NameNotFoundException e) {
//Do nothing
}
holder.iconLoader = new IconAsyncTask(holder.icon, info);
holder.iconLoader.execute();
holder.label.setText(info.loadLabel(mPackageManager));
holder.packageName.setText(info.packageName);
boolean isSystemApp = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
holder.isSystemApp.setText(isSystemApp ? getString(R.string.system) : getString(R.string.user));
if (item.size != -1L)
holder.size.setText(Formatter.formatFileSize(getActivity(), item.size));
return view;
}
#Override
public int getPositionForSection(int section) {
for (int i = 0; i < this.getCount(); i++) {
String item = mItemList.get(i).label;
if (item.charAt(0) == sections.charAt(section))
return i;
}
return 0;
}
#Override
public int getSectionForPosition(int i) {
return 0;
}
#Override
public Object[] getSections() {
String[] sectionsArr = new String[sections.length()];
for (int i = 0; i < sections.length(); i++)
sectionsArr[i] = "" + sections.charAt(i);
return sectionsArr;
}
class IconAsyncTask extends AsyncTask<Void, Integer, Drawable> {
ImageView imageView;
ApplicationInfo info;
IconAsyncTask(ImageView imageView, ApplicationInfo info) {
this.imageView = imageView;
this.info = info;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
imageView.setVisibility(View.INVISIBLE);
}
#Override
protected Drawable doInBackground(Void... voids) {
if (!isCancelled())
return info.loadIcon(mPackageManager);
return null;
}
#Override
protected void onPostExecute(Drawable drawable) {
super.onPostExecute(drawable);
imageView.setImageDrawable(drawable);
imageView.setVisibility(View.VISIBLE);
}
}
}
class SpinnerAdapter extends BaseAdapter {
private Context mContext;
private int mLayoutResId;
private String[] mItems;
public SpinnerAdapter(Context themedContext, int arrayResId, int layoutResId) {
mContext = themedContext;
mItems = themedContext.getResources().getStringArray(arrayResId);
mLayoutResId = layoutResId;
}
#Override
public int getCount() {
return mItems.length;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
//It make no sense to implement recycled view system because there is only 5 items in list
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = View.inflate(mContext, mLayoutResId, null);
if (view instanceof TextView)
((TextView) view).setText(mItems[i]);
return view;
}
/**
* Set sort_by_size item disabled if all items haven't retrieved them size.
*/
#Override
public boolean isEnabled(int position) {
return position != SORT_SIZE || mItemList != null && mOnSizeFinishedItemCount == mItemList.size();
}
}
class Async extends AsyncTask<Void, Async.Progress, List<Item>> {
class Progress {
String label;
int totalSize;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.show();
}
#Override
protected List<Item> doInBackground(Void... voids) {
List<ApplicationInfo> applicationInfos = mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA);
Progress progress = new Progress();
progress.totalSize = applicationInfos.size();
List<Item> itemList = new ArrayList<Item>(applicationInfos.size());
mOnSizeFinishedItemCount = 0;
for (ApplicationInfo applicationInfo : applicationInfos) {
if (isCancelled())
break;
Item item = new Item();
item.applicationInfo = applicationInfo;
String label = applicationInfo.loadLabel(mPackageManager).toString();
item.label = label;
try {
item.date = mPackageManager.getPackageInfo(applicationInfo.packageName, 0).firstInstallTime;
} catch (PackageManager.NameNotFoundException e) {
item.date = 0L;
}
itemList.add(item);
getItemSize(item);
progress.label = label;
publishProgress(progress);
}
sortApplicationList(itemList, mSortBy);
return itemList;
}
private void getItemSize(final Item item) {
try {
Method getPackageSizeInfo = mPackageManager.getClass().getMethod(
"getPackageSizeInfo", String.class, IPackageStatsObserver.class);
getPackageSizeInfo.invoke(mPackageManager, item.applicationInfo.packageName, new IPackageStatsObserver.Stub() {
#Override
public void onGetStatsCompleted(final PackageStats pStats, boolean succeeded)
throws RemoteException {
if (succeeded)
item.size = pStats.codeSize + pStats.cacheSize + pStats.dataSize
+ pStats.externalCodeSize + pStats.externalCacheSize + pStats.externalDataSize
+ pStats.externalMediaSize + pStats.externalObbSize;
else
item.size = -1L;
onItemFinishedSizeProcess();
}
});
} catch (NoSuchMethodException e) {
e.printStackTrace();
onItemFinishedSizeProcess();
} catch (IllegalAccessException e) {
e.printStackTrace();
onItemFinishedSizeProcess();
} catch (InvocationTargetException e) {
e.printStackTrace();
onItemFinishedSizeProcess();
}
}
#Override
protected void onProgressUpdate(Progress... values) {
super.onProgressUpdate(values);
Progress progress = values[0];
mProgressDialog.setMessage(progress.label);
if (mProgressDialog.getMax() == 100)
mProgressDialog.setMax(progress.totalSize);
mProgressDialog.incrementProgressBy(1);
}
#Override
protected void onPostExecute(List<Item> list) {
super.onPostExecute(list);
mProgressDialog.hide();
onTaskEnded(list);
}
#Override
protected void onCancelled(List<Item> list) {
super.onCancelled(list);
mProgressDialog.hide();
}
}
}
In the xml that you have posted,replace the TAG <Fragment> with <LinearLayout> or <RelativeLayout> and inside this you simply show what you want to display in you UI
Make sure you extend Fragment class in you fragment activity
Could you post the code for your fragment? The problem could be with your import statements. You have 'import android.support.v4.app.FragmentActivity'. Do you have 'import android.support.v4.app.Fragment' in your fragment file?
Clearing or adding data does not get updated in the method addData in my custom ArrayAdapter class. What is going on? I have also tried updating the List which is fed into the ArrayAdapter and that does not get changed either, both times the amount of items in the adapter stay the same. Please help!
Class:
package sukh.app.ireddit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
/**
* While this looks like a lot of code, all this class
* actually does is load the posts in to the listview.
*
* #author Hathy
*/
public class PostsFragment extends Fragment{
ListView postsList;
PostAdapter adapter;
Handler handler;
Activity activity;
String subreddit;
List<Post> posts;
PostsHolder postsHolder;
public PostsFragment(){
handler=new Handler();
posts=new ArrayList<Post>();
activity=getActivity();
}
public static Fragment newInstance(String subreddit){
PostsFragment pf=new PostsFragment();
pf.subreddit=subreddit;
pf.postsHolder=new PostsHolder(pf.subreddit);
return pf;
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.posts
, container
, false);
postsList=(ListView)v.findViewById(R.id.posts_list);
return v;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initialize();
}
private void initialize(){
// This should run only once for the fragment as the
// setRetainInstance(true) method has been called on
// this fragment
if(posts.size()==0){
// Must execute network tasks outside the UI
// thread. So create a new thread.
new Thread(){
public void run(){
posts.addAll(postsHolder.fetchPosts());
// UI elements should be accessed only in
// the primary thread, so we must use the
// handler here.
handler.post(new Runnable(){
public void run(){
createAdapter();
}
});
}
}.start();
}else{
createAdapter();
}
}
/**
* This method creates the adapter from the list of posts
* , and assigns it to the list.
*/
private void createAdapter(){
// Make sure this fragment is still a part of the activity.
if(getActivity()==null) return;
adapter=new PostAdapter(posts);
postsList.setAdapter(adapter);
Log.i("sukh", "setting adapter");
postsList.setOnScrollListener(adapter);
}
protected class PostAdapter extends ArrayAdapter<Post> implements OnScrollListener {
private int previousTotal = 0;
private boolean loading = true;
//PostAdapter _adapter = this;
public PostAdapter(List<Post> posts){
super(getActivity(), R.layout.post_item, posts);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = getActivity().getLayoutInflater().inflate(R.layout.post_item, null);
}
Post thePost = getItem(position);
TextView postTitleTextView = (TextView) convertView.findViewById(R.id.post_title);
postTitleTextView.setText(thePost.getTitle());
TextView postDetailsTextView = (TextView) convertView.findViewById(R.id.post_details);
postDetailsTextView.setText(thePost.getDetails());
TextView postScoreTextView = (TextView) convertView.findViewById(R.id.post_score);
postScoreTextView.setText(thePost.getScore());
return convertView;
}
private void addData() {
//final List<Post> newPosts = new ArrayList<Post>();
Log.i("update1", this.adapterToString());
new Thread(){
public void run(){
//neither of these following statements make a difference
//neither does posts.clear() or posts.addAll...
//adapter.addAll(postsHolder.fetchMorePosts());
adapter.clear();
}
};
Log.i("sukh", "executed scroll");
adapter.notifyDataSetChanged();
Log.i("update2", this.adapterToString());
}
private String adapterToString() {
StringBuilder sb = new StringBuilder();
int total = this.getCount();
sb.append("contents: ");
/*for (int i = 0; i < this.getCount(); i ++) {
sb.append(this.getItem(i).title + "/n");
}*/
//return sb.toString();
return sb.append(total).toString();
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading &&
(firstVisibleItem + visibleItemCount + 1 >= totalItemCount)
) {
addData();
loading = true;
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
}
EDIT: fixed. Added new class that extends ASyncTask and had it fetchMorePosts before updating the adapter.
Class is shown :
private class AddPostsTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Log.i("update2", "start fetchMorePosts");
posts.addAll(postsHolder.fetchMorePosts());
Log.i("update2", "end fetchMorePosts");
return null;
}
#Override
protected void onPostExecute(Void result) {
Log.i("update2", "start adapterChange");
adapter.notifyDataSetChanged();
Log.i("update2", "start adapterChange");
super.onPostExecute(result);
}
}
in your addData function, you're clearing adapter in a thread 'after' notifyDataSetChanged() is called.