How to run SQLite query asynchronously - android

I'm trying to get all the contacts from my SQLite database.
Everything is working fine, I just want to make it asynchronous and not run in the main thread, to not influence the UI.
public List<contacts> getAllcontacts() {
List<contacts> contactsl = new LinkedList<contacts>();
String query = "SELECT * FROM contacts WHERE show is not 'NOTSIGNEDUP'"
+" ORDER BY name COLLATE NOCASE;";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
contacts contact = null;
if (cursor.moveToFirst()) {
do {
contact = new contacts();
contact.setName(cursor.getString(1));
contact.setNumero(cursor.getString(3));
contact.setProfil(cursor.getString(2));
contact.setShow(cursor.getString(5));
contact.setBlocked(cursor.getString(4));
contact.setObjectid(cursor.getString(6));
contactsl.add(contact);
} while (cursor.moveToNext());
}
return contactsl;
}
I'm calling this function from my activity :
final sql s = sql.getInstance(getContext());
if (ContactsList != null) {
ContactsList.clear();
ContactsList.addAll(list);
ContactsList.addAll(s.getAllcontacts_());
cAdapter.notifyDataSetChanged();
}
Is there any way to make s.getAllcontacts() runs asyn
I made my Fragment like this :
public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<contacts>> {
private RecyclerView mRecyclerView;
private LinearLayoutManager mLayoutManager;
private ContactsAdapter cAdapter;
private List<contacts> ContactsList;
public ContactsFragment() {
// Required empty public constructor
}
public void set(List<contacts> list) {
final sql s = sql.getInstance(getContext());
if (ContactsList != null) {
ContactsList.clear();
ContactsList.addAll(list);
ContactsList.addAll(s.getAllcontacts_());
cAdapter.notifyDataSetChanged();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View view = getView();
if(view != null) {
mRecyclerView = (RecyclerView) view.findViewById(R.id.contacts_recycler);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(view.getContext());
mRecyclerView.setLayoutManager(mLayoutManager);
final sql s = sql.getInstance(view.getContext());
ContactsList = new ArrayList<contacts>();
cAdapter = new ContactsAdapter(ContactsList, mRecyclerView);
mRecyclerView.setAdapter(cAdapter);
getLoaderManager().initLoader(0, null, this);
}
}
#Override
public android.support.v4.content.Loader<List<contacts>> onCreateLoader(int id, Bundle args) {
return new AppListLoader(this.getContext());
}
#Override
public void onLoadFinished(android.support.v4.content.Loader<List<contacts>> loader, List<contacts> data) {
ContactsList.addAll(data);
cAdapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(android.support.v4.content.Loader<List<contacts>> loader) {
}
public static class AppListLoader extends AsyncTaskLoader<List<contacts>> {
final sql s = sql.getInstance(getContext());
public AppListLoader(Context context) {
super(context);
}
#Override
public List<contacts> loadInBackground() {
return s.getAllcontacts();
}
}
}

in addition to what #CommonsWare suggests, you could also use give to the AsyncTaskLoader a try. You could define
public static class AppListLoader extends AsyncTaskLoader<List<Contact>> {
and move your querying logic in loadInBackground().
Your Activity/Fragment will make then use of the LoaderManager. It will implement LoaderManager.LoaderCallbacks<List<Contact>> and onCreateLoader will return a new instance of your AsyncTaskLoader. The List<Contact> will be delivered as part of onLoadFinished

Related

How to assign date/time to specific item in RecyclerView?

I'm developing a simple To do App. The recyclerview gets items from Sqlite datebase.
By clicking the specific item, i want to assign date from Calendar to that item. Now i want to schedule each item in recyclerview with date. I'm facing problem to assign date/time to specific item because when i add date, it shows as next item in recyclerview
#Override
public void onBindViewHolder(#NonNull final MyHolder holder, final int position) {
final InboxViewModel inboxViewModel = (InboxViewModel) arrayList.get(position);
holder.textView.setText(inboxViewModel.getText());
holder.date.setText(inboxViewModel.getDate());
setAnimation(holder.itemView, position);
MainClass is:
public class InboxFragment extends Fragment{
RecyclerView inbox_recyclerview;Inbox_Adapter adapter;
ArrayList arrayList;
String myId,myTask,myDate; int pos;String dt;
MyDatabase db;
private InboxViewModel inboxViewModel;
FragmentHelper fragmentHelper; BottomSheetListener bottomSheetListener;
RelativeLayout relativeLayout; DataController dataController;
ActivityMain activityMain;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
fragmentHelper = (FragmentHelper) context;
bottomSheetListener=(BottomSheetListener)context;
dataController=(DataController)context;
activityMain=(ActivityMain)context;
}
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_inbox, container, false);
relativeLayout=root.findViewById(R.id.relative1);
arrayList=new ArrayList<>();
inbox_recyclerview=root.findViewById(R.id.inbox_recycler);
inbox_recyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
inbox_recyclerview.setHasFixedSize(true);
// dataController.onGetData();
MyDatabase myDatabase = new MyDatabase(getContext());
Cursor c = myDatabase.getData();
if (c.getCount() == 0) {
Toast.makeText(getContext(), "no data available", Toast.LENGTH_SHORT).show();
} else {
if (c.moveToFirst()) {
do {
myId = c.getString(c.getColumnIndex(myDatabase.id));
myTask = c.getString(c.getColumnIndex(myDatabase.task_col));
myDate = c.getString(c.getColumnIndex(myDatabase.date_col));
inboxViewModel =new InboxViewModel(myTask,myId,myDate);
arrayList.add(inboxViewModel);
} while (c.moveToNext());
{
adapter=new Inbox_Adapter(getActivity(),arrayList,fragmentHelper,bottomSheetListener);
inbox_recyclerview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
}
inbox_recyclerview.setItemAnimator(new DefaultItemAnimator());
inbox_recyclerview.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.VERTICAL));
return root;
}
}
MainFragmentClass is:
public class InboxFragment extends Fragment{
RecyclerView inbox_recyclerview;Inbox_Adapter adapter;
ArrayList arrayList;
String myId,myTask,myDate; int pos;String dt;
MyDatabase db;
private InboxViewModel inboxViewModel;
FragmentHelper fragmentHelper; BottomSheetListener bottomSheetListener;
RelativeLayout relativeLayout; DataController dataController;
ActivityMain activityMain;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
fragmentHelper = (FragmentHelper) context;
bottomSheetListener=(BottomSheetListener)context;
dataController=(DataController)context;
activityMain=(ActivityMain)context;
}
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_inbox, container, false);
relativeLayout=root.findViewById(R.id.relative1);
arrayList=new ArrayList<>();
inbox_recyclerview=root.findViewById(R.id.inbox_recycler);
inbox_recyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
inbox_recyclerview.setHasFixedSize(true);
// dataController.onGetData();
MyDatabase myDatabase = new MyDatabase(getContext());
Cursor c = myDatabase.getData();
if (c.getCount() == 0) {
Toast.makeText(getContext(), "no data available", Toast.LENGTH_SHORT).show();
} else {
if (c.moveToFirst()) {
do {
myId = c.getString(c.getColumnIndex(myDatabase.id));
myTask = c.getString(c.getColumnIndex(myDatabase.task_col));
myDate = c.getString(c.getColumnIndex(myDatabase.date_col));
inboxViewModel =new InboxViewModel(myTask,myId,myDate);
arrayList.add(inboxViewModel);
} while (c.moveToNext());
{
adapter=new Inbox_Adapter(getActivity(),arrayList,fragmentHelper,bottomSheetListener);
inbox_recyclerview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
}

Android onCreateLoader incompatible types [duplicate]

I considered some examples of working with AsyncTaskLoader and Fragment (https://gist.github.com/codeswimmer/884591) and I tried to do the same. But now I can't fix incompatible types error - in method onCreateLoader. I have no idea why it happens, because I have done the same.
FeedLoader.java
public class FeedLoader extends AsyncTaskLoader<ArrayList<RSSItemData>> {
ArrayList<RSSItemData> listData;
Context ctx;
RSSItemData rssItem;
final Integer HTTP_CONNECTION_TIMEOUT = 15;
DBHelper dbHelper;
public FeedLoader(Context context) {
super(context);
this.ctx = context;
dbHelper = new DBHelper(ctx);
}
#Override
public ArrayList<RSSItemData> loadInBackground() {
listData = new ArrayList<RSSItemData>();
if(!BaseUtils.isNetworkAvailable(ctx)) return getNewsFromDB();
if(doWeHaveAnyNews()){
Log.d("myLogs", "We have news!");
String data = JSONUtils.getJSON("http://I-changed-URL.com", HTTP_CONNECTION_TIMEOUT*1000, ctx);
JSONResult result = new Gson().fromJson(data, JSONResult.class);
listData = result.items;
deleteAllNewsFromDB();
putNewsIntoDB(listData);
}
else{
Log.d("myLogs", "No news, retrieve from database");
listData = getNewsFromDB();
}
Log.d("myLogs", "Size of listData - " + listData.size());
return listData;
}
public boolean doWeHaveAnyNews() {...}
public void putNewsIntoDB(ArrayList<RSSItemData> listData) {...}
public void deleteAllNewsFromDB() {...}
public ArrayList<RSSItemData> getNewsFromDB() {...}
}
RetrieveFeedFragment.java
public class RetrieveFeedFragment extends Fragment implements LoaderManager.LoaderCallbacks<ArrayList<RSSItemData>> {
private RecyclerView rvNews;
LinearLayout progBarLinearLayout;
ProgressBar progBar;
TextView progBarText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
getActivity().getSupportLoaderManager().initLoader(0, null, this).forceLoad();
Log.d("myLogs", "Fragment onCreate");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("myLogs", "Fragment onCreateView");
View v = inflater.inflate(R.layout.news_list_fragment, null);
rvNews = (RecyclerView) v.findViewById(R.id.listViewNews);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rvNews.setLayoutManager(llm);
rvNews.setHasFixedSize(true);
rvNews = (RecyclerView) v.findViewById(R.id.listViewNews);
progBarLinearLayout = (LinearLayout) v.findViewById(R.id.progressBarLinearLayout);
progBar = (ProgressBar) v.findViewById(R.id.progressBar);
progBarText = (TextView) v.findViewById(R.id.progressBarText);
return v;
}
#Override
public Loader<ArrayList<RSSItemData>> onCreateLoader(int id, Bundle args) {
return new FeedLoader(getActivity());
/* Incompatible types ERROR
Required - anroid.support.v4.content.Loader <java.util.ArrayList<com.project.myproject.RetrieveFeed.RSSItemData>>
Found - com.project.myproject.RetrieveFeed.FeedLoader
*/
}
#Override
public void onLoadFinished(Loader<ArrayList<RSSItemData>> loader, ArrayList<RSSItemData> listData) {
// RSSAdapter = new RSSAdapter(listData, getActivity());
// rvNews.setAdapter(RSSAdapter);
// progBarLinearLayout.setVisibility(LinearLayout.GONE);
Log.d("myLogs", "onLoadFinished");
}
#Override
public void onLoaderReset(Loader<ArrayList<RSSItemData>> loader) {
Log.d("myLogs", "onLoaderReset");
}
}
MainActivity.java (just in case)
public class MainActivity extends FragmentActivity {
RetrieveFeedFragment fragment;;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null){
fragment = new RetrieveFeedFragment();
getSupportFragmentManager().beginTransaction().add(R.id.fragment_news, fragment, "retrieve_feed_tag").commit();
Log.d("myLogs", "New Fragment in Activity");
}
else{
fragment = (RetrieveFeedFragment) getSupportFragmentManager().findFragmentByTag("retrieve_feed_tag");
Log.d("myLogs", "Get old Fragment by tag in Activity");
}
}
}
Check your imports. Make sure you are using
android.support.v4.app.LoaderManager.LoaderCallbacks<D> instead of
android.app.LoaderManager.LoaderCallbacks<D> in your Fragment and android.support.v4.content.AsyncTaskLoader<D> in your FeedLoader

