How to use startmanagingcursor in fragment? - android

How can I use startmanagingcursor in fragment? Because I need to pull data from SQLite in Fragment but I cannot use startmanagingcursor in it.
Here is my coding
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dbUtil.open();
Cursor cursor = dbUtil.fetchNews(getArguments().getString("title"));
getActivity().startManagingCursor(cursor);
newsTitle = cursor.getString(0);
dbUtil.close();
}

Since everyone else seems to want to preach at you and not give you an answer, I'll actually answer your question (then preach :p).
getActivity().startManagingCursor(yourCursor);
It's as simple as that.
As others have noted, it's deprecated and a CursorLoader is recommended for many reasons... keeping data processing off the UI thread being the major one.
But if you truly need/want to use startManagingCursor in a fragment, the above snippet is how you would do it.
Given the further information you have posted, another issue might be where you are trying to call your database from. You should not use the onCreate method in a fragment class (at least for these operations), you should use onActivityCreated. That way you are certain that the activity that controls your fragment has finished setting itself up before you try and use anything associated with it.

Related

How to create functionality as TikTok / Musical.ly for android app?

Screen 1: GridView
Screen 2: Detail Page
Task Achieve:
1) Load all the videos in gridview from the server.
2) User clicks at any position of gridview item.
3) Open and play the particular video in detail screen.
4) On vertical scroll play next or previous videos.
Current Implementation:
GridFragment {
ArrayList<VideoPostModel> videoPostList;
RecyclerView gridView;
onnItemClick() {
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("data", videoPostList);
intent.putExtra("click_index", clickedIndex);
intent.putExtra("pagination_index", paginationIndex);
startActivity(intent);
}
}
DetailActivity {
VerticlaViewPager vertiCalViewPager;
ArrayList<VideoPostModel> videoPostList;
onCreate() {
videoPostList = getIntent().getParcelableArrayListExtra("data");
clickedIndex = getIntent().getIntExtra("clickindex", 0);
paginationIndex = getIntent().getIntExtra("pagination_index", 0);
VideoFragmentStatePagerAdapter viewPagerAdapter = new VideoFragmentStatePagerAdapter(videoPostList);
vertiCalViewPager.setAdapter(viewPagerAdapter);
}
}
Problem:
If videoPostList has more data(approx 100+ objects of VideoPostModel) while passing data from fragment to activity then app crashes, as there is a limitation of sending data with intent(https://stackoverflow.com/a/37054839/3598052).
Hacky Alternatives:
1) Static arraylist
2) Arraylist in Application class
Looking for the OPTIMAL and EFFICIENT solution to achieve above functionality.
Any suggestion, reference link or code in the direction of achieving this would be highly appreciated, and thanks in advance.
Update 1:
Another solution I found is passing data with enum, but as per comments I'm not sure about it's performance. Refrence: https://stackoverflow.com/a/14706456/3598052
I think you can write in an activity or use Arraylist in the application as you mentioned. Or it could be a library that recently appeared in the Android Jetpack. It is similar in nature to the Arraylist in application.
ViewModel objects that make it easier to manage and store data.
It lets you access data at different activities or fragments in an application. You try it and hope it will be useful to you
You have several options. I'll put my opinion here.
Static list
Enum
Singleton class with list
LiveData
Most easy would be making static list at activity or application level. Just make sure you are freeing up List memory after use by making it NULL.
Another solution I found is passing data with enum, but as per
comments I'm not sure about it's performance
There would be sure some differences in each of above approaches. But that would not be measurable difference, because each approach put List in memory, use it and then free up.
Looking for the OPTIMAL and EFFICIENT solution to achieve above
functionality.
Make static List, and make it NULL after use. will be most efficient and easy way.
You can make List NULL in onDestroy() of your Fragment.
You can use LiveData but I think it would be not a good idea to add LiveData library just for one use in app. Also you need to understand it first. So you can go with static list.
in Activity
showFragment();
ApplicationClass.list = myList;
In Fragment
onViewCreated(){
...
setAdapter(ApplicationClass.list);
...
}
onDestroy(){
ApplicationClass.list = null;
}
Important
It is never a good idea to pull all data at once from server. Please do pagination, which you app needs most, because there can be thousands of users online at one time.
So by that approach you will pass only few items to Fragment. then you will do pagination in Fragment.
This approach needs time to change flow a bit. But is most robust way in your case.
Edit
If you are already using pagination and still getting large data at one time, that's again an issue. Because pagination is used to escape these memory issues.
You can do 2 things as solution.
1. Ask for limited data at once, say 50-60 items per request.
2. You can map and remove unnecessary fields from your list when passing in intent.
I would prefer the first one.
I know I'm late but this will help some future visitor.
Add Pagination & transfer data with arraylist & clicked position to detail activity using intent & after, set the current position of clicked position.
like viewpager.setCurrentPosition(clickedPosition);

