Android Cursor loader initialize slow - android

I tried to follow this tutorial to implement CursorLoader for listview in fragment. Everything is fine when scrolling in listview (even fast scroll, it very smooth), except the first time I switch to this fragment, cursor loader load slow a bit. Does any one know how to speed it up? here is my try:
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] projection = { DatabaseHandler.UserTable.id, DatabaseHandler.UserTable.name };
cursorLoader = new CursorLoader(this, DatabaseAccessUtility.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
public void onLoadFinished(Loader<Cursor> loader,Cursor cursor) {
if(mAdapter!=null && cursor!=null)
mAdapter.swapCursor(cursor);
public void onLoaderReset(Loader<Cursor> arg0) {
if(mAdapter!=null)
mAdapter.swapCursor(null);
}

Related

How to show ProgressiDialog when using LoaderCallbacks

I have a class that loads the images on the device. This is an example of my activity:
public class MediaListActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
private ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
progressDialog.show();
getSupportLoaderManager().initLoader(1, null, this);
}
#Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = new CursorLoader(this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor cursor) {
progressDialog.dismiss();
}
}
Of course, I can't put progressDialog.show() inside the onCreate() method, since if the ContentObserver find a change in MediaStore.Images.Media.EXTERNAL_CONTENT_URI and the Cursor is reloaded the method progressDialog.show() will not be called.
How can I solve this problem?
Thank you in advance
Try showing the dialog in onLoaderReset() callback. It is called anytime a loader is restarted, despite the onCreateLoader() that may not be called every time because the loader might already be created.

startmanagingcursor() still needed?

I am using cursorLoader in my app.
My question is I am still using startmanagingcursor(cursor); method to manage my cursor in a particularactivity. Is this function still needed?
since this method is deprecated, may I know the exact alternative method.
Everyone said LoaderManager with Loader are the solution to my problem.
The real problem is I have implemented LoaderManager and Loader along with these below overridden methods:
#Override
public void onLoaderReset(Loader<Cursor> arg0)
{
adapter.swapCursor(null);
}
#Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor)
{
adapter.swapCursor(cursor);
}
#Override
public Loader<Cursor> onCreateLoader(int arg1, Bundle instanceState)
{
CursorLoader cursorLoader= new CursorLoader(getApplicationContext(), searchContentUri, null, selection, selecArgs, null);
return cursorLoader;
}
I wanna know that here where the query is being called?

Android CursorLoader with ListView issue

I have finally after several tutorials make my CursorLoader display in my ListView but I have some questions that I hope you guys can help me to solve.
1) my big problem was this:
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
if(uriMatcher.match(uri)==CUSTOMERS){
DB.open();
return DB.leer();
}
else
{
return null;
}
}
as you can see this is from my Content Provider class, my problem was that I dont figure I need to OPEN my DB.
when I put the code for open the DB works for me but then I dont know if I need to close here or it close after doing this:
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1){
Uri uri = Contenido.CONTENT_URI;
return new CursorLoader(this, uri, null, null, null, null);
}
/** A callback method, invoked after the requested content provider returned all the data */
#Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
mAdapter.swapCursor(arg1);
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
mAdapter.swapCursor(null);
}
should I put DB.close() on any place of this functions?
Or maybe below this:
getSupportLoaderManager().initLoader(0, null, this);
getSupport is on the OnCreate Bundle. I really don't understand if its necesary close the db that is open from the Cursor query.

Android - onLoadFinished not called

