Grokking Android

Getting Down to the Nitty Gritty of Android Development

How to Use Loaders in Android

By 59 Comments

With the introduction of Honeycomb Loaders became the preferred way to access data of databases or content providers. They load data asynchronously and notify listeners when the results are ready.

Google did not only introduce Loaders but also deprecated the previous way to handle a Cursor within your activities. You shouldn’t use startManagingCursor() or managedQuery() in your projects anymore.

With managed cursors queries and requeries are executed on the UI thread. This could cause the app to feel unresponsive or to even display an ANR error message. With Loaders your queries will no longer run on the UI thread and your app remains responsive.

In this post I introduce the classes that form the Loader API and show you how to use them.

The classes and interfaces of the Loader API
Class Usage
LoaderManager Manages your Loaders for you. Responsible for dealing with the Activity or Fragment lifecycle
LoaderManager.LoaderCallbacks A callback interface you must implement
Loader The base class for all Loaders
AsyncTaskLoader An implementation that uses an AsyncTask to do its work
CursorLoader A subclass of AsyncTaskLoader for accessing ContentProvider data

In the following sections I describe most of these classes and what you need to know about them – starting with the LoaderManager.

LoaderManager

This class keeps your Loaders in line with the lifecycle of your activities or fragments. If Android destroys your fragments or activities, the LoaderManager notifies the managed loaders to free up their resources. The LoaderManager is also responsible for retaining your data on configuration changes like a change of orientation and it calls the relevant callback methods when the data changes. In short: The LoaderManager is way more powerful than the old startManagingCursor() or managedQuery() methods.

You do not instantiate the LoaderManager yourself. Instead you simply call getLoaderManager() from within your activity or your fragment to get hold of it.

Most often you are only interested in two methods of the manager:

initLoader()

The initLoader() method adds a Loader to the LoaderManager:


getLoaderManager().initLoader(LIST_ID, null, this);

It takes three arguments:

You might need the ID for further method calls. So using a final static field for the ID makes your code more readable. The Bundle can be used to pass additional arguments to your Loader, but isn’t used by the CursorLoader. The third argument, the callback interface, will be covered in detail later on.

The initLoader() method creates a new Loader only if for this ID none has been created previously. Keep in mind that Android deals with configuration changes for you, thus a simple change in orientation is enough to trigger a new call to initLoader(). In this case the method returns the existing instance and your query is not executed again.

restartLoader()

Because Android doesn’t execute the query again, you need a way to re-initialize the Loader when data, that is used to build the query, changes. Typical examples are search queries.

You reset your Loader by using the restartLoader() method. It takes the same parameters as initLoader(). Of course you have to use the same ID you used for initializing.


getLoaderManager().restartLoader(LIST_ID, null, this);

LoaderManager.LoaderCallbacks

The interface LoaderCallbacks defines methods you must implement to create your Loader, to deal with the results and to clean up resources.

Since the interface is parameterized you must specify the type of data your Loader holds. Most often the type will be Cursor:


public class YourFragment extends Fragment
implements LoaderCallbacks<Cursor> {
//…
}

The methods you have to implement are:

In the next sections I show what to do in each of these callback methods.

onCreateLoader()

The LoaderManager calls this method when you call initLoader() for the first time. As mentioned, the manager only calls this method if no loader for the given ID exists.

The method gets an int value and a Bundle passed in. These are the same values you used for your initLoader() call.

A typical example creating a CursorLoader looks like this:


public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader loader = new CursorLoader(
this.getActivity(),
SOME_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder);
return loader;
}

As you can see the parameters are a Context object plus those of the ContentResolver’s query() method. If you’re not familiar with these arguments, I recommend you read my post about accessing content providers.

If you need to track multiple queries and thus use different IDs for your Loaders, all you need to add is a simple case- or if-else-branch.

onLoadFinished()

This method is the most interesting one. Here you update the UI based on the results of your query.

For ListAdapters you simply swap the cursor of the adapter as described in the section “Changes needed for CursorAdapters“.

For all other cases you have to get references to the view elements and set their value according to the result.

This is how it looks in the sample project:


public void onLoadFinished(
Loader<Cursor> loader,
Cursor cursor) {
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
int idIndex =
cursor.getColumnIndex(LentItems._ID);
int nameIndex =
cursor.getColumnIndex(LentItems.NAME);
int borrowerIndex =
cursor.getColumnIndex(LentItems.BORROWER);
this.itemId = cursor.getLong(idIndex);
String name = cursor.getString(nameIndex);
String borrower = cursor.getString(borrowerIndex);
((EditText)findViewById(R.id.name)).
setText(name);
((EditText)findViewById(R.id.person)).
setText(borrower);
}
}

onLoadReset()

This method allows you to release any resources you hold, so that the Loader can free them. You can set any references to the cursor object you hold to null.
But do not close the cursor – the Loader does this for you.

See also the section about how to deal with CursorAdapters.

Loader, AsyncTaskLoader and CursorLoader

The Loader interface and its implementations are not very interesting – unless you write your own custom Loaders. You have to create a Loader of course. But other than using the constructor of CursorLoader, you normally do not interact with these objects yourself.

If you use multiple Loaders you need to access the ID in the callback methods. You can do so by calling getId() on the loader passed in to the callbacks.

If you want to write a custom Loader yourself, please have a look at Alex Lockwood’s tutorial on implementing loaders.

Changes needed for CursorAdapters

An important use of cursors in Android is to use a CursorAdapter as data source for ListViews, AutoCompleteTextViews and so on. When working with Loaders you have to adapt the old way slightly.

First of all: You do not have a Cursor object before the onLoadFinished() method of your callback has been called. In other words: The cursor is not ready when you create the adapter. Thus you create the adapter using null for the cursor argument:


SimpleCursorAdapter adapter =
new SimpleCursorAdapter(
getApplicationContext(),
android.R.layout.simple_list_item_1,
null,
columns,
layoutIds,
0);

When the cursor is finally available you have to add it. You do this by calling swapCursor() on your adapter and passing in the cursor object of your callback method:


public void onLoadFinished(
Loader<Cursor> loader,
Cursor cursor) {
((SimpleCursorAdapter)this.getListAdapter()).
swapCursor(cursor);
}

And to clean up resources in the onLoadReset() method you also use swapCursor(), this time passing in a null value:


public void onLoaderReset(Loader<Cursor> loader) {
((SimpleCursorAdapter)this.getListAdapter()).
swapCursor(null);
}

Use the Support Library for older Android versions

To support newer features on older Android versions, Google provides the Support Library. The two main components this library contains are Fragments and Loaders.

You can and should use this library for projects that must support older versions. All reasons for using the Loader-API are valid for pre-Honeycomb devices as well.

But you have to keep an eye on the import statements. All import statements for classes of the Support Library begin with android.support.v4:


import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;

Don’t mix classes of the support library with normal classes. The compiler will spot most problems for you and then there is also Lint to help you. But if you ever wonder why some code is marked as invalid, this most likely is the reason.

To use Loaders for older Android versions, you need to use activities or fragments of the Support Library. The normal ones do not have the getLoaderManager() method before Honeycomb. You project would still compile (if your build target is at least SDK 11) but at runtime you would get a NoSuchMethodError on older devices.

Using Loaders to access your SQLiteDatabase

Since Android’s CursorLoader is only for Cursors returned by content providers we need another Loader implementation if we want to use SQLite directly.

Thankfully Mark Murphy has written a library that offers enhancements to the Loader framework. This library also contains a SQLiteCursorLoader.

To use Mark Murphy’s SQLiteCursorLoader you have to create an SQL select statement and pass it to the constructor.The constructor also expects an SQLiteOpenHelper object. An example of the onCreateLoader() method could look like this:


public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String rawQuery = "SELECT …";
String[] queryParams = // to substitute placeholders
SQLiteCursorLoader loader =
new SQLiteCursorLoader(
getActivity().getApplicationContext(),
yourSqliteOpenHelper,
rawQuery,
queryParams);
return loader;
}

But there is more to it. You have to use this loader also for deleting, updating or inserting rows as well. Only by doing so, the loader knows about a data change and can call the correct callback methods.

I won’t go into these details here. See the project’s github page or have a look at Mark Murphy’s sample project.

If you intend to use this library, don’t use the jar-file offered on the project page. It is outdated. Instead clone the git repository and add the project to your IDE directly.