Should I persist data objects in onSaveInstanceState

I'm using greenDAO in my android app to display a list of objects in a RecyclerView. I have a subclass of RecyclerView.Adapter that takes a list of objects which are greenDAO entities.
What I do in onCreate is:
Create an instance of my adapater passing null for my list. This is just to make the adapter known to the RecyclerView below.
Initialize the RecyclerView with layout and adapter.
Call a method that asynchronously queries the data using greenDAO and upon success updates the adapter with the actual list of objects so they are displayed.
This is the relevant code:
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mListAdapter = new MyRecyclerAdapter(null);
mList.setHasFixedSize(true);
mList.setLayoutManager(mLayoutManager);
mList.setAdapter(mListAdapter);
refreshItems();
}
public void refreshItems()
{
AsyncSession asyncSession = ((App)getApplication()).getDaoSession().startAsyncSession();
asyncSession.setListenerMainThread(new AsyncOperationListener()
{
#Override
public void onAsyncOperationCompleted(final AsyncOperation operation)
{
if (operation.isCompletedSucessfully())
mListAdapter.setItems((List<Item>) operation.getResult());
}
});
asyncSession.loadAll(Item.class);
}
This works pretty well. Now I noticed, that of course the method that queries the database via greenDAO is invoked every time I rotate the activity or come back to it from another activity. That's pretty clear, since I'm calling that method from onCreate.
My question is: is it best practice to do this like I'm doing it (requery DAO every time) or should I make my objects parcelable and save the list I have in onSaveInstanceState and restore it in onRestore instead of requerying DAO?
What you're doing is completely valid and you don't need to save the queried data in onSaveInstanceState(), use in-memory cache, or any other optimization (even if GreenDAO wouldn't have internal cache).
In fact, you're more than all-right because you perform the query asynchronously - GreenDAO's creators kind of claim that the queries can be executed on UI thread in most cases (which I find hard to agree with).
I would also suggest that you perform data query in onStart() instead of onCreate(). I personally think that onCreate() should be used only for operations you would otherwise perform in the constructor (e.g. fields initializations). Another reason to perform this query in onStart() is that if the user leaves your application for a long time and then gets back to it, the data might get outdated (e.g. due to background syncs by SyncAdapter) and you'll want to refresh it.
The last piece that you might want to add is "data change notifications". You will want this mechanism to be in place if the data that you query and display to the user can change without user's interaction (e.g. due to background syncs by SyncAdapter). The concept is simple - Activity registers for notifications about data change in onCreate(), and if notification received you perform re-query in order to make sure that the user sees an up-to-date data.
I can't claim that the above are "best practices", but they are good practices that work well.
Lazy list:
As #pskink suggested in his comment, you could also employ LazyList. Be aware, though, that it doesn't obviate a need for async query of data. Usage of LazyList allows you to perform the query as usual, but load the results into memory in on-demand way. This might be useful if you expect the query to produce lots of data.
In my opinion, however, one should optimize the code only if actual performance problem is being observed. So, unless you know ahead of time that a particular query produces thousands of results, I say you don't need LazyList.

Is it actually unsafe to call stopLoading on a Loader that is being managed?

The android documentation for Loader#stopLoading() says:
When using a Loader with LoaderManager, you must not call this method
yourself, or you will conflict with its management of the Loader.
But is that really true? Specifically I am interested in CursorLoader. I looked the through the Android source for version 4.2 and it seems pretty benign. Has anyone tried using this method and seen a problem? Is there an alternative if I want to keep the current active Cursor last delivered by the CursorLoader and also stop it temporarily from reloading due to the internal ContentObserver being triggered? Basically I want to make a bunch of changes to the ContentProvider that is the source of this managed Cursor and I don't want the Loader kicking off a ton of loads until I am done.
I agree with a.ch that relying on the Android source code isn't the way to go not just because you risk breaking your app with future updates but also because of the hundreds of modified versions of Android (the joy of fragmentation). stopLoading() wouldn't work anyway, for reasons see below.
cancelLoad() will not close the underlying cursor (where did you get that from?) so while this method will cancel a load if one is in progress, it won't prevent future loads. And even if it would prevent future loads it wouldn't work either (for the same reasons stopLoading() won't work).
My initial idea to solve this was to implement a custom CursorLoader and just override the onContentChanged() method using a flag to decide whether to "take" the changes or not. This way one could temporarily disable the update:
class MyCursorLoader extends CursorLoader {
private boolean mDontUpdate;
public MyCursorLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
super(context, uri, projection, selection, selectionArgs, sortOrder);
}
#Override
public void onContentChanged () {
if (! mDontUpdate) {
super.onContentChanged();
}
}
#Override
public boolean takeContentChanged () {
return mDontUpdate ? false : super.takeContentChanged();
}
void dontUpdate(boolean dontUpdate) {
mDontUpdate = dontUpdate;
}
}
You would use this class instead of the CursorLoader in the onCreateLoader(int, Bundle) and you would set the don't update flag during the database update.
Now that works nicely except it doesn't. While it's not clear from the question what the CursorLoader and the resulting Cursor are used for I assume the Cursor is used in a CursorAdapter for a ListView or a similar widget.
The widget registers its own ContentObserver to the Cursor and updates the views accordingly. So even if no new Cursor is loaded a ListView (a GridView or any other widget attached to the Cursor) would still update (Android would call the newView, bindView methods in a CursorAdapter).
This brings me to my next approach.
Although it's not clear from your question I assume you are doing some modifications to a database? If that's the case then why not do all the modifications in a single transaction? If done in one transaction changes wouldn't show anywhere before the transaction is committed and that's probably what you want.
If your Cursor isn't backed by a database though you would probably have to remove the Adapter from your widget during the update.
First of all, you shouldn't rely on the android source code: if there are no any issues with the current android build, it doesn't mean there won't be any in future. I'd suggest considering android system as a black box, this will let you write robust and reliable apps.
According to your question on the alternative, consider cancelLoad().

Correct approach for async ListFragment

I'm pretty new to Android and I'm finding it difficult to figure out the correct/best way to accomplish the following:
I'm using ActionBarSherlock to have a set of tabs that each load a fragment. One of these is a ListFragment (actually SherlockListFragment). I started off by simply using a new thread to load the list, and all seemed fine, until you switch to a different tab before the list has loaded. Then it fails at SetListShown(true) because I guess the fragment is not active.
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
SetListShown(false);
var listView = (ListView) Activity.FindViewById(Android.Resource.Id.List);
Button loadMore = new Button(Activity);
loadMore.SetText("Load more articles", TextView.BufferType.Normal);
loadMore.Click += LoadMoreArticles;
listView.AddFooterView(loadMore);
ThreadPool.QueueUserWorkItem((obj) => {
var articles = _articleService.GetArticles(0, 10, DateTime.UtcNow);
_items = articles.Select(x => new ArticleSummaryModel(x)).ToList();
Activity.RunOnUiThread(() => {
_adapter = new ArticleList_Adapter(Activity, _items);
ListAdapter = _adapter;
SetListShown(true);
});
});
}
What I'd like to happen is that when a tab is opened for the first time it starts loading the data, showing the standard progress indicator, then then it completes the list is shown and the progress indicator removed. If the tab is change while data is loading, it should be visible when that tab is opened again.
If there's a simple way to achieve this that I've missed, great! It it's simply not possible with Android, I'd like to know that too so I can stop trying ;-)
I've read a lot about AsyncTask, AsyncTaskLoader, IntentService, etc. but I'm not at all clear what I need to use, and it any of these would actually achieve what I want!
FYI I'm using mono for android and the compatibility pack to support v2.3+, but can hopefully translate any java examples etc.
Many thanks in advance!
Robin
I'm not sure how this would work with monodroid but I'm guessing it should be about the same. Use an AsyncTaskLoader since they are tied to the activity lifecycle through the LoaderManager. You should have your fragments implement the LoaderCallbacks interface and call loaderManager.init(...) somewhere in there (for example, in onActivityCreated). When the loader task is finished you'll be notified in onLoadFinished with the data and there you can load your it into the adapter and do the progressbar and listview transition. You can find examples on how to implement an AsyncTaskLoader on the documentation page here or with a bit more detail here. As for the transition, use something like this which gives some polish to your app.

