dariusiv
dariusiv

Reputation: 105

onLoadFinished is never called

It seems that there is a bug in the Support library v4, I want to access the MediaStore Audio using CursorLoader and LoaderManager and I have followed the protocol to the T, and no matter what I do, OnLoaderFinished is not called.

Here are some code snippets, I created something I called MediaStoreInterface,

the relevant parts of MediaStoreInterface are as follows:

public class MediaStoreInterface extends Observable
{
protected Cursor cursor;
protected static final int LOADER_ID1 = 1;
protected static final int LOADER_ID2 = 2;
protected static int lastLoaderId = 0; 
protected static String function = "SONGS"; 
protected static PaudioActivity act;
protected static Sound selectedSound = null;
protected static final String[] projections = {MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.DATA};
protected static final String[] projectionsPlaylist = {MediaStore.Audio.Playlists._ID,MediaStore.Audio.Playlists.NAME};
protected static final Uri sourceUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
protected static final Uri uriPlaylists = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
protected static ArrayList<String> ret;
protected static boolean done = false;
//Singleton 

protected static MediaStoreInterface ref = null;


public static MediaStoreInterface getMusicLibrary(Activity act_)
{
    if (ref == null)
        ref = new MediaStoreInterface(act_);

    return ref;     
}

protected MediaStoreInterface(Activity act_)
{
    act = (PaudioActivity) act_;        
}
public static MediaStoreInterface getMSI() 
{
    if (android.os.Build.VERSION.SDK_INT < 11)
        return MediaStoreInterfaceFrodo.getMusicLibrary(act);
    else
        return MediaStoreInterfaceHoneyComb.getMusicLibrary(act);
}



protected void loadArray(Cursor data) 
{
    int num = data.getColumnCount();
    if (data == null || !data.moveToFirst())
        return;
    while(!data.isLast())
    {
        String s  = data.getString(0);
        int col = 1;
        while(col < num)
            s += "|" + data.getString(col++);
        ret.add(s);
        data.moveToNext();          
    }

    if (function == "SONGS")
        numSongs = ret.size();
    if (function == "PLAYLISTS")
        numPlaylists = ret.size();
    cursor = data;  
}
public static void setDone() 
{
   done = true;     
}



}

It's a Singleton, that is supposed to return the right MediaStoreInterface for each API, I extend Frodo from this, as follows:

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.content.Loader.OnLoadCompleteListener;






    public class MediaStoreInterfaceFrodo extends MediaStoreInterface implements LoaderManager.LoaderCallbacks<Cursor>, OnLoadCompleteListener<Cursor>
    {

        public static MediaStoreInterface getMusicLibrary(Activity act_)
        {
            if (ref == null)
                ref = new MediaStoreInterfaceFrodo(act_);

            return ref;     
        }

        public void setPaudioActivity(PaudioActivity act_)
        {
            act = act_;
        }

        protected MediaStoreInterfaceFrodo(Activity act_) 
        {
            super(act_);
        }

        public ArrayList<String> getSongList() 
        {
            function = "SONGS";
            done = false; 
            if (ret == null)
                ret = new ArrayList<String>();
            else
                ret.clear();
            lastLoaderId = LOADER_ID1;
            LoaderManager lm = act.getSupportLoaderManager(); 
            Loader<Cursor> loader1 = lm.getLoader(LOADER_ID1);
            if (loader1 != null && loader1.isReset())
                loader1 = lm.restartLoader(LOADER_ID1, null, this);
            else
            {
                loader1 = lm.initLoader(LOADER_ID1, null, this);    
            }

            while(!done)
            {
                waitabit();
            }

            return ret; 
        }

        public static void editSelectedSongTitle(String newtitle) 
        {
            // TODO Auto-generated method stub      
        }



        public static void setContinuePlayMode(PlayMode pm_) 
        {
            pm = pm_;       
        }

        public List<String> getPlayListNames() 
        {
            function = "PLAYLISTS";
            done = false; 
            if (ret == null)
                ret = new ArrayList<String>();
            else
                ret.clear();
            lastLoaderId = LOADER_ID2;
            LoaderManager lm = act.getSupportLoaderManager(); 
            lm.initLoader(LOADER_ID2, null,  this);

            while(!done)
            {
                waitabit();
            }

            function = "SONGS";

            return ret;

        }





        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle arg1) 
        {
            CursorLoader cursorLoader = null;

            switch (id) 
            {
            case LOADER_ID1:
                cursorLoader = new CursorLoader(act, sourceUri, projections, null, null, MediaStore.Audio.Media.TITLE); 
                break;
            case LOADER_ID2:
                cursorLoader = new CursorLoader(act, uriPlaylists, projectionsPlaylist, null, null,  MediaStore.Audio.Playlists.NAME);
                break;
            default:
                break;
            }
            cursorLoader.forceLoad();
            return cursorLoader;

        }

        @Override
        public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) 
        {
            cursor = data;
            loadArray(cursor);
            done = true;

        }

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

            act.getSupportLoaderManager().restartLoader(lastLoaderId, null,  ( android.support.v4.app.LoaderManager.LoaderCallbacks<Cursor>) this);

        }

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

        }




    }

