Android CursorAdapter not refreshing on first load - android

EDIT I didn't add my XML
I am writing a dialog for tagging selections. The first view is applying tags they have in their db. The next screen is a dialog for adding new tags to their db. I am supplying suggestions for them to use for their tags. I want to filter the list when they begin typing in their tag. I am using two custom CursorAdapters for each screen but they share the same ListView. I am also using a CursorLoader to run my queries in the background both are extended from the support library.
When I open the new tag screen the first time, after the dialog comes up, the list doesn't refresh with the filtered cursor in Android 4.0.3 nor does the quick scroll work. If I switch to the tag view and then back to the new tag dialog it filters and scrolls like it should.. My query works and the code works in Android 2.3.3 every time. I can't figure out why this is not working. Here is my code for the CursorLoader and the Suggestion adapter.
package org.lds.ldssa;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
import org.lds.ldssa.service.MLDatabase;
import org.lds.ldssa.service.aws.Annotation;
public class TagDialog extends AlertDialog implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String TAG = "ldssa.tagdialog";
public static final int TAGLOADERID = 0;
// View Items
private EditText mEditText;
private ListView mListView;
private TextView mEmptyView;
private ProgressBar mProgressBar;
private ImageButton mNewTagButton;
private ImageButton mSortTagButton;
private TextView mTitle;
private Button mOkButton;
private Button mCancelButton;
private String mTagTitle;
private String mNewTagTitle;
private Annotation mAnnotation;
private ContentFragment mContentFragment;
private boolean isNewTagView;
private static final String KEY_NEWTAGVIEW = "new_tag_view";
private SimpleCursorAdapter mSuggestionAdapter;
private TagListAdapter mTagAdapter;
private MLDatabase mlDatabase;
protected TagDialog(Context context) {
super(context);
}
public void onCreate(Bundle savedInstanceState){
Context context = getContext();
Resources r = context.getResources();
final LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.dialog_tag, null);
// Main parts of the view
mEditText = (EditText) view.findViewById(R.id.tag_new_tag);
mListView = (ListView) view.findViewById(android.R.id.list);
mProgressBar = (ProgressBar) view.findViewById(R.id.tag_spin_progress_bar);
mEmptyView = (TextView) view.findViewById(android.R.id.empty);
mEmptyView.setVisibility(View.INVISIBLE);
// Titlebar
View titleBar = inflater.inflate(R.layout.dialog_tag_title, null);
mNewTagButton = (ImageButton) titleBar.findViewById(R.id.tag_new_icon);
mSortTagButton = (ImageButton) titleBar.findViewById(R.id.tag_sort_icon);
mTitle = (TextView) titleBar.findViewById(R.id.tag_title);
mTagTitle = r.getString(R.string.tag_dialog_title);
mNewTagTitle = r.getString(R.string.tag_new_dialog_title);
this.setCustomTitle(titleBar);
// Buttons
final String OK = r.getString(R.string.ok);
final String CANCEL = r.getString(R.string.cancel);
this.setButton(BUTTON_POSITIVE, OK, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) { /*Never Used*/}});
this.setButton(BUTTON_NEGATIVE, CANCEL, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) { /*Never Used*/}});
// Setup Button Listeners
setOnShowListener(new OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
Button ok = getButton(BUTTON_POSITIVE);
ok.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isNewTagView){
hideIMM();
setupTagDialog();
mEditText.setText("");
} else {
dismiss();
}
}
});
Button cancel = getButton(BUTTON_NEGATIVE);
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isNewTagView){
hideIMM();
setupTagDialog();
mEditText.setText("");
} else {
dismiss();
}
}
});
}
});
mNewTagButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setupNewTagDialog();
}
});
mSortTagButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
mEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void afterTextChanged(Editable s) {
LoaderManager lm = getLoaderManager();
if(lm != null){
Loader l = lm.getLoader(TAGLOADERID);
if(l != null){
l.forceLoad();
} else {
restartLoader();
}
} else {
restartLoader();
}
}
});
String[] UIBindFrom = {MLDatabase.CL_ID};
int[] UIBindTo = {android.R.id.text1};
mTagAdapter = new TagListAdapter(context, null);
mSuggestionAdapter = new SimpleCursorAdapter(context, android.R.layout.simple_list_item_1, null,
UIBindFrom, UIBindTo, 0);
//Handle Rotations
if(savedInstanceState == null){
//New
setupTagDialog();
} else {
//rotated
isNewTagView = savedInstanceState.getBoolean(KEY_NEWTAGVIEW, false);
if(isNewTagView){
restoreTagState(savedInstanceState);
} else {
restoreNewTagState(savedInstanceState);
}
}
LoaderManager lm = getLoaderManager();
if(lm != null){
lm.initLoader(TAGLOADERID, null, this);
}
this.setView(view);
super.onCreate(savedInstanceState);
}
public void onStart(){
restartLoader();
}
#Override
public Bundle onSaveInstanceState(){
Bundle bundle = super.onSaveInstanceState();
bundle.putBoolean(KEY_NEWTAGVIEW, isNewTagView);
return bundle;
}
#Override
public void onBackPressed(){
if(isNewTagView){
hideIMM();
setupTagDialog();
} else {
this.dismiss();
}
}
private void setupTagDialog() {
isNewTagView = false;
mTitle.setText(mTagTitle);
mNewTagButton.setVisibility(View.VISIBLE);
mSortTagButton.setVisibility(View.VISIBLE);
mEditText.setVisibility(View.GONE);
mListView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
mListView.setAdapter(mTagAdapter);
restartLoader();
}
private void setupNewTagDialog() {
isNewTagView = true;
mTitle.setText(mNewTagTitle);
mNewTagButton.setVisibility(View.INVISIBLE);
mSortTagButton.setVisibility(View.INVISIBLE);
mEditText.setVisibility(View.VISIBLE);
mListView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
mListView.setAdapter(mSuggestionAdapter);
restartLoader();
}
private void restoreTagState(Bundle bundle) {
setupTagDialog();
}
private void restoreNewTagState(Bundle bundle) {
setupNewTagDialog();
}
public void setAnnotation(Annotation a) {
mAnnotation = a;
}
public void setContentViewInterface(ContentFragment contentFragment) {
mContentFragment = contentFragment;
}
private MLDatabase getDatabase() {
if(mlDatabase == null){
GospelLibraryApplication app = (GospelLibraryApplication) getContext().getApplicationContext();
mlDatabase = app.getMlDatabase();
}
return mlDatabase;
}
public String getFilter() {
return mEditText.getText().toString().trim();
}
public Integer getAnnotationID(){
if(mAnnotation != null){
return mAnnotation.getDbKey();
}
return -1;
}
private LoaderManager getLoaderManager(){
if(mContentFragment == null){
Log.d(TAG, "ContentFragment is NULL!");
return null;
}
return mContentFragment.getContentActivity().getSupportLoaderManager();
}
private void restartLoader(){
LoaderManager lm = getLoaderManager();
if(lm != null){
lm.restartLoader(TAGLOADERID, null, this);
}
}
private void hideIMM(){
InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
TagCursorLoader loader = new TagCursorLoader(getContext(), this);
return loader;
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
if(isNewTagView) {
mSuggestionAdapter.changeCursor(data);
} else {
mTagAdapter.changeCursor(data);
}
mListView.invalidateViews();
mProgressBar.setVisibility(View.GONE);
mListView.setVisibility(View.VISIBLE);
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
if(mSuggestionAdapter != null) {
mSuggestionAdapter.changeCursor(null);
}
}
public static class TagCursorLoader extends CursorLoader {
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
private TagDialog dialog;
private MLDatabase mlDatabase;
private Cursor mCursor;
private String mFilter;
private Integer mAnnotationID;
// Runs on worker thread
#Override
public Cursor loadInBackground(){
Cursor cursor = null;
if(dialog.isNewTagView){
mFilter = dialog.getFilter();
cursor = mlDatabase.getTagSuggestions(mFilter);
} else {
mAnnotationID = dialog.getAnnotationID();
}
if(cursor != null){
cursor.registerContentObserver(mObserver);
}
return cursor;
}
//Runs on UI thread
#Override
public void deliverResult(Cursor cursor){
//Handle if canceled in the middle.
if(isReset()){
if(cursor != null){
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if(isStarted()) {
super.deliverResult(cursor);
}
if(oldCursor != null && !oldCursor.equals(cursor) && !oldCursor.isClosed()) {
oldCursor.close();
}
}
public TagCursorLoader(Context context, TagDialog dialog) {
super(context);
this.dialog = dialog;
mlDatabase = dialog.getDatabase();
}
#Override
public void onStartLoading(){
if(mCursor == null) {
forceLoad();
} else {
if(dialog.isNewTagView && mFilter.equals(dialog.getFilter())) {
deliverResult(mCursor);
} else {
forceLoad();
}
}
}
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
#Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
}
}
package org.lds.ldssa;
import android.R;
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.widget.CursorAdapter;
import android.widget.TextView;
import org.lds.ldssa.service.MLDatabase;
public class TagSuggestionAdapter extends CursorAdapter {
public TagSuggestionAdapter(Context context, Cursor cursor, int flags){
super(context, cursor, flags);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.simple_list_item_1, parent, false);
bindView(v, context, cursor);
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tv = (TextView) view.findViewById(R.id.text1);
tv.setText(cursor.getString(cursor.getColumnIndex(MLDatabase.CL_ID)));
}
}
Thanks in Advance for any help.
XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tag_layout"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="#dimen/min_dialog_width"
android:padding="5dp"
android:animateLayoutChanges="true"
>
<!-- Here is the view to show if the list is emtpy -->
<TextView
android:id="#android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="50dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_centerInParent="true"
android:gravity="center"
android:text="#string/no_items"
android:visibility="invisible"
/>
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
/>
<ProgressBar
android:id="#+id/tag_spin_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
/>
</RelativeLayout>

