Using LoaderCallbacks without Fragment
Asked Answered
E

1

6

I am doing some hands-on reading on AsyncTaskLoader so I can use the technique to load the contact list. The only time the code works is when I implement the callbacks from a class that extends Fragment as in MyLoader extends Fragment implements LoaderCallbacks<ArrayList<Contact>>. Is there another way? All I really need is the contact list (name, phone, thumbnail), to send to my backend. When, for example, I try to use Context, since I can get that from any activity by simply doing (Context)this, the code fails to even compile. By context I mean

context.getLoaderManager().initLoader(1, null, this);
//I already changed to Fragment so don't really remember the exact ".context" line.
//But someone who has done this will understand the snippet.

BTW: I am using multiple references. One is http://developer.android.com/reference/android/content/AsyncTaskLoader.html.

QUESTION (again): Can I use AsyncTaskLoader without Fragment or FragmentActivity?

THE CODE THAT WORKS WITH THE FRAGMENT:

package com.example.contactpreload.utils;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;

public class LoadingContacts extends Fragment implements LoaderCallbacks<ArrayList<Contact>> {
    ArrayList<Contact> loadedContacts;
    static Fragment fragmentActivity;

    public static LoadingContacts newInstance(int arg) {

        LoadingContacts f = new LoadingContacts();
        Bundle bundle = new Bundle();
        bundle.putInt("index", arg);
        f.setArguments(bundle);
        fragmentActivity = new Fragment();
        return f;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.out.println("onCreate()");
        int mIndex = getArguments().getInt("index");
        System.out.println(mIndex);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        System.out.println("onActivityCreated()");
        getLoaderManager().initLoader(1, null, this);
    }

    @Override
    public Loader<ArrayList<Contact>> onCreateLoader(int arg0, Bundle arg1) {

        System.out.println("onCreateLoader()");
        return new ContactsLoader(getActivity());
    }

    @Override
    public void onLoadFinished(Loader<ArrayList<Contact>> loader, ArrayList<Contact> data) {
        loadedContacts = data;
        System.out.println("AND THE CONTACTS ARE: ");
        for (Contact c : loadedContacts) {
            System.out.println("NAME: " + c.getName());
            System.out.println("getPhoneNumberHome: " + c.getPhoneNumber());
        }

    }

    @Override
    public void onLoaderReset(Loader<ArrayList<Contact>> arg0) {
        System.out.println("onLoaderReset()");
        // TODO Auto-generated method stub

    }

}



package com.example.contactpreload;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;

import com.example.contactpreload.utils.LoadingContacts;

public class MainActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LoadingContacts fragment = LoadingContacts.newInstance(1);
        fragment.setRetainInstance(true);
        getSupportFragmentManager().beginTransaction()
            .add(android.R.id.content, fragment).commit();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

MANIFEST:

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="16" />
Exciter answered 22/4, 2013 at 16:38 Comment(1)
@bossylobster, I have been trying to respond to this one, but I am not cracking it. Any input? How about your colleagues? What gets me is the level 8 api portion. It does indeed work with fragment but with nothing else apparently (ref the discussion below in wangyif2's response).Divaricate
T
7

AsyncTaskLoader has nothing to do with whether you are using a Fragment or an Activity.

To give you an example, consider a list activity:

public class ExampleActivity extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor> {

     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.todo_list);

         //to start the loader:
         getLoaderManager().initLoader(0, null, this);
     }

     //override the loader callback methods as usual
     // Creates a new loader after the initLoader () call
     @Override
     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
         CursorLoader cursorLoader = new CursorLoader(this,
         uri, projection, null, null, null);
         return cursorLoader;
     }

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

     @Override
     public void onLoaderReset(Loader<Cursor> loader) {
         // data is not available anymore, delete reference
         adapter.swapCursor(null);
     }
}

Obviously you need to create corresponding adapter for the list view and layout, but the example just shows you how a simple loader for cursor would work for an Activity.

Also, make sure all your import are consistent, either using the support.v4 library, or the regular library:

import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;

Another question that is asked, is that if the LoaderCallback interface can be used standalone. This is not recommended if you consider that the LoaderCallback is for.

The LoaderManager.LoaderCallbacks<D> interface is a simple contract that the LoaderManager uses to report data back to the client. What that means, is its only job is to load some data in the background requested by a client, which is effectively, an activity.

If you create a standalone class, you could extend the class definition to implement LoaderManager.LoaderCallbacks<D>, but you will need to report the loaded data back to the original activity through some kind of mechanism, which would complicated a simple task.

Now if you are really fixed on doing this, you could create your standalone class as so:

public class LoadingContacts implements LoaderManager.LoaderCallbacks<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    return null;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
}

In your onLoadFinished method, you will need to send the loaded Cursor back through either a broadcast, or some kind of message bus:

  • LocalBroadcastManager
  • Otto
  • Messenger

After you send this information to the MainActivity, you can load it to the adapter and continue as is.

Trapeziform answered 22/4, 2013 at 17:25 Comment(8)
Many thanks for your reply: +1. I have now added the code that works with the Fragment and FragmentActivity. Do you mind editing it into your answer to show how it would work if LoadingContacts had no parent activity (e.g. Fragment) and MainActivity had not extended FragmentActivity?Exciter
Let me understand you question, you want a MainActivity to extend Activity and LoadingContacts to be purely a loader, not an Activity or Fragment?Trapeziform
I have updated the answer, please check if your question is answered.Trapeziform
I decided to use your example, but it's complaining that getLoaderManager().initLoader(0, null, this); should have a min API 11 not 8. Changing from ListActivity to Activity made no difference. Does it compile on your system with min api 8?Exciter
Referring to the android documentation, Loader was introduced in API 11, and before that API level, ManagedCursor was used. developer.android.com/reference/android/content/Loader.htmlTrapeziform
Great link by the way (ref androiddesignpatterns). Concerning the API 11 comment: that's true. But how come the code works when using Frame and FrameActivity?Guitarfish
It is possible that you are using Loader from the support.v4 library, which has denpendency on externally referenced JAR rather than API level. developer.android.com/reference/android/support/v4/content/…Trapeziform
@Trapeziform do we need to use asynctaskloader for parsing data from webservice and displaying it in listview? Or the normal asynctask will do...Sabra

© 2022 - 2024 — McMap. All rights reserved.