I have tried to separate the database query from the usual nukes and crannies of my activity, long story short I have a button that if one clicks, getSongList is called, I also have setActivity to turn the act member into the calling Activity,

I have read ALL relevant StackOverflow articles and everything on android development site. Some of you might object that I have to call some of my functions on the UI thread, I have done that too, to no avail. I have implemented the same set of code, in my main Activity, but still no matter what I do. OnLoadFinished is never called.

Upvotes: 0

Views: 3162

Answers (2)

Suau
Suau

Reputation: 4738

I'm unsure what is causing the problem, as your code is incomplete, however your imports imply you might not use the activity from the support package:

import android.app.Activity;

should be

import android.support.v4.app.FragmentActivity;

i actually don't see how your code could even compile, as the non-support-activity doesn't have a method called getSupportLoaderManager()

without knowing what the actual problem is, i'll post a sample i just created, i boiled down the code to what is actually necessary. Note however that you don't have to implement the LoaderCallback in an activity. This code is working, as i tested it.

package com.suhw.samples.mediastore;

import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.Log;

public class QueryMediaStoreActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> {
    private final static String TAG = "QueryMediaStoreActivity";
    private static final int LOADER_ID1 = 1;
    private static final String[] audioMediaProjection = {MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.DATA};
    private static final Uri audioMediaUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        LoaderManager loaderManager = getSupportLoaderManager();
        loaderManager.initLoader(LOADER_ID1, null, this);
    }


    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
        switch (id) {
            case LOADER_ID1:
                return new CursorLoader(this, audioMediaUri, audioMediaProjection, null, null, MediaStore.Audio.Media.TITLE);
            default:
                return null;
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        switch (cursorLoader.getId()) {
            case LOADER_ID1:
                Log.d(TAG, "onLoadFinished called:\n\tcursorCount:" + cursor.getCount());
                break;
        }
    }

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

Upvotes: 3

Amit Gupta
Amit Gupta

Reputation: 8939

Change your OncreateLoader(), If dealing with multiple Loader then better use switch() statement.

@Override
    public Loader<Cursor> onCreateLoader(int id, Bundle arg1) 
    {
        CursorLoader cursorLoader = null;

        switch (id) {
        case LOADER_ID1:
            cursorLoader = new CursorLoader(getActivity(), sourceUri, projections, null, null, MediaStore.Audio.Media.TITLE); 
            break;
        case LOADER_ID2:
            cursorLoader = new CursorLoader(getActivity(), uriPlaylists, projectionsPlaylist, null, null,  MediaStore.Audio.Playlists.NAME);
            break;
        default:
            break;
        }
        cursorLoader.forceLoad();
        return cursorLoader;

    }

Edit:-

Use getActivity() instead of act for details CursorLoader

Note:- The method getLoaderManager() is only available in the Fragment class. To get a LoaderManager in a FragmentActivity, call getSupportLoaderManager().

Try like this.

Upvotes: 1

Related Questions