Try it without
android:animateLayoutChanges="true"
... in your XML layout.

Related

SearchView Filter, get correct position in listview

How to get the correct item when the filtered result display in the ListView and when the filtered result is selected it will display the correct output in another fragment, so far this is my current codes.
Current Problem Output:
My codes so far:
YourGroup.java
package com.findforme.www.myapplication;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Filter;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class YourGroup extends Fragment implements SearchView.OnQueryTextListener,SearchView.OnCloseListener{
private String TAG = YourGroup.class.getSimpleName();
private ListView gridView;
private SearchView mSearchView;
ListAdapterShowGroups adapter;
ArrayList<your_groups> your_groupList;
public static YourGroup newInstance() {
YourGroup fragment = new YourGroup();
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void findViews(View view) {
your_groupList = new ArrayList<>();
mSearchView = view.findViewById(R.id.floating_search_view);
mSearchView.setOnQueryTextListener(this);
mSearchView.setOnCloseListener(this);
gridView = view.findViewById(R.id.lv_showGroup);
gridView.setTextFilterEnabled(false);
new GetGroups().execute();
}
#Override
public boolean onClose() {
final FilterHelper filterHelper = new FilterHelper(your_groupList,adapter,getActivity());
adapter = new ListAdapterShowGroups(filterHelper.currentList,getActivity());
gridView.setAdapter(adapter);
return false;
}
#Override
public boolean onQueryTextSubmit(String s) {
adapter.getFilter().filter(s);
return false;
}
#Override
public boolean onQueryTextChange(String query) {
adapter.getFilter().filter(query);
return false;
}
public static class FilterHelper extends Filter{
ArrayList<your_groups> currentList;
ListAdapterShowGroups adapter;
Context c;
FilterHelper(ArrayList<your_groups> currentList, ListAdapterShowGroups adapter, Context c){
this.currentList = currentList;
this.adapter = adapter;
this.c = c;
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if(constraint != null && constraint.length()>0){
constraint = constraint.toString().toLowerCase();
ArrayList<your_groups> foundFilters = new ArrayList<>();
your_groups your_group = null;
for (int i=0;i<currentList.size();i++){
your_group = currentList.get(i);
if(your_group.GroupName.toLowerCase().contains(constraint)){
foundFilters.add(your_group);
}
}
filterResults.count=foundFilters.size();
filterResults.values=foundFilters;
} else {
filterResults.count =currentList.size();
filterResults.values=currentList;
}
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
if(filterResults.count == 0){
adapter.invalidate();
} else {
adapter.setYourGroups((ArrayList<your_groups>)filterResults.values);
adapter.refresh();
}
}
}
private class GetGroups extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//Toast.makeText(getActivity(), "Retrieving data", Toast.LENGTH_SHORT).show();
}
#Override
protected Void doInBackground(Void... voids) {
HttpHandler sh = new HttpHandler();
int id = MainActivity.user.getId();
String user_id = Integer.toString(id);
//String url = "https://findforme2018.000webhostapp.com/show_groups_joined.php?id="+user_id;
String url = "http://192.168.211.1/Capstone%202018/FindForMe/show_groups_joined.php?id="+user_id;
String jsonStr = sh.makeServiceCall(url);
Log.e(TAG, "Response from url: " + jsonStr);
if( jsonStr != null){
try{
JSONObject jsonObj = new JSONObject(jsonStr);
JSONArray groups = jsonObj.getJSONArray("group_join");
your_groups your_groups;
your_groupList = new ArrayList<>();
for (int i = 0; i < groups.length(); i++){
JSONObject c = groups.getJSONObject(i);
your_groups = new your_groups();
your_groups.setGroupName(c.getString("group_name"));
your_groups.setId(c.getInt("group_id"));
your_groupList.add(your_groups);
}
}catch (final JSONException e){
Log.e(TAG, "Error: " + e.getMessage());
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getActivity(),
"No groups join yet",
Toast.LENGTH_LONG).show();
}
});
}
}
else {
Log.e(TAG, "Couldn't get json from server.");
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getActivity(),
"Couldn't get json from server. Check LogCat for possible errors!",
Toast.LENGTH_LONG).show();
}
});
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter = new ListAdapterShowGroups(your_groupList,getActivity());
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
int id = your_groupList.get(i).id;
String group_id = Integer.toString(id);
String groupname = your_groupList.get(i).GroupName;
Bundle args = new Bundle();
args.putString("group_id", group_id);
args.putString("groupname", groupname);
SelectedGroup fragment = new SelectedGroup();
fragment.setArguments(args);
Toast.makeText(getActivity(),
groupname,
Toast.LENGTH_LONG).show();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_main
, fragment).addToBackStack(null).commit();
}
});
}
}
View myView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
myView = inflater.inflate(R.layout.fragment_your_group, container, false);
findViews(myView);
return myView;
}
}
This is the adapter that display the data in listview and its filter
package com.findforme.www.myapplication;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
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;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
public class ListAdapterShowGroups extends BaseAdapter implements Filterable{
Context context;
private ArrayList<your_groups> valueList;
private YourGroup.FilterHelper filterHelper;
ListAdapterShowGroups(ArrayList<your_groups> listValue, Context context)
{
this.context = context;
this.valueList = listValue;
}
#Override
public int getCount()
{
return this.valueList.size();
}
#Override
public Object getItem(int position)
{
return this.valueList.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
ListAdapterShowGroups.ViewItem viewItem;
if(convertView == null)
{
viewItem = new ListAdapterShowGroups.ViewItem();
LayoutInflater layoutInflater = (LayoutInflater)this.context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.customgroup_layout,null);
viewItem.image = convertView.findViewById(R.id.groupImage);
viewItem.groupname = convertView.findViewById(R.id.tv_groupName);
convertView.setTag(viewItem);
}
else
{
viewItem = (ListAdapterShowGroups.ViewItem)convertView.getTag();
}
viewItem.groupname.setText(valueList.get(position).getGroupName());
String img = valueList.get(position).getGroupName();
//Glide.with(this.context).load("https://findforme2018.000webhostapp.com/Group_Image/"+img+".jpg").asBitmap().into(viewItem.image);
Glide.with(this.context).load("http://192.168.211.1/Capstone%202018/FindForMe/Group_Image/"+img+".jpg").asBitmap().into(viewItem.image);
return convertView;
}
public void setYourGroups(ArrayList<your_groups> filteredYourGroups){
this.valueList = filteredYourGroups;
}
#Override
public Filter getFilter() {
if(filterHelper == null){
filterHelper = new YourGroup.FilterHelper(valueList,this,context);
}
return filterHelper;
}
public void refresh(){
notifyDataSetChanged();
}
public void invalidate(){
notifyDataSetInvalidated();
}
class ViewItem {
Integer id;
TextView groupname;
ImageView image;
}
}
your_groups.java
package com.findforme.www.myapplication;
public class your_groups {
public String GroupName;
public Integer id;
public int getId(){
return id;
}
public void setId(int id) {
this.id = id;
}
public String getGroupName(){
return GroupName;
}
public void setGroupName(String GroupName){
this.GroupName = GroupName;
}
}
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
text_view.setText(adapter.getItem(position - 1) + "");
}
});
Refer this code and change according your code..
public class IndexItemAdapter extends RecyclerView.Adapter<IndexItemAdapter.ItemViewHolder> implements Filterable {
private List<UserData> userVoList = new ArrayList<>();
private List<UserData> filterUserVoList = new ArrayList<>();
private Context context;
private String userId;
onItemClickListener onItemClickListener;
public void setOnItemClickListener(IndexItemAdapter.onItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public IndexItemAdapter(Context context, List<UserData> userVoList, String userId) {
this.userVoList = userVoList;
this.context = context;
this.userId = userId;
this.filterUserVoList = userVoList;
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
filterUserVoList = userVoList;
} else {
ArrayList<UserData> filteredList = new ArrayList<>();
for (UserData userData : userVoList) {
if (userData.getSubject().toLowerCase().contains(charString) || userData.getName().toLowerCase().contains(charString) || userData.getMessages().toLowerCase().contains(charString)) {
filteredList.add(userData);
}
}
filterUserVoList = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = filterUserVoList;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
filterUserVoList = (ArrayList<UserData>) filterResults.values;
notifyDataSetChanged();
}
};
}
public interface onItemClickListener {
void onItemClick(UserData userData);
}
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.index_row_layout, parent, false);
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ItemViewHolder holder, int position) {
final UserData userData = filterUserVoList.get(position);
holder.tvName.setText(CommonUtils.checkForNullValue(userData.getSubject()));
holder.tvContent.setText(CommonUtils.checkForNullValue(userData.getMessages()));
if (userData.getUserVo() != null) {
holder.tvEmail.setText(userData.getUserVo().getEmail());
Glide.with(context).load(CommonUtils.checkForNullValue(userData.getUserVo().getPhoto())).apply(RequestOptions.circleCropTransform())
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL))
.apply(RequestOptions.placeholderOf(R.drawable.big_user))
.into(holder.ivUserImage);
if (userId.equals(userData.getReceiverId())) {
holder.ivRecivedIcon.setImageResource(R.drawable.forward);
} else {
holder.ivRecivedIcon.setImageResource(R.drawable.reply);
}
}
}
private void changeTextColor(TextView textView, int color) {
textView.setTextColor(color);
}
#Override
public int getItemCount() {
return filterUserVoList.size();
}
public class ItemViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.irlIvUserImage)
ImageView ivUserImage;
#BindView(R.id.irlTvName)
TextView tvName;
#BindView(R.id.irlTvEmail)
TextView tvEmail;
#BindView(R.id.irlTvDes)
TextView tvContent;
#BindView(R.id.irlTvTime)
TextView tvTime;
#BindView(R.id.irlIvGetImage)
ImageView ivRecivedIcon;
public ItemViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
and search view in.. make sure your adapter not null
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
indexItemAdapter.getFilter().filter(newText.toLowerCase());
indexItemAdapter.notifyDataSetChanged();
return true;
}
});