When not to use Loaders

On reddit, cokacokacoh noted that my post missed a section on when not to use Loaders. He was right of course. So I added the following paragraph to this post.

As cokacokacoh points out, you shouldn’t use Loaders if you need the background tasks to complete. Android destroys Loaders together with the Activities/Fragments they belong to. If you want to do some tasks, that have to run until completion, do not use Loaders. You should use services for this kind of stuff instead.

Keep in mind that Loaders are special components to help you create responsive UIs and to asynchronously load data that this UI component needs. That’s the reason why Loaders are tied to the lifecycle of their creating components. Do not try to abuse them for anything else!

Lessons learned

In this blog post you have seen how to use the Loader framework. And since this framework is available for older Android versions using the Support Library there is no reason not to use it.

The CursorLoader provided by Android is useful for content providers. But not all projects use these. If your project uses SQLite directly you can use Mark Murphys SQLiteCursorLoader as shown above.

I didn’t cover how to write Loaders on your own. If you need to do so, +Alex Lockwood has a nice tutorial on implementing loaders.

Please let me know in the comments if this post was helpful or if you have any questions left. And don’t forget to plus one or tweet this post, if you liked it 🙂

Wolfram Rittmeyer lives in Germany and has been developing with Java for many years.

In recent years he shifted his attention to Android and blogs about anything interesting that came up while developing for Android.

You can find him on Google+ and Twitter.