What is the recommended way to manage cursors in Android with SimpleCursorTreeAdapter?

I have an class that extends ExpandableListActivity. To fill the data for this list, I'm using a class that extends SimpleCursorTreeAdapter. I have a group (top-level) cursor that looks something like this:
mGroupCursor = ((MyApplication)getApplication()).
getDatabaseHelper().getGroupCursor();
startManagingCursor(mGroupCursor);
Of course, I also need to provide the child cursors:
#Override
protected Cursor getChildCursor(Cursor groupCursor)
{
Cursor childCursor = ((MyApplication)getApplication().
getDatabaseHelper().
getChildCursorForGroup(groupCursor.getInt(mGroupIdIndex));
startManagingCursor(childCursor);
return childCursor;
}
I was under the impression that I could call startManagingCursor on these cursors and everything would be taken care of. Apparently that is not the case, because leaving the list view and coming back with the back button throws an exception, "unable to resume activity: attempting to requery closed cursor" or something like that.
Removing the calls to startManagingCursor() fixes the problem, although I think that this is not really the right way to do things because in this case I'm not closing the cursors anywhere.
What is the recommended way to handle these cursors? I'm looking for something simple and lightweight. My database is a local SQLite database and is relatively small, so as long as the performance isn't unreasonably slow it's not an issue for me.
startManagingCursor is obsolete. I'd look at using an AsyncTask to get the cursors in the background, and set the observers yourself.

Categories

Resources