android xml: Error inflating class fragment

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?

Trying to programmatically set the state of a SWITCH inside a LISTVIEW after the listview is displayed

So i have a list of alarms and i bind that to the listview, lstAlarms. In my custom ListView layout, i also have a switch, which i want to be set programmatically according to the status of the alarm. I want to do this right after the ListView is just displayed.
Please see my codes below.
The method that display the ListView is DisplayAlarmList().
The method that im trying to use to set the states of the switches is InitSwitches(), which is being called inside of DisplayAlarmList().
DisplayAlarmList() is called in the onCreate() method.
public void DisplayAlarmList()
{
final String[] columns = {Database.getAlarmID(), Database.getAlarmTime(), Database.getAlarmName(), Database.getAlarmStatus(), Database.getAlarmRepeats()};
Cursor c = Database.selectAlarm(db, Database.getTableName(), columns, null, null, null, null, null);
int[] to = new int[]{
R.id.alarmID,
R.id.alarmTime,
R.id.alarmName,
R.id.alarmStatus,
R.id.alarmRepeats,
};
SimpleCursorAdapter ca = new SimpleCursorAdapter(this,
R.layout.alarm_info,
c,
columns,
to,
0);
lstAlarm.setAdapter(ca);
InitSwitches();
lstAlarm.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> listView, View view, int position, long id)
{
Alarm alarm = new Alarm();
Cursor selectedCursor = (Cursor) listView.getItemAtPosition(position);
Switch s = (Switch) view.findViewById(R.id.alarmSwitch);
String whereArgs = Integer.toString(selectedCursor.getInt(selectedCursor.getColumnIndexOrThrow(Database.getAlarmID())));
Cursor data = Database.RawQuery(db, "SELECT * FROM " + Database.getTableName() + " WHERE " + Database.getAlarmID() + " = " + whereArgs);
if (data.moveToFirst())
{
alarm.setAlarmID(data.getString(data.getColumnIndexOrThrow(Database.getAlarmID())));
alarm.setAlarmName(data.getString(data.getColumnIndexOrThrow(Database.getAlarmName())));
alarm.setAlarmTime(data.getString(data.getColumnIndexOrThrow(Database.getAlarmTime())));
alarm.setAlarmSound(data.getString(data.getColumnIndexOrThrow(Database.getAlarmSound())));
alarm.setAlarmRepeats(data.getString(data.getColumnIndexOrThrow(Database.getAlarmRepeats())));
alarm.setAlarmStatus(data.getString(data.getColumnIndexOrThrow(Database.getAlarmStatus())));
}
Intent i = new Intent(view.getContext(), ScreenEdit.class);
i.putExtra("editAlarm", new Gson().toJson(alarm));
startActivityForResult(i, EDIT_ALARM);
}
});
}
public void InitSwitches()
{
View v;
Switch s;
int index = 0;
String query = "Select " + Database.getAlarmID() + ", " + Database.getAlarmStatus() + " FROM " + Database.getTableName();
Cursor statuses = Database.RawQuery(db, query);
while (statuses.moveToNext())
{
v = lstAlarm.getAdapter().getView(index++, null, null);
s = (Switch) v.findViewById(R.id.alarmSwitch);
if (statuses.getString(statuses.getColumnIndexOrThrow(Database.getAlarmStatus())).equals("ON")){
s.toggle();
}
else{
}
}
}
ScreenShot of app
As you can see from the screen shot, the switch in the second row is supposed to be ON, but it's not. I tried InvilidateView() too but didnt work. Please help.
The problem is that ListView is one of those views that is being constantly redrawn, meaning that this is bad, becuase it will lose the state when redrawn
if (statuses.getString(statuses.getColumnIndexOrThrow(Database.getAlarmStatus())).equals("ON")){
s.toggle();
}
First create AlarmItem... you should make it according to your needs. Here is mine
public class AlarmItem {
private String alarmName;
private String alarmDescption;
private boolean state;
private long id;
public AlarmItem(String alarmName, String alarmDescption, long id, boolean state) {
this.alarmName = alarmName;
this.alarmDescption = alarmDescption;
this.id = id;
this.state = state;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAlarmName() {
return alarmName;
}
public void setAlarmName(String alarmName) {
this.alarmName = alarmName;
}
public String getAlarmDescption() {
return alarmDescption;
}
public void setAlarmDescption(String alarmDescption) {
this.alarmDescption = alarmDescption;
}
public boolean getState() {
return state;
}
public void setState(boolean state) {
this.state = state;
}
}
Now we will need a CustomSwitch class because of this: LINK
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Switch;
public class CustomSwitch extends Switch {
private OnCheckedChangeListener mListener;
public CustomSwitch(Context context) {
super(context);
}
public CustomSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomSwitch(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
// Do not call supper method
mListener = listener;
}
#Override
public void setChecked(boolean checked) {
super.setChecked(checked);
if (mListener != null) {
mListener.onCheckedChanged(this, checked);
}
}
public void setCheckedProgrammatically(boolean checked) {
// You can call super method, it doesn't have a listener... he he :)
super.setChecked(checked);
}
}
create a layout file and name it alarm_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical">
<com.example.alarm.list.CustomSwitch
android:id="#+id/alarmSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_toLeftOf="#id/alarmSwitch"
android:orientation="vertical">
<TextView
android:id="#+id/tvAlarmName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="Alarm Name"
android:textSize="18sp"/>
<TextView
android:id="#+id/tvAlarmDesc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="Alarm description"
android:textSize="15sp"/>
</LinearLayout>
</RelativeLayout>
Now the main layout -> activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/lvAlarms"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Now we need an adapter that is responsible for drawing the items and their handling. Name the class AlarmAdapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CompoundButton;
import android.widget.TextView;
import java.util.List;
public class AlarmAdapter extends BaseAdapter {
private List<AlarmItem> listOfAlarms;
private Context context;
private OnAlarmCheckedChangeListener mCallback;
// avoid constant allocation
private View tmpView;
private AlarmItemViewHolder mHolder;
private AlarmItem tmpItem;
public AlarmAdapter(List<AlarmItem> listOfAlarms, Context context, OnAlarmCheckedChangeListener callBack) {
this.listOfAlarms = listOfAlarms;
this.context = context;
mCallback = callBack;
}
#Override
public int getCount() {
return listOfAlarms == null ? 0 : listOfAlarms.size();
}
#Override
public AlarmItem getItem(int i) {
return listOfAlarms == null ? null : listOfAlarms.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(final int i, View view, ViewGroup viewGroup) {
tmpItem = listOfAlarms.get(i);
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(context);
tmpView = inflater.inflate(R.layout.alarm_list_item, null, false);
mHolder = new AlarmItemViewHolder(tmpView);
tmpView.setTag(mHolder);
}
else {
tmpView = view;
mHolder = (AlarmItemViewHolder) view.getTag();
}
mHolder.getAlarmNameTextView().setText(tmpItem.getAlarmName());
mHolder.getAlarmDescriptionTextView().setText(tmpItem.getAlarmDescption());
mHolder.getSwitch().setCheckedProgrammatically(tmpItem.getState());
mHolder.getSwitch().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
listOfAlarms.get(i).setState(b);
mCallback.onAlarmStateChanged(listOfAlarms.get(i), i);
}
});
return tmpView;
}
public void clear() {
listOfAlarms.clear();
notifyDataSetChanged();
}
public void refill(List<AlarmItem> listOfAlarms) {
this.listOfAlarms = listOfAlarms;
notifyDataSetChanged();
}
public void toggleAllSwitches() {
for (AlarmItem item : listOfAlarms) {
item.setState(!item.getState());
}
notifyDataSetChanged();
}
public interface OnAlarmCheckedChangeListener {
public void onAlarmStateChanged(AlarmItem item, int postionInList);
}
private class AlarmItemViewHolder {
View base;
CustomSwitch mSwitch;
TextView mAlarmName;
TextView mAlarmDescription;
public AlarmItemViewHolder(View base) {
this.base = base;
}
public CustomSwitch getSwitch() {
if (mSwitch == null) {
mSwitch = (CustomSwitch) base.findViewById(R.id.alarmSwitch);
}
return mSwitch;
}
public TextView getAlarmNameTextView() {
if (mAlarmName == null) {
mAlarmName = (TextView) base.findViewById(R.id.tvAlarmName);
}
return mAlarmName;
}
public TextView getAlarmDescriptionTextView() {
if (mAlarmDescription == null) {
mAlarmDescription = (TextView) base.findViewById(R.id.tvAlarmDesc);
}
return mAlarmDescription;
}
}
}
And now finally the MainActivity
import android.app.ActionBar;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener, AlarmAdapter.OnAlarmCheckedChangeListener {
private ListView listView;
private AlarmAdapter adapter;
private Toast toast;
private Handler handler;
private Runnable handlerRunnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Make a nice actionBar title
ActionBar ab = getActionBar();
if (ab != null) {
ab.setTitle("Alarm List");
}
listView = (ListView) findViewById(R.id.lvAlarms);
// Simulating alarms from database. You need to convert your items to these
List<AlarmItem> alarmsFromDb = new ArrayList<>();
alarmsFromDb.add(new AlarmItem("Alarm 1", "Lalalala", 1, true));
alarmsFromDb.add(new AlarmItem("Alarm 2", "something", 2, false));
alarmsFromDb.add(new AlarmItem("Alarm 3", "gfdgdf", 3, true));
alarmsFromDb.add(new AlarmItem("Alarm 4", "sda", 4, true));
alarmsFromDb.add(new AlarmItem("Alarm 5", "yxcxyc", 5, false));
alarmsFromDb.add(new AlarmItem("Alarm 6", "dsfsd", 6, false));
adapter = new AlarmAdapter(alarmsFromDb, this, this);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
// Toggle all switches after 5s... this is what you need, right?
handlerRunnable = new Runnable() {
#Override
public void run() {
adapter.toggleAllSwitches();
showToast("All switches toggeled :)");
}
};
handler = new Handler(Looper.getMainLooper());
handler.postDelayed(handlerRunnable, 5 * 1000);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (handler != null) {
handler.removeCallbacks(handlerRunnable);
handler = null;
handlerRunnable = null;
}
}
private void showToast(String str) {
if (toast != null) {
toast.cancel();
}
toast = Toast.makeText(this, str, Toast.LENGTH_SHORT);
toast.show();
}
#Override
public void onAlarmStateChanged(AlarmItem item, int postionInList) {
String onOff = item.getState() ? "ON" : "OFF";
showToast("Alarm " + item.getAlarmName() + " is: " + onOff);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
AlarmItem item = adapter.getItem(position);
showToast("Alarm " + item.getAlarmName() + " clicked");
}
}
Here is the complete android studio project, if you have any problems: LINK
Now all you need to do is convert the results from your database to this list or modify the AlarmItem and the UI. This solution will work and you already have some helpful methods in the adapter.
Happy coding!
does your adapter use the viewholder pattern? If not, the Views that go off screen are reused and may have old switch status that the new row coming in when scrolling should not have.