SearchView doesn't work with RecyclerView & SQLite

I have a Fragment with a RecyclerView. users input data and they will store in a SQLite DataBase. i am trying to Search in the items of this RecyclerView but it does not work,
here is my Fragment :
public class FragmentOne extends Fragment {
private RecyclerView mDetailRecyclerView;
private DetailAdapter mAdapter;
private boolean mNumberVisible;
private SearchView sv;
private ArrayList<Detail> mDetails=new ArrayList<>();
private View view;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_one_layout,
container, false);
mDetailRecyclerView = (RecyclerView) view.findViewById(R.id.detail_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
layoutManager.setReverseLayout(true); //This will reverse the data order but not scroll the RecyclerView to the last item
layoutManager.setStackFromEnd(true); //For keeping data order same and simply scrolling the RecyclerView to the last item
mDetailRecyclerView.setLayoutManager(layoutManager);
if (savedInstanceState != null) {
mNumberVisible =
savedInstanceState.getBoolean(SAVED_NUMBER_VISIBLE);
}
sv = (SearchView) view.findViewById(R.id.sv);
mAdapter = new DetailAdapter(mDetails);
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit (String query) {
return false;
}
#Override
public boolean onQueryTextChange(String query) {
getDetailsSearch(query);
return false;
}
});
initViews();
updateUI();
return view;
}
#Override
public void onResume() {
super.onResume();
updateUI();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(SAVED_NUMBER_VISIBLE, mNumberVisible);
}
..
..
private class DetailHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnLongClickListener {
private TextView mTitleTextView;
// private TextView mDateTextView;
private Detail mDetail;
private RatingBar mRatingBar;
public DetailHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.list_item_detail,
parent, false));
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
mTitleTextView = (TextView) itemView.findViewById(R.id.detail_title);
mRatingBar = (RatingBar) itemView.findViewById(R.id.ratingBar);
}
public void bind(Detail detail) {
mDetail = detail;
mTitleTextView.setText(mDetail.getTitle());
mRatingBar.setRating(mDetail.getRate());
}
#Override
public void onClick(View view) {
Intent intent = DetailPagerActivity.newIntent(getActivity(),
mDetail.getId());
startActivity(intent);
}
}
private class DetailAdapter extends RecyclerView.Adapter<DetailHolder> {
private List<Detail> mDetails;
private Detail mDetail;
public DetailAdapter(List<Detail> details) {
mDetails = details;
}
#Override
public DetailHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
return new DetailHolder(layoutInflater, parent);
}
#Override
public void onBindViewHolder(DetailHolder holder, int position) {
Detail detail = mDetails.get(position);
holder.bind(detail);
}
#Override
public int getItemCount() {
return mDetails.size();
}
public void setDetails(final List<Detail> details) {
mDetails = details;
}
..
..
}
public void initViews(){
mDetailRecyclerView.setAdapter(mAdapter);
initSwipe();
}
..
..
private void getDetailsSearch (String searchTerm) {
mDetails.clear();
DBAdapter db = new DBAdapter(getActivity());
db.openDB();
Detail p = null;
Cursor c = db.retrieve(searchTerm);
while (c.moveToNext()) {
String title = c.getString(2);
p = new Detail();
p.setTitle(title);
mDetails.add(p);
}
db.closeDB();
mDetailRecyclerView.setAdapter(mAdapter);
}
}
and this is my Database Adapter:
public class DBAdapter {
Context c;
SQLiteDatabase db;
DetailBaseHelper helper;
public DBAdapter (Context c) {
this.c = c;
helper = new DetailBaseHelper(c);
}
public void openDB() {
try {
db = helper.getWritableDatabase();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void closeDB() {
try {
helper.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Cursor retrieve (String searchTerm) {
String[] columns = {
"_id",
"uuid",
"title",
"des",
"date",
"rate"
Cursor c = null;
if (searchTerm != null && searchTerm.length()>0) {
String sql ="SELECT * FROM " +DetailDbSchema.DetailTable.NAME+
" WHERE "+DetailDbSchema.DetailTable.Cols.TITLE+
" LIKE '%"+searchTerm+"%'";
c = db.rawQuery(sql, null);
return c;
}
c = db.query(DetailDbSchema.DetailTable.NAME, columns,
null, null, null, null, null);
return c;
}
}
and here is DataBase Helper:
public class DetailBaseHelper extends SQLiteOpenHelper{
private static final int VERSION = 1;
private static final String DATABASE_NAME = "detailBase.db";
public DetailBaseHelper (Context context) {
super(context, DATABASE_NAME, null, VERSION);
}
#Override
public void onCreate (SQLiteDatabase db) {
db.execSQL("create table " + DetailTable.NAME +
"(" +
" _id integer primary key autoincrement," +
DetailTable.Cols.UUID + ", " +
DetailTable.Cols.TITLE + ", " +
DetailTable.Cols.DES + ", " +
DetailTable.Cols.DATE + ", " +
DetailTable.Cols.RATE +
")"
);
}
#Override
public void onUpgrade (SQLiteDatabase db,
int oldVersion, int newVersion) {
}
}
here is the tutorial that i used for this,
I'll be appreciate if u have any idea for helping me.
I think that the main problem is here you're changing the adapter, but the new adapter was never modified by the data of the results, and also you have to notify your recycler that the data set changed. so
private void getDetailsSearch (String searchTerm) {
mDetails.clear();
/// the loop wiith the cursor
/// change the dataset
mAdapter = new DetailAdapter(mDetails);
mDetailRecyclerView.setAdapter(mAdapter);
/// tell the recycler there is a different data to display
mDetailRecyclerView.notifyDataSetChanged();
}

Listview does not refresh when underlying Loader data changes

First, I'll preface my question with the fact that I'm not using a CursorLoader.
I'm pulling in data from a SQLlite database to populate a listview in a ListFragment. The initial load works well, but once the data is manipulated (i.e. an addition is made to the list), the listview NEVER refreshes to show the new data. I am implementing the Loader callbacks like so:
public class BillListingFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Bill>> {
private billListAdapter mAdapter;
private static final int LOADER_ID = 1;
private SQLiteDatabase mDatabase;
private BillsDataSource mDataSource;
private BillsStoreDatabaseHelper mDbHelper;
/**
* The fragment argument representing the fragment type (archive or outstanding)
*/
private static final String ARG_FRAGMENT_TYPE = "fragment_type";
/**
* Returns a new instance of this fragment based on type
*/
public static BillListingFragment newInstance(String type) {
// TODO: Make the fragment type an enum
BillListingFragment fragment = new BillListingFragment();
Bundle args = new Bundle();
args.putString(ARG_FRAGMENT_TYPE, type);
fragment.setArguments(args);
return fragment;
}
public BillListingFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.bill_view_layout, container, false);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mDbHelper = new BillsStoreDatabaseHelper(getActivity());
mDatabase = mDbHelper.getWritableDatabase();
mDataSource = new BillsDataSource(mDatabase);
mAdapter = new billListAdapter(getActivity(), R.layout.bill_row_layout);
setListAdapter(mAdapter);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public Loader<List<Bill>> onCreateLoader(int id, Bundle args) {
BillDataLoader loader = new BillDataLoader(getActivity(), mDataSource);
return loader;
}
#Override
public void onLoadFinished(Loader<List<Bill>> loader, List<Bill> data) {
for(Bill bill: data){
mAdapter.add(bill);
}
setListAdapter(mAdapter);
}
#Override
public void onLoaderReset(Loader<List<Bill>> loader) {
mAdapter.clear();
}
#Override
public void onDestroy() {
super.onDestroy();
mDbHelper.close();
mDatabase.close();
mDataSource = null;
mDbHelper = null;
mDatabase = null;
}
public void reload(){
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
private class billListAdapter extends ArrayAdapter<Bill> {
Context context;
public billListAdapter(Context context, int resourceID){
super(context, resourceID);
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.bill_row_layout, parent, false);
}
TextView payToField = (TextView) convertView.findViewById(R.id.nameField);
TextView dueDateField = (TextView) convertView.findViewById(R.id.overdueField);
payToField.setText(getItem(position).getPayTo());
// calculate days until due
Bill bill = getItem(position);
// TODO: Add how many days until bill in overdue field + add color
JodaTimeAndroid.init(getActivity());
DateTime dueDateDt = new DateTime(bill.getDateDue());
DateTime currentDt = new DateTime();
int daysDifference = Days.daysBetween(currentDt.toLocalDate(), dueDateDt.toLocalDate()).getDays();
// depending on what that differential looks like set text / color
if (daysDifference > 1) {
dueDateField.setText(Integer.toString(daysDifference) + " Days");
} else {
if (daysDifference == 0) {
dueDateField.setText("DUE TODAY");
} else {
if (daysDifference < 0) {
}
}
}
return convertView;
}
}
}
I have debugged my code so I know that the onLoadFinished callback is being made after the data has been manipulated. I also know that adapter contains the updated data at this point. I have tried resetting the adapter via setListAdapter(mAdatper) and every notifyDataChanged-like method I can find, but to no avail. What is going on here and how can I get the listview to update?

ViewPager is trying to recreate a Fragment from bad data

The main problem I am running into is that when I try to update my PagerAdapter with a brand new set of data, I get a FC. More specifically, I get the FC only if I remove something from the PagerAdapter's dataset.
In my Main activity I have this loader callback:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor newCursor) {
List<CycleItem> cycleItems = CursorInflator.inflateList(newCursor, CycleItem.class);
mCycleAdapter.setCycleList(cycleItems);
mIndicator.notifyDataSetChanged();
}
Here is my CycleViewPagerAdapter (mCycleAdapter is a reference to this):
public class CycleViewPagerAdapter extends FragmentPagerAdapter implements TitleProvider {
private ArrayList<CycleItem> mCycleItems;
private CyclePagerCallbacks mParent;
public CycleViewPagerAdapter(CyclePagerCallbacks parent, FragmentManager fm) {
super(fm);
mParent = parent;
mCycleItems = new ArrayList<CycleItem>();
}
public CycleViewPagerAdapter(FragmentManager fm, List<CycleItem> cycleItems) {
super(fm);
mCycleItems = (ArrayList<CycleItem>) cycleItems;
}
public void setCycleList(List<CycleItem> cycleItems) {
mCycleItems = (ArrayList<CycleItem>) cycleItems;
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
return CycleDetailFragment.newInstance(mParent, mCycleItems.get(position % mCycleItems.size()).getId());
}
public String getTitle(int position) {
return mCycleItems.get(position % mCycleItems.size()).getName();
}
#Override
public int getCount() {
if (mCycleItems != null) {
return mCycleItems.size();
} else {
return 0;
}
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
This CycleViewPagerAdapter creates and returns CycleDetailFragments when the getItem method is called. Here is that class:
public class CycleDetailFragment extends Fragment implements PaginatedFragmentProtocol {
public interface CyclePagerCallbacks {
public void removeCycle(Uri cycleUri);
}
private static final String TAG = "CycleDetailFragment";
private CyclePagerCallbacks mParent;
private long mCycleId;
private Cycle cycle;
private static final String CYCLE_ID_KEY = "cycle_id";
private TextView mCycleName;
private TextView mNumItem;
private Button mDeleteCycle;
public static CycleDetailFragment newInstance(CyclePagerCallbacks parent, long cycleId) {
CycleDetailFragment cycleDetailFragment = new CycleDetailFragment(parent);
Bundle bundle = new Bundle();
bundle.putLong(CYCLE_ID_KEY, cycleId);
cycleDetailFragment.setArguments(bundle);
return cycleDetailFragment;
}
public CycleDetailFragment(CyclePagerCallbacks parent) {
mParent = parent;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null) {
mCycleId = arguments.getLong(CYCLE_ID_KEY);
} else {
mCycleId = 0;
}
Log.i(TAG, Long.toString(mCycleId));
final Uri cycleUri = ContentUris.withAppendedId(CycleContentProvider.CONTENT_URI, mCycleId);
Cursor cursor = getActivity().getContentResolver().query(cycleUri, null, null, null, null);
final Cycle cycle = CursorInflator.inflateOne(cursor, Cycle.class);
Uri cycleItemsUri = ContentUris.withAppendedId(CycleItemContentProvider.CYCLE_ID_FIELD_CONTENT_URI, mCycleId);
Cursor cycleItemsCursor = getActivity().getContentResolver().query(cycleItemsUri, null, null, null, null);
mCycleName.setText(cycle.getName() + " " + cycle.getId());
mNumItem.setText(Integer.toString(cycleItemsCursor.getCount()));
mDeleteCycle.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
getActivity().getContentResolver().delete(cycleUri, null, null);
mParent.refresh();
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("Creating View", "Cycle ID: " + mCycleId);
View view = inflater.inflate(R.layout.cycle_detail, container, false);
mCycleName = (TextView) view.findViewById(R.id.cycle_name);
mNumItem = (TextView) view.findViewById(R.id.num_items);
mDeleteCycle = (Button) view.findViewById(R.id.delete_cycle);
return view;
}
#Override
public String getFragmentTitle() {
return cycle.getName();
}
}
So you see that the CycleDetailFragment looks in the database for information to populate the view.
Here is the problem I am having. After I DELETE a Cycle from the database, the onLoadFinished method is called and the cycleItems is populated with the correct items, but once mCycleAdapter.setCycleList(cycleItems) is called after this deletion I get my error. The onAcitivityCreated method in the CycleDetailFragment is called (not by me or my PagerAdapter - something else internal), but it is fed data that should no longer exist! The bundle that it is passed contains the cycleId of the item that I just deleted and that does not exist in the freshly pulled cycleItems list that I just created. So, it tries to pull something from the database that no longer exists and null pointer exceptions are thrown.
How can I refresh the dataset of my PagerAdapter without the ViewPager trying to use old data first?
shouldn't you use FragmentStatePagerAdapter here?

Categories

Resources