I am facing an issue with Loader.
I have an Activity, which displays list of records retrieved from local DB. When the activity starts, records are automatically loaded via LoaderManager.initLoader() method.
There is also possibility to manually refresh the list via refresh button in ActionBarSherlock. However, after finishing another activity which adds a record to DB, onLoadFinished is not called.
I am using SimpleCursorLoader and here is code snippet from the activity:
#Override
public void onStart() {
...
getSupportLoaderManager().initLoader(0, null, this);
}
#Override
public void onPause() {
...
getSupportLoaderManager().destroyLoader(0);
}
public void refreshRecords() {
getSupportLoaderManager().restartLoader(0, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, final Bundle args) {
Loader<Cursor> l = new SimpleCursorLoader(this) {
#Override
public Cursor loadInBackground() {
return recordDAO.getCursor();
}
};
l.forceLoad();
return l;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
// updateUI
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
The issue is that after finishing the other activity, onLoaderCreate is called, but onLoaderFinished is not called.
after some debugging, I've found that SimpleCursorAdapter.deliverResults() is also called, bud ends up on .. if (isReset()) { ..
Am I missing something? How to force the reload of data?
Thank you in advance
I have finally found the solution to this problem thanks to the discussion on
https://groups.google.com/forum/#!topic/android-developers/DbKL6PVyhLI
public static <T> void initLoader(final int loaderId, final Bundle args, final LoaderCallbacks<T> callbacks,
final LoaderManager loaderManager) {
final Loader<T> loader = loaderManager.getLoader(loaderId);
if (loader != null && loader.isReset()) {
loaderManager.restartLoader(loaderId, args, callbacks);
} else {
loaderManager.initLoader(loaderId, args, callbacks);
}
}
In addition as of support library 28 make sure that you don't call initLoader from within Fragment.onCreate(). As the updated documentation states
You typically initialize a Loader within the activity's onCreate() method, or within the fragment's onActivityCreated() method.
see https://developer.android.com/guide/components/loaders
RaB solution dont work for me
My worked Solution, was always destroy Loader before restart
Loader<Cursor> loader = mLoaderManager.getLoader(mKeyLoader);
if (loader != null)
{
mLoaderManager.destroyLoader(mKeyLoader);
}
mLoaderManager.restartLoader(mKeyLoader, args, this);
In addition to RaB's answer, if you are using a custom Loader, make sure that if you call super if you overwrite deliverResult():
#Override
public void deliverResult(D data) {
super.deliverResult(data); // <--onLoadFinished() will not be called if you don't call this
...
}
fwiw, I had a similar problem from attempting to immediately restart the loader a second time, before the first onLoadFinished was called, resulting in neither being called.
this worked for me:
if( loader == null )
loader = loaderMngr.initLoader(
0, null, myLoaderCallbacks
);
else if( loader.isAbandoned() )
return;
else
loaderMngr.restartLoader(
0, null, myLoaderCallbacks
);
Check the support library.Use this import android.support.v4.app. Don't use android.app.loadermanager.
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
Initialize part
LoaderManager mLoaderManager=getSupportLoaderManager();
LoaderManager.LoaderCallbacks<Cursor> mCursorLoaderCallbacks=new LoaderManager.LoaderCallbacks<Cursor>() {
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle cursor) {
return new CursorLoader(getActivity(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, COLUMNS_OF_INTEREST, null, null,
MediaStore.Video.Media.DATE_ADDED + " DESC");
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
};
mLoaderManager.initLoader(URL_LOADER_EXTERNAL, null, mCursorLoaderCallbacks);

CursorLoader not showing DB entires

I've got a CursorLoader in a ListFragment (that is inside a ViewPager) that queries a database. I have a content provider for that database, which I've verified works.
The issue is this: when the app runs for the very first time a separate service calls a bulk insert in a ContentProvider:
public int bulkInsert(Uri uri, ContentValues[] values) {
if(LOGV) Log.v(TAG, "insert(uri=" + uri + ", values" + values.toString() + ")");
final SQLiteDatabase db = openHelper.getWritableDatabase();
final int match = uriMatcher.match(uri);
switch(match) {
case SNAP: {
db.beginTransaction();
for(ContentValues cv : values) {
db.insertOrThrow(Tables.SNAP, null, cv);
}
db.setTransactionSuccessful();
db.endTransaction();
getContext().getApplicationContext().getContentResolver().notifyChange(uri, null);
return values.length;
}
The CursorLoader in the list fragment returns 0 rows though on the very first run (when the database gets created). If I close and restart the app then the CursorLoader works great and returns exactly what I need. I've tried to implement waiting via a handler, but it doesn't seem to help. Here is the ListFragment that utilizes the CursorLoader:
public class DataBySnapFragment extends ListFragment implements LoaderCallbacks<Cursor> {
public static final String TAG = "DataBySnapFragment";
protected Cursor cursor = null;
private DataBySnapAdapter adapter;
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "RELOADING!!!!!");
onLoadDelay();
}
};
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated");
adapter = new DataBySnapAdapter(getActivity(),
R.layout.list_item_databysnap,
null,
new String[]{},
new int[]{},
0);
setListAdapter(adapter);
getLoaderManager().initLoader(0, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_databysnap, null);
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("error_workaround_1",
"workaroundforerror:Issue 19917,
http://code.google.com/p/android/issues/detail?id=19917");
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = new CursorLoader(getActivity(),
Snap.CONTENT_URI,
null,
null,
null,
Snap.DATA_MONTH_TO_DATE + " DESC LIMIT 6");
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
Log.d(TAG, "data rows: " + data.getCount());
if(data.getCount() <= 0) {
delayThread();
} else {
adapter.swapCursor(data);
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
private void onLoadDelay() {
getLoaderManager().initLoader(0, null, this);
}
private void delayThread() {
new Thread() {
public void run() {
longTimeMethod();
handler.sendEmptyMessage(0);
}
}.start();
}
private void longTimeMethod() {
try {
Thread.sleep(12000);
} catch (InterruptedException e) {
Log.e("tag", e.getMessage());
}
}
}
Can anyone let me know why this might be happening, or at least steer me in the right direction? Thanks!
Unless you were stalling the main thread, making a new thread and telling it to sleep wouldn't really solve anything.
I can't really say what exactly might be wrong, but it sounds like you might need to refresh your data. To test you could try to make a button with an OnClickListener which refreshes the data content, and re-pull it from the database.
Whenever your bulk insert is done you should send a message back to the fragment/activity implementing LoaderManager.LoaderCallbacks interface.
When the activity/fragment receives the message you would need to call getLoaderManager().restartLoader(0, null, this) to requery the DB.
This is what the sample app does too http://developer.android.com/guide/topics/fundamentals/loaders.html
Try to modify onLoadFinished this way:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
Log.d(TAG, "data rows: " + data.getCount());
if(data.getCount() <= 0) {
delayThread();
} else {
// set the notification for the cursor
data.setNotificationUri(getActivity().getContentResolver(), Snap.CONTENT_URI);
adapter.swapCursor(data);
}
}

Categories

Resources