I am getting the items in Listview repeated . Here is my sample code I am unable to find the bug in my code ! Can anyone help me out please?

//this is JOBListAdapter class
package com.example.hellotest.adapters;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
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 com.example.hellotest.R;
import com.example.hellotest.model.Job;
public class JobListAdapter extends BaseAdapter {
private LayoutInflater mInflater ;
private List<Job> mJobs;
private SimpleDateFormat mDateFormat;
private SimpleDateFormat mInputFormat;
private String mPosterPrefix;
public JobListAdapter(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mDateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
mInputFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.US);
mPosterPrefix = context.getString(R.string.job_posted_by);
}
public void setJobList(List<Job> jobs) {
mJobs = jobs;
}
#Override
public int getCount() {
if(null != mJobs) {
return mJobs.size();
}
return 0;
}
#Override
public Object getItem(int position) {
return mJobs.get(position);
}
#Override
public long getItemId(int position) {
return mJobs.get(position).getId();
}
//this is the method where I think that the problem is please somebody tell me.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(null == convertView) {
convertView = mInflater.inflate(R.layout.job_list_row, null);
holder = new ViewHolder();
holder.created = (TextView) convertView.findViewById(R.id.job_listing_date);
holder.location = (TextView) convertView.findViewById(R.id.job_listing_location);
holder.title = (TextView) convertView.findViewById(R.id.job_listing_title);
holder.experience = (TextView) convertView.findViewById(R.id.job_listing_experience);
holder.poster = (TextView) convertView.findViewById(R.id.job_listing_posted_by);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
updateRow(holder, mJobs.get(position));
return convertView;
}
private void updateRow(ViewHolder holder, Job job) {
holder.title.setText(job.getTitle());
int id = job.isPremium() ? R.drawable.icon_premium : 0;
holder.created.setText(getDate(job.getCreated()));
holder.created.setCompoundDrawablesWithIntrinsicBounds(0, 0, id, 0);
holder.experience.setText(job.getExperience());
holder.location.setText(job.getLocation());
holder.poster.setText(mPosterPrefix + job.getPoster());
}
private CharSequence getDate(String created) {
try {
return mDateFormat.format(mInputFormat.parse(created));
} catch (ParseException e) {
e.printStackTrace();
}
return created;
}
private static class ViewHolder {
TextView created;
TextView title;
TextView location;
TextView experience;
TextView poster;
}
}
// layout for fragmentjob_listing even I make the listview height to fill_parent as suggested when I googled the solution for the issue.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/job_listing_filter_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/job_listing_tab_bg"
android:gravity="center_vertical"
android:minHeight="48dp" >
<TextView
android:id="#+id/job_listing_experience"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/selector_job_listing_tab"
android:clickable="true"
android:gravity="center"
android:text="#string/job_listing_experience" />
<ImageView
android:id="#+id/space2"
android:layout_width="1dp"
android:layout_height="match_parent"
android:contentDescription="#string/app_name"
android:scaleType="fitXY"
android:src="#drawable/job_listing_horizontal_divider" />
<TextView
android:id="#+id/job_listing_location"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/selector_job_listing_tab"
android:clickable="true"
android:gravity="center"
android:text="#string/job_listing_location" />
</LinearLayout>
<ImageView
android:id="#+id/imageView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/app_name"
android:scaleType="fitXY"
android:src="#drawable/job_listing_divider" />
<TextView
android:id="#+id/job_listing_message"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:visibility="gone"/>
<ListView
android:id="#+id/job_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ListView>
</LinearLayout>
// JobListingFragment Class where the joblistAdapter class called up
package com.example.hellotest;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.Request.Method;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.Volley;
import com.example.hellotest.R;
import com.example.hellotest.adapters.JobListAdapter;
import com.example.hellotest.config.Constant;
import com.example.hellotest.io.CookieStringRequest;
import com.example.hellotest.io.json.JobsProcessor;
import com.example.hellotest.model.Job;
import com.example.hellotest.model.JobList;
import com.example.hellotest.model.Pagination;
import com.example.hellotest.tasks.JsonParserTask;
import com.example.hellotest.tasks.JsonParsingListener;
import com.example.hellotest.util.AccountUtils;
import com.example.hellotest.util.Log;
public class JobListingFragment extends Fragment {
public static final String ARG_URL = "argument_url";
public static final String ARG_IS_FILTER_ON = "argument_is_filtered";
public static final String ARG_IS_DEFAULT_JOB_LIST = "argument_is_default_job_list";
public static final String ARG_EMPTY_MESSAGE = "argument_empty_message";
protected static final int REQUEST_EXPERIENCE = 0x11;
protected static final int REQUEST_LOCATION = 0x12;
private ListView mJobsList;
private TextView mMessageView;
private JobListAdapter mAdapter;
private List<Job> mJobs;
private Pagination mPagination;
private boolean mIsFetching;
private boolean mIsDefaultList;
private boolean mIsFilterOn;
private String mUrl;
private String mLocId;
private int mExperienceId = -1;
private ProgressBar mFooterProgress;
private Log mLogger = new Log(JobListingFragment.class);
private Object mRequestTag = new Object();
private RequestQueue mRequestQueue;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new JobListAdapter(getActivity());
if (null != savedInstanceState) {
getState(savedInstanceState);
} else {
getState(getArguments());
}
// init();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mRequestQueue = Volley.newRequestQueue(getActivity());
}
#Override
public void onDetach() {
mRequestQueue.cancelAll(mRequestTag);
super.onDetach();
}
#Override
public void onResume() {
init();
super.onResume();
}
private void getState(Bundle bundle) {
mUrl = bundle.getString(ARG_URL);
mIsFilterOn = bundle.getBoolean(ARG_IS_FILTER_ON);
mIsDefaultList = bundle.getBoolean(ARG_IS_DEFAULT_JOB_LIST);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_job_listing, null);
mJobsList = (ListView) view.findViewById(R.id.job_list);
mMessageView = (TextView) view.findViewById(R.id.job_listing_message);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
View footer = getLayoutInflater(savedInstanceState).inflate(R.layout.paginated_list_footer, null);
mFooterProgress = (ProgressBar) footer.findViewById(R.id.footer_progress);
if (!mIsFilterOn) {
view.findViewById(R.id.job_listing_filter_container).setVisibility(View.GONE);
} else {
view.findViewById(R.id.job_listing_experience).setOnClickListener(mOnClickListener);
view.findViewById(R.id.job_listing_location).setOnClickListener(mOnClickListener);
}
mJobsList.addFooterView(footer);
mJobsList.setAdapter(mAdapter);
mJobsList.setOnScrollListener(mOnScrollListener);
mJobsList.setOnItemClickListener(mOnItemClickListener);
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(ARG_URL, mUrl);
outState.putBoolean(ARG_IS_FILTER_ON, mIsFilterOn);
outState.putBoolean(ARG_IS_DEFAULT_JOB_LIST, mIsDefaultList);
super.onSaveInstanceState(outState);
}
public void startAfresh(String url, boolean isPaginated) {
mLogger.d("old fragment reused");
mIsFilterOn = true;
mUrl = url;
reset();
init();
}
private void init() {
mLocId = AccountUtils.getLocationFilter();
mExperienceId = AccountUtils.getExperienceFilter();
String url = getUrl(1);
fetchJobs(url);
}
private void reset() {
mJobs = null;
mPagination = null;
mAdapter.setJobList(null);
mAdapter.notifyDataSetChanged();
}
private String getUrl(int pageNumber) {
String appender = "";
if (mIsFilterOn) {
if (null != mLocId || -1 < mExperienceId) {
if (null != mLocId) {
appender += "/loc-" + mLocId;
} else {
appender += "/loc-" + 0;
}
if (-1 < mExperienceId) {
appender += "/exp-" + mExperienceId;
} else {
appender += "/exp-" + 0;
}
}
}
String url = mUrl + appender + "/pg-" + pageNumber;
if (mIsDefaultList && AccountUtils.isLoggedIn()) {
url += "?" + Constant.MAP_COOKIE_KEY + "=" + AccountUtils.getCookie();
}
return url;
}
private void fetchJobs(String url) {
mIsFetching = true;
mLogger.d("url :" + url);
int method = mIsDefaultList ? Method.GET : Method.POST;
CookieStringRequest request = new CookieStringRequest(method, url, mListener, mErrorListener);
request.setTag(mRequestTag);
mRequestQueue.add(request);
}
private Response.Listener<String> mListener = new Listener<String>() {
#Override
public void onResponse(String response) {
mLogger.d("response :" + response);
JsonParserTask<JobList> jsonTask = new JsonParserTask<JobList>(new JobsProcessor());
jsonTask.setListener(mJsonListener);
jsonTask.execute(response);
}
};
private Response.ErrorListener mErrorListener = new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
mIsFetching = false;
Toast.makeText(getActivity(), R.string.network_error, Toast.LENGTH_LONG).show();
}
};
private JsonParsingListener<JobList> mJsonListener = new JsonParsingListener<JobList>() {
#Override
public void onSuccess(JobList result) {
if (null == mPagination) {
mPagination = result.getPagination();
mPagination.setCurrentPage(0);
if(null == result.getJobs() || 0 == result.getJobs().size()) {
mMessageView.setText(getArguments().getString(ARG_EMPTY_MESSAGE));
mMessageView.setVisibility(View.VISIBLE);
} else {
mMessageView.setVisibility(View.GONE);
}
} else {
mPagination.updateData(result.getPagination());
}
if (null != mJobs) {
mJobs.addAll(result.getJobs());
} else {
mJobs = result.getJobs();
}
mAdapter.setJobList(mJobs);
mAdapter.notifyDataSetChanged();
mIsFetching = false;
}
#Override
public void onFailure(Exception e) {
Toast.makeText(getActivity(), "Unable to process response", Toast.LENGTH_LONG).show();
mIsFetching = false;
}
};
private OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Job job = (Job) mAdapter.getItem(position);
Intent intent = new Intent(getActivity(), JobDetailsActivity.class);
intent.putExtra(JobDetailsActivity.EXTRA_JOB, job);
startActivity(intent);
}
};
// this is the function where I also found that might cause some problem because when I scrolls down the items in the list repeated.
private OnScrollListener mOnScrollListener = new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount;
if (loadMore && totalItemCount > 0 && null != mPagination) {
boolean isLastPage = mPagination.getCurrentPage() >= mPagination.getTotalPages();
if (isLastPage) {
mFooterProgress.setVisibility(View.GONE);
}
if (!mIsFetching && !isLastPage) {
fetchJobs(getUrl(mPagination.getCurrentPage()+1));
}
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (Activity.RESULT_OK == resultCode) {
switch (requestCode) {
case REQUEST_EXPERIENCE:
onExperienceSelection(data);
break;
case REQUEST_LOCATION:
onLocationSelection(data);
break;
}
}
}
add one more line in your function:
mjob.clear();
private JsonParsingListener<JobList> mJsonListener = new JsonParsingListener<JobList>() {
#Override
public void onSuccess(JobList result) {
if (null == mPagination) {
mPagination = result.getPagination();
mPagination.setCurrentPage(0);
if(null == result.getJobs() || 0 == result.getJobs().size()) {
mMessageView.setText(getArguments().getString(ARG_EMPTY_MESSAGE));
mMessageView.setVisibility(View.VISIBLE);
} else {
mMessageView.setVisibility(View.GONE);
}
} else {
mPagination.updateData(result.getPagination());
}
if (null != mJobs) {
mJobs.clear();
mJobs.addAll(result.getJobs());
} else {
mJobs = result.getJobs();
}
mAdapter.setJobList(mJobs);
mAdapter.notifyDataSetChanged();
mIsFetching = false;
}

Android 4.0.3 CursorAdapter doesn't populate ListView on changeCursor

EDIT: I didn't post my XML for this dialog.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tag_layout"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="#dimen/min_dialog_width"
android:padding="5dp"
android:animateLayoutChanges="true"
>
<!-- Here is the view to show if the list is emtpy -->
<TextView
android:id="#android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="50dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_centerInParent="true"
android:gravity="center"
android:text="#string/no_items"
android:visibility="invisible"
/>
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
/>
<ProgressBar
android:id="#+id/tag_spin_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"
/>
</RelativeLayout>
I am using the android.support.v4.CursorLoader and CursorAdapter and I am trying to get it to update its cursor. In Android 2.3.3 it works just fine. However when I try it on my 4.0.3 device the ListView doesn't refresh and the newView method in my adapter is never called. I know the cursor has data in it since I can see it on my 2.3.3 device.
If I rotate my device the ListView shows what I want. I have tried invalidating the ListView but that doesn't solve the issue.
If I don't reset the ListView's adapter the list doesn't go blank, but it still doesn't refresh the list.
I am doing all of this inside of an extended AlertDialog that is embedded in a DialogFragment.
Here is the entire class
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
import org.lds.ldssa.service.MLDatabase;
import org.lds.ldssa.service.aws.Annotation;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class TagDialog extends AlertDialog implements LoaderManager.LoaderCallbacks<Cursor>,AdapterView.OnItemClickListener {
private static final String TAG = "ldssa.tagdialog";
public static final int TAGLOADERID = 0;
// View Items
private EditText mEditText;
private ListView mListView;
private TextView mEmptyView;
private ProgressBar mProgressBar;
private ImageButton mNewTagButton;
private ImageButton mSortTagButton;
private TextView mTitle;
private String mTagTitle;
private String mNewTagTitle;
private Annotation mAnnotation;
private ContentFragment mContentFragment;
private boolean isNewTagView;
private static final String KEY_NEWTAGVIEW = "new_tag_view";
private static final String POSITION_KEY = "TAG_POSITION";
private static final String Y_KEY = "TAG_Y";
private static final String SORT_KEY = "TAG_SORT";
private static final String CHECKED_STATE_KEY = "TAG_CHECKED_STATE";
private static final int NOT_SET = -1;
private int mPosition;
private int mY;
private TagSuggestionAdapter mSuggestionAdapter;
private TagListAdapter mTagAdapter;
private MLDatabase mlDatabase;
private boolean mSortAlpha;
private HashMap<Long, CheckedState> mCheckedState;
protected TagDialog(Context context) {
super(context);
}
public void onCreate(Bundle savedInstanceState){
Context context = getContext();
Resources r = context.getResources();
final LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.dialog_tag, null);
// Main parts of the view
mEditText = (EditText) view.findViewById(R.id.tag_new_tag);
mListView = (ListView) view.findViewById(android.R.id.list);
mProgressBar = (ProgressBar) view.findViewById(R.id.tag_spin_progress_bar);
mEmptyView = (TextView) view.findViewById(android.R.id.empty);
mEmptyView.setVisibility(View.INVISIBLE);
// Titlebar
View titleBar = inflater.inflate(R.layout.dialog_tag_title, null);
mNewTagButton = (ImageButton) titleBar.findViewById(R.id.tag_new_icon);
mSortTagButton = (ImageButton) titleBar.findViewById(R.id.tag_sort_icon);
mTitle = (TextView) titleBar.findViewById(R.id.tag_title);
mTagTitle = r.getString(R.string.tag_dialog_title);
mNewTagTitle = r.getString(R.string.tag_new_dialog_title);
this.setCustomTitle(titleBar);
// Buttons
final String OK = r.getString(R.string.ok);
final String CANCEL = r.getString(R.string.cancel);
this.setButton(BUTTON_POSITIVE, OK, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) { /*Never Used*/}});
this.setButton(BUTTON_NEGATIVE, CANCEL, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) { /*Never Used*/}});
// Setup Button Listeners
setOnShowListener(new OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
Button ok = getButton(BUTTON_POSITIVE);
ok.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isNewTagView){
hideIMM();
addNewTag();
mEditText.setText("");
setupTagDialog();
} else {
Collection<CheckedState> changes = mCheckedState.values();
boolean success = true;
MLDatabase db = getDatabase();
db.beginAnnotationTransaction();
for(CheckedState change : changes){
if(!change.checked()){
//Detag
db.detagAnnotation(mAnnotation.getDbKey(), change.tagID());
} else {
mAnnotation.saveHighlightsToDatabase(db);
if(mAnnotation.getDbKey().intValue() != MLDatabase.NOT_SET_INT &
change.tagID() != MLDatabase.NOT_SET_INT){
success = db.tagAnnotation(mAnnotation.getDbKey(), change.tagID(), change.changed());
}
}
}
if(success){
db.setAnnotationTransactionSuccessful();
}
db.endAnnotationTransaction();
mCheckedState.clear();
dismiss();
}
}
});
Button cancel = getButton(BUTTON_NEGATIVE);
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isNewTagView){
hideIMM();
setupTagDialog();
mEditText.setText("");
} else {
mCheckedState.clear();
dismiss();
}
}
});
}
});
mNewTagButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setupNewTagDialog();
}
});
mSortTagButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mSortAlpha = !mSortAlpha;
restartLoader();
}
});
mListView.setOnItemClickListener(TagDialog.this);
mEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void afterTextChanged(Editable s) {
LoaderManager lm = getLoaderManager();
if(lm != null){
Loader l = lm.getLoader(TAGLOADERID);
if(l != null){
l.forceLoad();
} else {
restartLoader();
}
} else {
restartLoader();
}
}
});
//Handle Rotations
if(savedInstanceState == null){
//New
mPosition = NOT_SET;
mY = NOT_SET;
mSortAlpha = false;
mCheckedState = getCheckedState(mAnnotation.getDbKey());
isNewTagView = false;
} else {
//rotated
isNewTagView = savedInstanceState.getBoolean(KEY_NEWTAGVIEW, false);
mPosition = savedInstanceState.getInt(POSITION_KEY, NOT_SET);
mY = savedInstanceState.getInt(Y_KEY, NOT_SET);
mSortAlpha = savedInstanceState.getBoolean(SORT_KEY, false);
restoreCheckedState(savedInstanceState);
}
mTagAdapter = new TagListAdapter(context, null, mCheckedState);
mSuggestionAdapter = new TagSuggestionAdapter(context, null, 0);
LoaderManager lm = getLoaderManager();
if(lm != null){
lm.initLoader(TAGLOADERID, null, this);
}
this.setView(view);
super.onCreate(savedInstanceState);
}
private void addNewTag() {
String tag = mEditText.getText().toString().trim();
if(!tag.equals("")){
getDatabase();
Integer langID = mAnnotation.getLanguageId();
try{
long tagID = mlDatabase.insertTag(langID, tag);
if(mAnnotation.getDbKey().intValue() != MLDatabase.NOT_SET_INT &&
tagID != MLDatabase.NOT_SET_INT){
mCheckedState.put(tagID, new CheckedState(tagID, true, true));
}
} catch (Exception e) {
Log.d(TAG, "Problem saving new tag: " + tag + " : " + e.getMessage());
e.printStackTrace();
}
}
}
public void onStart(){
if(isNewTagView){
setupNewTagDialog();
} else {
setupTagDialog();
}
restartLoader();
}
#Override
public Bundle onSaveInstanceState(){
Bundle bundle = super.onSaveInstanceState();
//Save What dialog we are in.
bundle.putBoolean(KEY_NEWTAGVIEW, isNewTagView);
bundle.putBoolean(SORT_KEY, mSortAlpha);
//Save position
bundle.putInt(POSITION_KEY, mListView.getFirstVisiblePosition());
final View v = mListView.getChildAt(0);
bundle.putInt(Y_KEY, (v == null) ? 0 : v.getTop());
//Save Checked State
Iterator it = mCheckedState.entrySet().iterator();
int i = 0;
while(it.hasNext()){
Map.Entry pair = (Map.Entry)it.next();
bundle.putSerializable(CHECKED_STATE_KEY + i, (CheckedState)pair.getValue());
i++;
}
bundle.putInt(CHECKED_STATE_KEY, i);
return bundle;
}
private void restoreCheckedState(Bundle bundle){
int count = bundle.getInt(CHECKED_STATE_KEY);
mCheckedState = new HashMap<Long, CheckedState>();
boolean success = true;
for(int i = 0; i < count; i++){
CheckedState cs = (CheckedState)bundle.getSerializable(CHECKED_STATE_KEY+i);
if(cs == null){
success = false;
break;
}
mCheckedState.put(cs.tagID(), cs);
}
if(!success){
mCheckedState = getCheckedState(mAnnotation.getDbKey());
}
}
#Override
public void onBackPressed(){
if(isNewTagView){
hideIMM();
setupTagDialog();
} else {
this.dismiss();
}
}
private void setupTagDialog() {
isNewTagView = false;
mTitle.setText(mTagTitle);
mNewTagButton.setVisibility(View.VISIBLE);
mSortTagButton.setVisibility(View.VISIBLE);
mEmptyView.setVisibility(View.INVISIBLE);
mEditText.setVisibility(View.GONE);
mListView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
mListView.setAdapter(mTagAdapter);
restartLoader();
}
private void setupNewTagDialog() {
isNewTagView = true;
mTitle.setText(mNewTagTitle);
mNewTagButton.setVisibility(View.INVISIBLE);
mSortTagButton.setVisibility(View.INVISIBLE);
mEmptyView.setVisibility(View.INVISIBLE);
mEditText.setVisibility(View.VISIBLE);
mListView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
mListView.setAdapter(mSuggestionAdapter);
restartLoader();
}
public void setAnnotation(Annotation a) {
mAnnotation = a;
}
public void setContentViewInterface(ContentFragment contentFragment) {
mContentFragment = contentFragment;
}
private MLDatabase getDatabase() {
if(mlDatabase == null){
GospelLibraryApplication app = (GospelLibraryApplication) getContext().getApplicationContext();
mlDatabase = app.getMlDatabase();
}
return mlDatabase;
}
public String getFilter() {
return mEditText.getText().toString().trim();
}
public Integer getAnnotationID(){
if(mAnnotation != null){
return mAnnotation.getDbKey();
}
return MLDatabase.NOT_SET_INT;
}
private LoaderManager getLoaderManager(){
if(mContentFragment == null){
Log.d(TAG, "ContentFragment is NULL!");
return null;
}
return mContentFragment.getContentActivity().getSupportLoaderManager();
}
private void restartLoader(){
LoaderManager lm = getLoaderManager();
if(lm != null){
lm.restartLoader(TAGLOADERID, null, this);
}
}
private void hideIMM(){
InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
private HashMap<Long, CheckedState> getCheckedState(Integer annotationID) {
HashMap<Long, CheckedState> checkedState = new HashMap<Long, CheckedState>();
MLDatabase db = getDatabase();
Cursor cursor = db.queryAllTagsWithAnnotation(annotationID);
if(cursor != null){
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()){
Long tagID = cursor.getLong(cursor.getColumnIndex(MLDatabase.CL_ID));
boolean isChecked = !cursor.isNull(cursor.getColumnIndex(MLDatabase.CL_ANNOTATION));
checkedState.put(tagID, new CheckedState(tagID, isChecked, false));
}
}
return checkedState;
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
TagCursorLoader loader = new TagCursorLoader(getContext(), this);
return loader;
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
if(isNewTagView) {
mSuggestionAdapter.changeCursor(data);
if(mListView.getAdapter() == null){
mListView.setAdapter(mSuggestionAdapter);
}
} else {
mTagAdapter.changeCursor(data);
if(mListView.getAdapter() == null){
mListView.setAdapter(mTagAdapter);
}
}
if(mPosition != NOT_SET && mY != NOT_SET){
mListView.setSelectionFromTop(mPosition, mY);
mPosition = mY = NOT_SET;
}
if (mListView.getAdapter() != null) {
if (mListView.getAdapter().getCount() > 0) {
mEmptyView.setVisibility(View.INVISIBLE);
}
else {
mEmptyView.setVisibility(View.VISIBLE);
}
}
else {
mEmptyView.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
mListView.setVisibility(View.VISIBLE);
mListView.invalidate();
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
if(mSuggestionAdapter != null) {
mSuggestionAdapter.changeCursor(null);
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(isNewTagView){
TextView tv = (TextView)view;
mEditText.setText(tv.getText());
Button ok = getButton(BUTTON_POSITIVE);
if(ok != null){
ok.performClick();
}
} else {
CheckedTextView ctv = (CheckedTextView)view;
boolean checked = !ctv.isChecked();
ctv.setChecked(checked);
mCheckedState.put(id, new CheckedState(id, checked, true));
}
}
public static class TagCursorLoader extends CursorLoader {
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
private TagDialog dialog;
private MLDatabase mlDatabase;
private Cursor mCursor;
private String mFilter;
private Integer mAnnotationID;
// Runs on worker thread
#Override
public Cursor loadInBackground(){
Cursor cursor = null;
if(dialog.isNewTagView){
mFilter = dialog.getFilter();
cursor = mlDatabase.getTagSuggestions(mFilter);
} else {
cursor = mlDatabase.queryTags(dialog.mSortAlpha);
}
if(cursor != null){
cursor.registerContentObserver(mObserver);
}
return cursor;
}
//Runs on UI thread
#Override
public void deliverResult(Cursor cursor){
//Handle if canceled in the middle.
if(isReset()){
if(cursor != null){
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if(isStarted()) {
super.deliverResult(cursor);
}
if(oldCursor != null && !oldCursor.equals(cursor) && !oldCursor.isClosed()) {
oldCursor.close();
}
}
public TagCursorLoader(Context context, TagDialog dialog) {
super(context);
this.dialog = dialog;
mlDatabase = dialog.getDatabase();
}
#Override
public void onStartLoading(){
if(mCursor == null) {
forceLoad();
} else {
if(dialog.isNewTagView && mFilter.equals(dialog.getFilter())) {
deliverResult(mCursor);
} else {
forceLoad();
}
}
}
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
#Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
}
/**
* Class is used to store the temporary checked state of the tags.
*/
public class CheckedState implements Serializable {
private static final long serialVersionUID = 1263560458217339487L;
/**
* #serialField
*/
private long tagID;
/**
* #serialField
*/
private boolean checked;
/**
* #serialField
*/
private boolean changed;
/**
* Constructor for CheckedState.
* #param tagID The tag ID
* #param checked The Current Checked State
* #param changed Ture if changed in the dialog. False if pulling from database.
*/
public CheckedState(long tagID, boolean checked, boolean changed){
this.tagID = tagID;
this.checked = checked;
this.changed = changed;
}
public long tagID(){
return tagID;
}
public boolean checked() {
return checked;
}
public boolean changed() {
return changed;
}
}
}
Note I didn't add my XML before.
That is where the issue resides.
andriod:animateLayoutChanges
doesn't work with what I was trying to do.
Once I removed that from my XML it worked like a charm.
In most examples that I see, the you create your adapter instance once and set it into the ListView when you view is created, and then call getLoaderManager().initLoader().
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
Then in the onLoadFinished() method you call swapCursor() which automatically refreshes the ListView.
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
...
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
}
The above code was copied from the Loaders documentation
http://developer.android.com/guide/topics/fundamentals/loaders.html
UPDATE:
The documentation talks about using Loaders for Activities and Fragments, but doesn't mention using Dialogs. I'm guessing that if getLoaderManager() exists you are fine, but if you are not using the LoaderManager and you are running the Loader manually yourself, then I would think that you'd need to ensure that when you call swapCursor() or setAdapter() that you are doing this on the UI thread. Sometimes the easiest way to ensure this, is to call
getListView().post(new Runnable() {
public void run() {
// so the setAdapter() or swapCursor() here
}
});
I have run into cases myself where I've updated a ListView in the background and it doesn't reflect as being updated until I rotate the device, because the UI wasn't updated on the UI thread.

Categories

Resources