59 thoughts on “How to Use Loaders in Android”

  1. Great post! BTW, I think it’s worth clarifying that Mark Murphy’s SQLiteCursorLoader is a bit different from the Android SDK CursorLoader in that there is no global notification system in place to notify the Loader when changes are made to the underlying SQLiteDatabase. That is, with a CursorLoader you can use the ContentResolver to modify the underlying data source from wherever you want and you can trust that the CursorLoader will be notify about these changes. The same cannot be said about the SQLiteCursorLoader… all modifications to the SQLiteDatabase *must* be followed by a call to the loader’s “onContentChanged()” method, which will notify the Loader to reload its data. IIRC, the LoaderEx project includes a few AsyncTasks that you can use to perform asynchronous insertions/updates/deletions to the SQLiteDatabase, each of which are followed by a call to “onContentChanged()”.

    I guess it’s not that big of a deal, but this is one of the reasons why I prefer using ContentProviders. 🙂

    1. Alex, you can use the insert/delete/update methods of SQLiteCursorLoader to achieve this. But, yes, that’s way more cumbersome than using a content provider directly.

  2. My content provider has the notifyUriChange() and related stuffs.
    I noticed that onLoadFinished() gets called when the data gets changed. Is restartLoader() called automatically?

    The problem is I find the need to handle onLoadFinished() differently when it’s from restartLoader(). Is there a way to do this?

    1. The onLoaderFinished() method gets called by the LoaderManager directly without the use of restartLoader(). That’s triggered by the ContentObserver used within CursorLoader.

      Is that what you were hoping for? And why would you want to treat the loading differently depending on which of the initLoader() vs. restartLoader() methods caused it?

  3. Very Nice Tutorial!! Clear and Concise !!

    1. Thanks, Vipul. I’m glad that you liked it!

  4. Hi Wolfram, first of all thanks for tutorials & Google+ shares

    From what I’ve understood about Loaders, regarding DB access their only purpose is to Read, as we can’t be sure that an Insert, Update or Delete will take place. Services are the way to go for must-happen operations.

    If I’m right about this, why does Mark Murphy’s ‘loaderex’ project mention the possibility of using Insert, delete or update with his SQLiteCursorLoader? I know you are not the developer, but since you recommend the library maybe you can shed light on this topic.

    On a more abstract approach, in the past I’ve used DAOs accessing the DB directly and DAOs accessing DB through ContentProviders, but right now I’m quite confused with all the options available. To your understanding, what’s the best DB architecture?

    In a new project I don’t need to share data with other applications, so I’m considering using Services + DAOs with direct access to DB through a synchronized singleton, and Loaders for reading that data.

    Sorry for long post, needed to put my doubts on paper, no one near experienced enough to ask 🙁

    1. About LoaderEx: See the Activity ConstantsBrowserACL from his sample project. While the Loader is initially used as usual (for querying data) you can later on use the same loader to delete or add data. And you get automatic reloading with this.

      I personally wouldn’t use ContentProvider until I have to. I have to when I either want to be notified about changes in the underlying data or when I want to export data. Notifying myself about changes is much easier with CP because they are specifically designed to do so and thus you do not need too much code. If you export data, think about possible joins people might want to use!

      About DAOs: Fine. But don’t do them yourself. Use GreenDAO, ormlight or StORM.

  5. Hello Wolfram, very well-informed post and got a fine knowledge about Cursor Loader. I’ve already gone through many posts and blog but after reading your post only I became comfortable with Loaders. I’ve to use it in my project, so thanks.

  6. of much help, thanks

  7. Thank you for the valueable article. Do you know of a implementation or article which concentrates on the special requirements of a map view such as for Google Maps on Android?

    1. With regards to Loaders? I don’t know of any special posts/articles about the combination of Loaders and a MapView. Well, I think, I didn’t understand your question. Can you expand a bit more on what you want/need?

  8. Hello,
    Is there a use case for calling destroy loader().

    Thanks,
    Igor

    1. Well, rarely 🙂

      If you need to de-couple your loader lifecycle from the component lifecycle is one use case. For example if – once the Loader has finished – you want to display the result but do not want it to reload with the next config change.

      Or if you either need to pass in a different Bundle or a different LoaderCallbacks when restarting a loader. In this case you would call destroyLoader() first and initLoader() with the changed arguments afterwards. A call to restartLoader() wouldn’t work in that case.

  9. Some great tutorials on your site, but for some reason every time I visit this page it resets my router!

  10. hi, i have gone through your tutorial an it was helpfull to me but i have one doubt what is difference between content reolver and loader both are used for accessing content providers then what is difference between them where exactly we can use this two?

    1. Wolfram Rittmeyer

      A Loader is a helper to asynchronously access a data provider. The data source could be anything – but very often is a ContentProvider. The Loader keeps track of the state the data is in and reloads data whenever the content has changed.

      A ContentResolver on the other hand works only with ContentProviders. It doesn’t load anything and it doesn’t reload anything. It just get’s notified whenever the data within the content provider has changed.

      The CursorLoader, a concrete Loader implementation provided by the framework, relies on ContentObservers to get notifications of any change in the underlying data. For any other data provider you would have to create something comparable as well to enable Loaders to be as powerful with that data provider.

      So the ContentObserver is what makes the CursorLoader so powerful.

      1. Thanks for the replay .now i understand it let me implement it and check

  11. hi..

    I want to refresh system time to be updated on screen without any button-clicks.plz help me how to do it?

    1. Wolfram Rittmeyer

      Could you please explain this a bit more. What do you mean by “refresh system time”? What has it to do with loaders? What intervals (if any)? And so on.

  12. Hello Wolfram,
    I work with CursorLoader with my custom CursorAdapter and pass a null Cursor to constructor as you made with SimpleCursorAdapter, how you explained so good.
    My Problem is that I can save data in my SQLiteDatabase but ListView is not populated and I tried with

    // dataAdapter is my Custom CursorAdapter
    dataAdapter.notifyDataSetChanged();
    listView.SetAdapter(dataAdapter);

    in the last line of onLoadFinished but I can’t see yet data in ListView.

    Kind Regards

    1. Hi Wolfram, that was my error, I knew where I had to notify and set the ListView with the adapter, precise in “onLoadFinished” but I did it below “adapter.swap(cursor)” Line and we must to do it above.

      Good WebSite.

      Grüße aus Niederbayern

  13. Hello, i wrote my own content provider, implemented CursorLoader on my main activity. I have list of items on main screen and i get them through ContentResolver . But when i call update on any item using COntentResolver it is toooo slow. I couldnt figure it out why. I’ll be happy if you can help me with this. Please take a look at codes here: http://p2p.wrox.com/book-professional-android-4-application-development/93177-content-provider-loadermanager.html

    1. Wolfram Rittmeyer

      What exactly is too slow? Your content provider? The time until your callback is called? The swapCursor() execution time? What time measurement are we speaking about? And how does the slowness manifest itself?

      Two things about your code:

      1.) You are calling the update() method on the main thread. You shouldn’t do that – depending on the device, the load the device is suffering from and so on, this might cause perceived lag – or even worse an ANR.

      2.) You are calling notifyDatasetChanged() on your OnClickListener but swap the Cursor with your Loader. swapCursor() is sufficient.

      1. As you have seen the app screen, when i click plus button again and again (maybe 2 clicks per second) the count increases slow, that’s my problem.In old version, when using startManagingCursor() there wasnt lack when i click Plus or Minus button. Is there any error you have noticed in contentProvider or LoaderManger so far?

      2. Not loaderManger sorry, Is there any error you have noticed in contentProvider or CursorLoader so far?

  14. JC, I have copy & pasted of API Reference
    http://developer.android.com/reference/android/app/Activity.html#startManagingCursor(android.database.Cursor)
    “void startManagingCursor(Cursor c)
    This method was deprecated in API level 11. Use the new CursorLoader class with LoaderManager instead; this is also available on older platforms through the Android compatibility package.”

    If you use CursorLoader, you need no more AsyncTask Class, so that CursorLoader is an extension of AsyncTaskLoader, as you can see in this web page.
    To better comprehesion take a look at http://www.mysamplecode.com/2012/11/android-database-content-provider.html

    You can see when and how CursorLoader works and when you are able to write Cursor-Provider Queries(*). Please modularize, you should have i.E. the initialization-Load in your main activity and in a second activity
    you can do (*) something
    Cursor = getContentResolver().query(uri, projection, null, null, null);

    1. Cursor = getContentResolver().query(uri, projection, null, null, null);

      By using this i can get row of data from database, and iterate it over cursor, use it..

      But i dont want to get data and display it, i want to insert and update data . so i used getContentResolver().update(…) which is slow, i didnt understand the reason.

      Also i use contentProvider, so that other applications can access my database, also do CRUD operations.

  15. Hi Wolfram

    I am using cursorLoader in my project, Whenever there is a insertion to the database the list is automatically updating and list is scrolled to top position.

    My point is how to stop to scroll the list to top when I am in the bottom of the list even there is a insertion to the database.

    Note: But the content should be update. Can you please help on this using CursorLoader.

    Thanks

    1. Hi, have you such a line? “listView.setSelection(0)”?
      It seems, that you have write such a code line in your Methode where you update

  16. thanks for the awesome information 🙂
    i have one question..
    does loader have utility for automatic, partial load data(like data from dabatabase using limit offset)

    1. No. Loaders do not support this out of the box.

      But if you are using your own content provider you could easily implement this behaviour with a specific URI. For example:

      content://yourauthority/items/from/a/to/z

      Where a is the offset value (e.g. 100) and z is the limit value (e.g. 50). Of course you would have to parse a tiny bit more, but that’s actually not that difficult.

      Only with existing providers you’re out of luck.

  17. Nice tutorial… can u please include SQLiteCursorLoader also in your post..

    1. Thanks shiv. I think Mark Murphy has a great sample app for his SQLiteCursorLoader that shows how to use it properly. Just clone the git, import it into your IDE and have a look around. I currently do not have enough time to expand on this tutorial.

      See also Alex Lockwood’s first comment to this post! SQLiteCursorLoader only works properly if you use the classes of the framework also to update, delete and insert queries. If you really need the full power of Loaders there’s no replacement for using ContentProviders.

  18. Great tutorial! thanks for sharing your knowledge!.

    Getting my head wrapped around Loaders has not been easy. I sill have this problem that bugs me more than It should:

    When a loader is in the RestState?

    And why do we do this (taken out of the documentation)

    @Override
    public void deliverResult(List apps) {
    if(isReset()){
    // An async query came in while the loader is stopped. We don’t need the result
    if(apps != null){
    onReleaseResources(apps);
    }
    }

    }

    Why do we checked if the loader isReset here?. What’s the loader lifecycle?

    Thanks 😀

    1. Which sample are you speaking about. Can you provide a link?

      The check isReset() is necessary because if the Loader is reset you do not have to deliver the result.

  19. Hi Wolfram,

    thank you to take so much care of the android community.
    I have many many manange cursor implemented and want to give full support on newer android versions.
    Much to do (incl. all the different data stati and multiple cursors I have in my code).
    Your tutorial gives great help
    Cheers Wayne

  20. giovanni poidomani

    when I need to write a custom Loader?

    1. Alex Lockwood has a good post about how to implement custom loaders. He also explains the benefits of Loaders in general at the top of it.

      I personally think Loaders only work if they are coming together with a complete API that also handles the change of data. Like Mark Murphy’s implementation of SQLite cursor loaders. It’s no wonder we see no other implementation in the framework than the one backed by content providers. Loaders shine in combination with content providers (though they are very tightly coupled to the UI layer, which is not without problems). Everywhere else you have to be very careful and thorough.

  21. This is a wonderful post and I´ve been reading a lot but few sources are so well explained.
    I was wondering if someone in this community could help me out with this error I´m getting from my app: I have two AutoCompleteTextViews in my Activitiy. Both are working perfectly well, but I cannot have them both working together because I get an error message on the method onLoadFinished. I am able to diferentiate on onCreateLoader using diferent ids for each adapter, but I don´t know how to proceed when it comes to onLoadFinished.
    I would really appreciate if you could give me an idea of what to do in this case.
    Thanks in advance.

    1. Not sure exactly about your specific problem. But you can get the id in question from the Loader object passed to your callback:

      loader.getId();

      This should be sufficient to trigger the respective updates on the correct adapter.

      If that’s not what you need to know, keep in mind that most often its better to ask questions like this on StackOverflow. Do not forget to add sufficient parts of your code to understand what you are doing and a complete logcat snippet to understand what is going wrong to your question. You are bound to get more and faster answers there. You can always leave a comment here linking to your SO question, if it’s relevant to the topic.

      1. You answered my question so fast that it seems you were waiting for it. Thank you for quick response. If I understood your hint on how to ask questions here in order to get faster responses, I decided to rephrase my question: This is how I different my adapters:

         
        @Override public Loader onCreateLoader(int id, Bundle args) { 
           final MyGlobalVariables globalVariables = (MyGlobalVariables) getApplicationContext(); 
           final int codigoEmpresa = globalVariables.getCodigoEmpresa(); 
           String[] projection; 
           String selection; 
           String sortBy; 
           CursorLoader cursorLoader; 
           switch (id) {
               case 0:
                   projection = new String[]{UsesalesContract.ClientesColumns.CLIENTES_ID,
                           UsesalesContract.ClientesColumns.CLIENTES_RAZAO_SOCIAL};
                   selection = UsesalesContract.ClientesColumns.CLIENTES_CODIGO_EMPRESA + " = " + codigoEmpresa;
                   sortBy = "_id DESC";
                   cursorLoader = new CursorLoader(this, UsesalesContract.URI_TABLE_CLIENTES, projection, selection, null, sortBy);
                   return cursorLoader;
               case 1:
                   projection = new String[]{UsesalesContract.FormasPagamentoColumns.FORMASPAGAMENTO_ID,
                           UsesalesContract.FormasPagamentoColumns.FORMASPAGAMENTO_DESCRICAO};
                   selection = UsesalesContract.FormasPagamentoColumns.FORMASPAGAMENTO_CODIGO_EMPRESA + " = " + codigoEmpresa;
                   sortBy = "_id DESC";
                   cursorLoader = new CursorLoader(this, UsesalesContract.URI_TABLE_FORMASPAGAMENTO, projection, selection, null, sortBy);
                   return cursorLoader;
               default:
                   throw new IllegalArgumentException("Unknow id" + id);
           }
        } 
        

        And this is where I get the error message:

        @Override public void onLoadFinished(Loader loader, Cursor data) {
           mAdapter.swapCursor(data); 
        }
        

        And you are telling me to use `loader.getId()`, and then I would change the method into:

        @Override public void onLoadFinished(Loader loader, Cursor data) { 
           switch(loader.getId) { 
           case 0: 
              mAdapter0.swapCursor(data); 
              break; 
           case 1:
              mAdapter1.swapCursor(data); break;
              } 
        

        And I already tested it and guess what? You saved my day!!! 🙂 Thank you very much indeed for your valuable help.

        1. Alas, any formatting gets lost on this blog when you use it in comments. That’s why yours now looks a bit odd. Sorry for that 🙂

          Anyway: Glad that I was of help!

          1. Thank you!

        2. Seems like unformatted spaghetti code. Hard to read. Please consider stripping out the non-essential parts.

          1. Looks better now!

  22. Nice tutorial. But don’t you think that in 2016 android devs should be using model-view-presenter architecture with RxJava, instead of Loaders? I am curious if Loaders with ContentProviders are still the preferred way to access a Sqlite db…

    1. I indeed think that most often MVP is the way to go. I also happen to use RxJava very much, but that’s not necessarily the only option.

      IMHO Loaders are only useful if you use content providers. But if you use content providers anyway – either because you use the built-in providers or because you want to share data across apps – they actually are still useful. A bit cumbersome in conjunction with MVP but nevertheless useful.

      1. Then how can a new dev make a sensible decision as to which approach/technology to use when working with Sqlite db? I mean there are so many options out there, they make your head spin. Even for a seasoned dev, much more so for a newbie.

        1. I have no definite answer. But I guess the best way in general is to follow the discussions among android devs (social media, blogs, communities or collections on G+ and so on) and after reading a fair bit of stuff deciding on your own.

          And if the first approach didn’t work out (or had some downsides), choose another based on this experience and on how the new approach tackles this specific problem you encountered.

          For me a mix of trying out stuff and reading about stuff – together with looking back at what went good and what not – helps me find better ways over time.

          All in all, I guess new devs have to find what works for them – unless they work with a great team and this team is willing to share the knowledge (which in my opinion is part of the definition of a great team).

          1. Yeah, this is the problem with Android development: there are always 10 ways to accomplish a specific task. And you will never know which way is best, off-hand. Developers have to spend inordinate quantities of time perusing Reddit, Google+ and StackOverflow just to get an idea of which approach may work better. And it may very well turn out to be the inferior approach in the long run.
            Try to explain this time suck to your boss, who expects you to have a piece of code done by the end of the day. Or try to explain to your teammates that MVP + RxJava is superior to LoaderManager. This game is not winnable.

          2. Yes, you are absolutely right. It takes time to get (and keep) familiar with all this stuff. And there’s always quite a lot of new stuff. But that’s not only that way for us Android devs. It’s the same on iOS (how to properly use all those new Swift constructs – then they also have Reactive Extensions and Realm and so on). And let’s not forget those poor web folks who have to cope with a new hype roughly every week 🙂

            On the other hand: I think that’s part of the fun of our job. Constantly learning (be it from others or from one’s own mistakes) and there’s always something new to grasp and conquer. All those nice successes when you grok yet another concept. We devs are constantly experiencing small successes – what other job can offer you that? Of course we also constantly struggle. But, well, that’s just to keep us on our toes. Honestly, I like it that way.

          3. Ah, I forget to comment on your second part: Of course, managers not getting this are a bummer. Most grievances come from managers not understanding development properly – or sometimes from clients, though they generally tend to be much better at this. Some are really gorgeous, some are better to be avoided and to be left behind.

  23. Glad someone feels my pain :). Lastly, I just want to add that LoaderManager’s source code hasn’t been updated in three years: https://android.googlesource.com/platform/frameworks/base/+blame/master/core/java/android/app/LoaderManager.java

    Meanwhile, multicore processing and app complexities have evolved exponentially, which effects the way we write apps. Therefore, one can safely assume that Google doesn’t give a shit about staying current with developer trends. So we are definitely better off following MVP and RxJava, as advocated by the open-source community for now.

  24. How can I know that a loader has a result, so that when I use loaderManager.getLoader(…), and see that there is a loader there, to check and even get its result ?

  25. Very nice and very detailed :). Blog posts like these are always worth the read and the bookmark. Thanks again for taking them time to put this together!!!

  26. Im a bit lost around the SimpleCursor adapter bit. In your snippet, its created, but i cant see a) which callback its being created in , b) where the ‘adapter’ object is ever used after creation and c) where the Cursor object is getting its data from.

    PS:Newbie here

  27. Very well described in simple way great post.

Leave a Reply

Your email address will not be published. Required fields are marked *

You can also subscribe without commenting.