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);
Related
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.
According to http://developer.android.com/guide/components/loaders.html, one of the nice thing about loader is that, it is able to retain its data during configuration change.
They automatically reconnect to the last loader's cursor when being
recreated after a configuration change. Thus, they don't need to
re-query their data.
However, it doesn't work well in all scenarios.
I take a following simple example. It is a FragmentActivity, which is hosting a Fragment. The Fragment itself owns the AsyncTaskLoader.
The following 3 scenarios work pretty well.
During first launched (OK)
1 loader is created, and loadInBackground is executed once.
During simple rotation (OK)
No new loader is being created and loadInBackground is not being triggered.
A child activity is launched, and back button pressed (OK)
No new loader is being created and loadInBackground is not being triggered.
However, in the following scenario.
A child activity is launched -> Rotation -> Back button pressed (Wrong)
At that time, old loader's onReset is called. Old loader will be destroyed. New loader will be created and new loader's loadInBackground will be triggered again.
The correct behavior I'm expecting is, no new loader will be created.
The loader related code is as follow. I run the code under Android 4.1 emulator.
package com.example.bug;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainFragment extends Fragment implements LoaderManager.LoaderCallbacks<Integer> {
private static class IntegerArrayLoader extends AsyncTaskLoader<Integer> {
private Integer result = null;
public IntegerArrayLoader(Context context) {
super(context);
Log.i("CHEOK", "IntegerArrayLoader created!");
}
#Override
public Integer loadInBackground() {
Log.i("CHEOK", "Time consuming loadInBackground!");
this.result = 123456;
return result;
}
/**
* Handles a request to cancel a load.
*/
#Override
public void onCanceled(Integer integer) {
super.onCanceled(integer);
}
/**
* Handles a request to stop the Loader.
* Automatically called by LoaderManager via stopLoading.
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to start the Loader.
* Automatically called by LoaderManager via startLoading.
*/
#Override
protected void onStartLoading() {
if (this.result != null) {
deliverResult(this.result);
}
if (takeContentChanged() || this.result == null) {
forceLoad();
}
}
/**
* Handles a request to completely reset the Loader.
* Automatically called by LoaderManager via reset.
*/
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
this.result = null;
}
}
#Override
public Loader<Integer> onCreateLoader(int arg0, Bundle arg1) {
Log.i("CHEOK", "onCreateLoader being called");
return new IntegerArrayLoader(this.getActivity());
}
#Override
public void onLoadFinished(Loader<Integer> arg0, Integer arg1) {
result = arg1;
}
#Override
public void onLoaderReset(Loader<Integer> arg0) {
// TODO Auto-generated method stub
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
return v;
}
// http://stackoverflow.com/questions/11293441/android-loadercallbacks-onloadfinished-called-twice
#Override
public void onResume()
{
super.onResume();
if (result == null) {
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
} else {
// Restore from previous state. Perhaps through long pressed home
// button.
}
}
private Integer result;
}
Complete source code can be downloaded from https://www.dropbox.com/s/n2jee3v7cpwvedv/loader_bug.zip
This might be related to 1 unsolved Android bug : https://code.google.com/p/android/issues/detail?id=20791&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/DbKL6PVyhLI
I was wondering, is there any good workaround on this bug?
My answer is quite straight forward actually. Don't use AsyncTaskLoaders. Because a few bugs regarding AsyncTaskLoaders you knew it by now.
A good combination would be a retainable (setRetainInstance(true) in onActivityCreated()) fragment with AsyncTask. Works the same way. Just have to restructure the code a bit.
Message from OP
Although the author doesn't provide any code example, this is the closest workable solution. I do not use the author proposed solution. Instead, I still rely on AsyncTaskLoader for all the necessary loading task. The workaround is that, I will rely on an additional retained fragment, to determine whether I should reconnect/create loader. The is the skeleton code on the whole idea. Works pretty well so far as long as I can tell.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
...
dataRetainedFragment = (DataRetainedFragment)fm.findFragmentByTag(DATE_RETAINED_FRAGMENT);
// dataRetainedFragment can be null still...
}
#Override
public void onResume() {
...
if (this.data == null) {
if (dataRetainedFragment != null) {
// Re-use!
onLoadFinished(null, dataRetainedFragment);
} else {
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
} else {
}
}
#Override
public void onLoadFinished(Loader<Data> arg0, Data data) {
this.data = data;
if (this.dataRetainedFragment == null) {
this.dataRetainedFragment = DataRetainedFragment.newInstance(this.data);
FragmentManager fm = getFragmentManager();
fm.beginTransaction().add(this.dataRetainedFragment, DATE_RETAINED_FRAGMENT).commitAllowingStateLoss();
}
Try to change,
#Override
public void onResume()
{
super.onResume();
if (result == null) {
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
} else {
// Restore from previous state. Perhaps through long pressed home
// button.
}
}
to
#Override
public void onResume()
{
super.onResume();
Loader loader = getLoaderManager().getLoader(0);
if ( loader != null && loader.isReset() ) {
getLoaderManager().restartLoader(0, getArguments(), this);
} else {
getLoaderManager().initLoader(0, getArguments(), this);
}
}
If you are using FragmentManager's replace fragment technique this issue will happen.
When you replace/remove the Fragment, the fragment is detached from the activity and since loaders are attached to the activity, the loaders will be recreated during orientation change.
Try using FragmentManager's hide/show technique. May be this will help you.
I've had success subclassing AsyncTaskLoader and making a few tweaks to its methods.
public class FixedAsyncTaskLoader<D> extends AsyncTaskLoader<D> {
private D result;
public FixedAsyncTaskLoader(Context context) {
super(context);
}
#Override
protected void onStartLoading() {
if (result != null) {
deliverResult(result);
} else {
forceLoad();
}
}
#Override
public void deliverResult(T data) {
result = data;
if (isStarted()) {
super.deliverResult(result);
}
}
#Override
protected void onReset() {
super.onReset();
onStopLoading();
result = null;
}
#Override
protected void onStopLoading() {
cancelLoad();
}
}
I am using an AsyncTaskLoader. I have an activity which has implemented LoaderCallbacks (Support library).
I have breakpoint debugged and put in logs, the loader delivers the result, however the second time the callback onLoadFinished is not triggered. The odd thing - when I rotate back again it works, which ever orientation I start on gets callbacks when I return to it.
In my Activity onResume:
LoaderManager lm = getSupportLoaderManager();
Loader loader = lm.initLoader(0, null, new LoaderManager.LoaderCallbacks<String>() {
#Override
public Loader<String> onCreateLoader(int i, Bundle bundle) {
Loader<String> loader = new TestLoader(MainActivity.this);
return loader;
}
#Override
public void onLoadFinished(Loader<String> stringLoader, String s) {
Log.d(Application.TAG, "OnLoadFinished " + s);
doStuff(s);
}
#Override
public void onLoaderReset(Loader<String> stringLoader) {
// NOP
}
});
In my loader:
public class TestLoader extends AsyncTaskLoader<String> {
private String mData;
public TestLoader(Context context) {
super(context);
}
// This get's called after a loader is initialized or a loader
// that is alive still is reset
#Override
public void onStartLoading() {
if (mData != null) { // Have our data loaded, just deliver it!
deliverResult(mData);
}
if (takeContentChanged() || mData == null) {
forceLoad();
}
}
// This is called when an Activity or Fragment requests a loader
// to be reset because they want new data
#Override
public void onReset() {
mData = null;
// Ensure that the old task is cancelled if it was running
// We do NOT have to call forceLoad here because onStartLoading
// will get called after this
cancelLoad();
}
// Here we just want to store our own data we got and reset our boolean
#Override
public void deliverResult(String data) {
Log.d(Application.TAG, "deliverResult " + data);
mData = data;
super.deliverResult(mData);
}
#Override
public String loadInBackground() {
// returns content from a content provider ...
}
}
Really baffled by this one, I am new to Android so maybe this is obvious to someone else :)
You must at least simply call getSupportLoaderManager() / getLoaderManager() in onCreate() if it's an Activity or onActivityCreated() if it's a Fragment. The actual initLoader() can be elsewhere. Otherwise the loader will be in a stopped state and won't deliver the results even though it completes the load. I suspect it's because the loader manager doesn't reattach the old loaders to the new Activity unless the above call is made in the new Activity's onCreate().
You have
Loader loader = lm.initLoader(...)
You should have
Loader loader = new LoaderManager.LoaderCallbacks(...) {...}
and in your onResume()
this.getLoaderManager().restartLoader(0, null, this.loader);
See Loaders documentation.
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);
}
}
I want to implement an AsyncTaskLoader in my project using the Compatibility Package, so I followed the Loader manual in Android Docs.
The problem is that the Loader does nothing, it seems loadInBackground() is never called
Any idea of what's wrong in my code?
(ExpandableListFragment extends Fragment,but doesn't override any critical method )
Thank you :-)
/**EDIT:
I realized (late, I'm a moron) that AsyncTaskLoader is an abstract class so I need to subclass it... m(__)m
I leave the question in case someone comes here behind me, who knows...
public class AgendaListFragment extends ExpandableListFragment implements
LoaderManager.LoaderCallbacks<JSONArray> {
private TreeMap<Integer, ArrayList<Evento>> mItems = new TreeMap<Integer, ArrayList<Evento>>();
private AgendaListAdapter mAdapter;
private ProgressBar mProgressBar;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_agenda, container);
mProgressBar = (ProgressBar) root.findViewById(R.id.loading);
return root;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new AgendaListAdapter(getActivity());
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
}
#Override
public Loader<JSONArray> onCreateLoader(int arg0, Bundle arg1) {
mProgressBar.setVisibility(View.VISIBLE);
return new AsyncTaskLoader<JSONArray>(getActivity()) {
#Override
public JSONArray loadInBackground() {
return getDataFromService(AgendaServices.LISTADO_MES);
}
};
}
#Override
public void onLoadFinished(Loader<JSONArray> loader, JSONArray data) {
// Some stuff to turn JSONArray into TreeMap
mProgressBar.setVisibility(View.GONE);
mAdapter.setItems(mItems);
}
#Override
public void onLoaderReset(Loader<JSONArray> arg0) {
mAdapter.setItems(null);
mProgressBar.setVisibility(View.VISIBLE);
}
}
I think the best solution for the Compatibility package is to override the AsyncTaskLoader.onStartLoading method.
e.g.
#Override
protected void onStartLoading() {
if(dataIsReady) {
deliverResult(data);
} else {
forceLoad();
}
}
This is exactly a fix but it should work. I am pretty sure the compatibility library is broken. Try this:
getLoaderManager().initLoader(0, null, this).forceLoad();
Cheok Yan Cheng is absolutely right:
Checking for takeContentChanged seems an important step too.
If you write your method like this:
protected void onStartLoading() {
forceLoad();
}
you ''ll notice that when a child activity comes up and then you return to the parent one, onStartLoading (and so loadInBackground) are called again!
What can you do?
Set an internal variable (mContentChanged) to true inside the constructor; then check this variable inside onStartLoading. Only when it's true, start loading for real:
package example.util;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
public abstract class ATLoader<D> extends AsyncTaskLoader<D> {
public ATLoader(Context context) {
super(context);
// run only once
onContentChanged();
}
#Override
protected void onStartLoading() {
// That's how we start every AsyncTaskLoader...
// - code snippet from android.content.CursorLoader (method onStartLoading)
if (takeContentChanged()) {
forceLoad();
}
}
}
Looking at discussion at https://code.google.com/p/android/issues/detail?id=14944, checking for takeContentChanged seems to be important step too.
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
I took the source code of CursorLoader from android framework, and wrote a CustomTaskLoader<T> class to ease the job.
https://github.com/Palatis/danbooru-gallery-android/blob/new_api/DanbooruGallery/src/main/java/tw/idv/palatis/danboorugallery/android/content/CustomTaskLoader.java
you basically implement these two functions:
public abstract T runTaskInBackground(CancellationSignal signal);
public abstract void cleanUp(T oldResult);
see the usage in the activities and fragments, for example this one:
(well my code just ignores the CancellationSignal, it's a TODO in my list, but you're free to use it.)
https://github.com/Palatis/danbooru-gallery-android/blob/new_api/DanbooruGallery/src/main/java/tw/idv/palatis/danboorugallery/PostListFragment.java
return new CustomTaskLoader<Cursor>(getActivity().getApplicationContext())
{
#Override
public Cursor runTaskInBackground(CancellationSignal signal)
{
return SiteSession.getAllPostsCursor(PostListAdapter.POST_COLUMNS);
}
#Override
public void cleanUp(Cursor oldCursor)
{
if (!oldCursor.isClosed())
oldCursor.close();
}
}
I have had the same problem after migrating from CursorLoader to AsyncTaskLoader.
documentation says: Subclasses of Loader<D> generally must implement at least onStartLoading(), onStopLoading(), onForceLoad(), and onReset().
AsyncTaskLoader extends Loader but not implements onStartLoading(), onStopLoading(), onReset(). You must implement it by yourself!
#davidshen84 proposed good solution. I only added checking for takeContentChanged.
#Override
protected void onStartLoading() {
try {
if (data != null) {
deliverResult(data);
}
if (takeContentChanged() || data == null) {
forceLoad();
}
Log.d(TAG, "onStartLoading() ");
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
}
Using forceLoad() is ok (not a bad practice). See what documentation says:
You generally should only call this when the loader is started - that is, isStarted() returns true.
I was still having the problem that loading of data was not called. I finally removed the AsyncTaskLoader (the support library version) and used only AsyncTask (not from support library) to do the job. And it worked.
It could be enough for your needs too.
Description and example: http://developer.android.com/reference/android/os/AsyncTask.html.
You have to extend the class AsyncTask.
The method doInBackground will do the work and in the method onPostExecute you will get the result. For starting the AsyncTask, you will call the method execute on its instance. See the link.