android loader源码分析之一:整体交互流程

activity或者fragment通过loadermanager控制loader
loader的子类去执行相关操作

一. Loader源码分析

 
package android.content;

import android.database.ContentObserver;
import android.os.Handler;
import android.util.DebugUtils;

import java.io.FileDescriptor;
import java.io.PrintWriter;

/**
 * 该类并没有做任何实质性的操作,只做了以下几件事情
 * 一是提供一系列生命周期方法,start,cancel,stop,reset等
 * 并将真正的操作用onStart,onCancel,onStop等形式以模板的形式提供出来由子类去实现
 * 二是:提供回调接口,数据加载完成,加载取消的回调接口以及接口的注册和注销
 * A class that performs asynchronous loading of data. While Loaders are active
 * they should monitor the source of their data and deliver new results when the
 * contents change.   
 */
public class Loader {
    int mId;
    OnLoadCompleteListener mListener;
    OnLoadCanceledListener mOnLoadCanceledListener;
    Context mContext;
    boolean mStarted = false;
    boolean mAbandoned = false;
    boolean mReset = true;
    boolean mContentChanged = false;
    boolean mProcessingChange = false;

    /**
     * 内容观察者,在数据发生变化的时候调用onContentChanged(),
     * onContentChanged()方法根据started标志位来决定是执行forceLoad还是将mCotentChanged设true
     */
    public final class ForceLoadContentObserver extends ContentObserver {
        public ForceLoadContentObserver() {
            super(new Handler());
        } 
        @Override
        public boolean deliverSelfNotifications() {
            return true;
        } 
        @Override
        public void onChange(boolean selfChange) { 
            onContentChanged();
        }
    }

    /**
     * loader加载完数据时使用的回调接口 
     */
    public interface OnLoadCompleteListener { 
        public void onLoadComplete(Loader loader, D data);
    }

    /**
     * loader取消使用的回调接口 
     */
    public interface OnLoadCanceledListener { 
        public void onLoadCanceled(Loader loader);
    }

    //无论传递的context是什么都会转化成ApplicationContext 
    public Loader(Context context) {
        mContext = context.getApplicationContext();
    }

    /**
     * 调用deliverResult执行listener的onLoadComplete回调方法
     * 把loader加载的数据用mListener传递出去 
     */
    public void deliverResult(D data) {
        if (mListener != null) {
            mListener.onLoadComplete(this, data);
        }
    }

    /**
     * 调用此方法告知mOnLoadCanceledListener,loader已经cancel
     */
    public void deliverCancellation() {
        if (mOnLoadCanceledListener != null) {
            mOnLoadCanceledListener.onLoadCanceled(this);
        }
    }

     


    /**
     * 注册回调 ,也就是给OnLoadCompleteListener mListener赋值
     */
    public void registerListener(int id, OnLoadCompleteListener listener) {
        if (mListener != null) {
            throw new IllegalStateException("There is already a listener registered");
        }
        mListener = listener;
        mId = id;
    }

    /**
     * 注销OnLoadCompleteListener mListener,也就是将它置为空
     * Remove a listener that was previously added with  
     * Must be called from the process's main thread.
     */
    public void unregisterListener(OnLoadCompleteListener listener) {
        if (mListener == null) {
            throw new IllegalStateException("No listener register");
        }
        if (mListener != listener) {
            throw new IllegalArgumentException("Attempting to unregister the wrong listener");
        }
        mListener = null;
    }

    /**
     *  同上
     */
    public void registerOnLoadCanceledListener(
            OnLoadCanceledListener listener) {
        if (mOnLoadCanceledListener != null) {
            throw new IllegalStateException(
                    "There is already a listener registered");
        }
        mOnLoadCanceledListener = listener;
    }

    /**
     *  同上
     */
    public void unregisterOnLoadCanceledListener(
            OnLoadCanceledListener listener) {
        if (mOnLoadCanceledListener == null) {
            throw new IllegalStateException("No listener register");
        }
        if (mOnLoadCanceledListener != listener) {
            throw new IllegalArgumentException(
                    "Attempting to unregister the wrong listener");
        }
        mOnLoadCanceledListener = null;
    }



    /**
     * 该方法会由LoaderManager自动执行,在使用loadermanager的时候就不要自己再去执行该方法
     * 改变标志位,并执行 onStartLoading方法,所以onStartLoading方法是在loadermanager调用
     * startLoading之后被执行的
     */
    public final void startLoading() {
        mStarted = true;//mStarted为true
        mReset = false;
        mAbandoned = false;
        onStartLoading();
    }

    /**
     * 子类需要实现这个方法去加载自己的数据,这个方法是在startLoading中被调用的,不由客户端自己调用
     */
    protected void onStartLoading() {
        
    }

    /**
     * Attempt to cancel the current load task. Must be called on the main
     * thread of the process.
     * 尝试取消一个loader操作,取消不是一个立刻会执行的操作,应为load是在子线程中执行
     * 如果task不能被cancel或者startLoading还没被调用的话返回false
     * 否则返回true,当返回true的时候,任务还在执行并指任务完成的时候OnLoadCanceledListener会被调用 
     */
    public boolean cancelLoad() {
        return onCancelLoad();
    }

    /** 
     * 这里是一个默认实现
     * 子类需要实现这个方法
     * 如果任务已经完成或者任务还没开始则返回false,否则返回true
     * 当返回true的时候,任务正在执行,当任务执行完成,回调OnLoadCanceledListener 
     */
    protected boolean onCancelLoad() {
        return false;
    }

    /**强制开始加载数据,和startLoading()不同的是,该方法会忽略之前加载的数据集并去加载新的数据
     * 该方法会调用onForceLoad方法
     * Must be called from the process's main thread.
     */
    public void forceLoad() {
        onForceLoad();
    }

    /**
     * 子类需要实现这个方法,这里是一个空实现
     */
    protected void onForceLoad() {
        
    }

    /**
     *  
     * 该方法在fragment/activity停止的时候由loadermanger自动去执行 
     * 将mStarted置为false并调用onStopLoading方法
     * Stops delivery of updates until the next time startLoading() is
     * called. Implementations should  not invalidate their data at this
     * point -- clients are still free to use the last data the loader reported.
     * They will, however, typically stop reporting new data if the data
     * changes; they can still monitor for changes, but must not report them to
     * the client until and if  startLoading()  is later called.
     */
    public void stopLoading() {
        mStarted = false;
        onStopLoading();
    }

    /**
     * 在stopLoading执行时调用该方法
     * 子类需要实现这个方法
     */
    protected void onStopLoading() {
    }

    /**
     * 在loadermanger重启一个loadre时使用 
     * Tell the Loader that it is being abandoned. This is called prior to
     * reset to have it retain its current data but not report any new
     * data.
     */
    public void abandon() {
        mAbandoned = true;
        onAbandon();
    }

    /**
     *子类需要实现该方法
     *
     */
    protected void onAbandon() {
    }

    /**
     * 销毁loader时由loadrmanger自动调用
     * 重置loader,此时loader需要释放资源
     * 各个标志位设置为false ,mReset为true
     */
    public void reset() {
        onReset();
        mReset = true;
        mStarted = false;
        mAbandoned = false;
        mContentChanged = false;
        mProcessingChange = false;
    }

    /**
     * 
     */
    protected void onReset() {
    }

    /**
     * Take the current flag indicating whether the loader's content had changed
     * while it was stopped. If it had, true is returned and the flag is
     * cleared.
     */
    public boolean takeContentChanged() {
        //mContentChanged是在onContentChanged方法中started为false设true
        boolean res = mContentChanged;
        mContentChanged = false;
        mProcessingChange |= res;
        return res;
    }

    /**
     */
    public void commitContentChanged() {
        mProcessingChange = false;
    }

    /**
     * 
     */
    public void rollbackContentChanged() {
        if (mProcessingChange) {
            onContentChanged();
        }
    }

 
    //ForceLoadContentObserver的onChange方法里调用此方法
    //也就是说在数据发生改变的时候内容观察者的onChange方法被回调,会调用此方法来重新加载数据
    //首先会检查当前loader是否started如果是就执行forceLoad,如果不是就设置一个标志位
    //该标志位在执行takeContentChanged方法返回true
    public void onContentChanged() { 
        if (mStarted) {
            forceLoad();
        } else {
            //loader已经停止,我们不能立马加载数据,但是记录一下,在开始的时候去更新 
            mContentChanged = true;
        }
    }
 
    
    
    public Context getContext() {
        return mContext;
    }

     
    public int getId() {
        return mId;
    } 
     
    public boolean isStarted() {
        return mStarted;
    }

     
    public boolean isAbandoned() {
        return mAbandoned;
    }

     
    public boolean isReset() {
        return mReset;
    }
 
}

二. LoaderManager源码分析

package android.app;
import android.content.Loader;
import android.os.Bundle;
import android.util.DebugUtils;
import android.util.Log;
import android.util.SparseArray; 
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.reflect.Modifier;

/**
 * 与activity和fragment关联负责管理loader的接口
 * 与activity和fragment的生命周期方法配合执行长时间的操作 
 */
public abstract class LoaderManager {
    /**
     * 客户端与loadermanager交互的回调接口
     */
    public interface LoaderCallbacks {
        /**
         * Instantiate and return a new Loader for the given ID. 
         * @param id The ID whose loader is to be created.
         * @param args Any arguments supplied by the caller.
         * @return Return a new Loader instance that is ready to start loading.
         */
        public Loader onCreateLoader(int id, Bundle args);

        /** 
         * 
         */
        public void onLoadFinished(Loader loader, D data);

        /**
         * Called when a previously created loader is being reset, and thus
         * making its data unavailable.  The application should at this point
         * remove any references it has to the Loader's data. 
         */
        public void onLoaderReset(Loader loader);
    }
    
    public abstract  Loader initLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks callback);

  
    public abstract  Loader restartLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks callback);

    
    public abstract void destroyLoader(int id);

   
    public abstract  Loader getLoader(int id);

    
    public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);

  
    public static void enableDebugLogging(boolean enabled) {
        LoaderManagerImpl.DEBUG = enabled;
    }
}


class LoaderManagerImpl extends LoaderManager {
    static final String TAG = "LoaderManager";
    static boolean DEBUG = false;

    // These are the currently active loaders.  A loader is here
    // from the time its load is started until it has been explicitly
    // stopped or restarted by the application.
    final SparseArray mLoaders = new SparseArray(0);

    // These are previously run loaders.  This list is maintained internally
    // to avoid destroying a loader while an application is still using it.
    // It allows an application to restart a loader, but continue using its
    // previously run loader until the new loader's data is available.
    final SparseArray mInactiveLoaders = new SparseArray(0);

    final String mWho;

    boolean mStarted;
    boolean mRetaining;
    boolean mRetainingStarted;
    
    boolean mCreatingLoader;
    private FragmentHostCallback mHost;

    final class LoaderInfo implements Loader.OnLoadCompleteListener,
            Loader.OnLoadCanceledListener {
        final int mId;
        final Bundle mArgs;
        LoaderManager.LoaderCallbacks mCallbacks;
        Loader mLoader;
        boolean mHaveData;
        boolean mDeliveredData;
        Object mData;
        boolean mStarted;
        boolean mRetaining;
        boolean mRetainingStarted;
        boolean mReportNextStart;
        boolean mDestroyed;
        boolean mListenerRegistered;

        LoaderInfo mPendingLoader;
        
        public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks callbacks) {
            mId = id;
            mArgs = args;
            mCallbacks = callbacks;
        }
        
        void start() {
            if (mRetaining && mRetainingStarted) {
                // Our owner is started, but we were being retained from a
                // previous instance in the started state...  so there is really
                // nothing to do here, since the loaders are still started.
                mStarted = true;
                return;
            } 
            if (mStarted) {
                // If loader already started, don't restart.
                return;
            } 
            mStarted = true;
            
            if (DEBUG) Log.v(TAG, "  Starting: " + this);
            if (mLoader == null && mCallbacks != null) {
                //当loader为空的时候通过onCreateLoader来创建loader
                //所以该方法只会被回调一次
               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
            }
            if (mLoader != null) {
                if (mLoader.getClass().isMemberClass()
                        && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
                    throw new IllegalArgumentException(
                            "Object returned from onCreateLoader must not be a non-static inner member class: "
                            + mLoader);
                }
                if (!mListenerRegistered) {//如果没有注册监听,就再这里注册
                    mLoader.registerListener(mId, this);
                    mLoader.registerOnLoadCanceledListener(this);
                    mListenerRegistered = true;//注册完成后修改标志位
                }
                //调用mLoader的startLoading 方法,在startLoading中调用 onStartLoading();
                //所以需要loader的子类实现onStartLoading方法
                mLoader.startLoading();
            }
        }
        
        void retain() {
            if (DEBUG) Log.v(TAG, "  Retaining: " + this);
            mRetaining = true;
            mRetainingStarted = mStarted;
            mStarted = false;
            mCallbacks = null;
        }
        
        void finishRetain() {
            if (mRetaining) {
                if (DEBUG) Log.v(TAG, "  Finished Retaining: " + this);
                mRetaining = false;
                if (mStarted != mRetainingStarted) {
                    if (!mStarted) {
                        // This loader was retained in a started state, but
                        // at the end of retaining everything our owner is
                        // no longer started...  so make it stop.
                        stop();
                    }
                }
            }

            if (mStarted && mHaveData && !mReportNextStart) {
                // This loader has retained its data, either completely across
                // a configuration change or just whatever the last data set
                // was after being restarted from a stop, and now at the point of
                // finishing the retain we find we remain started, have
                // our data, and the owner has a new callback...  so
                // let's deliver the data now.
                callOnLoadFinished(mLoader, mData);
            }
        }
        
        void reportStart() {
            if (mStarted) {
                if (mReportNextStart) {
                    mReportNextStart = false;
                    if (mHaveData && !mRetaining) {
                        callOnLoadFinished(mLoader, mData);
                    }
                }
            }
        }

        void stop() {
            if (DEBUG) Log.v(TAG, "  Stopping: " + this);
            mStarted = false;
            if (!mRetaining) {
                if (mLoader != null && mListenerRegistered) {
                    // Let the loader know we're done with it
                    //注销监听
                    mListenerRegistered = false;
                    mLoader.unregisterListener(this);
                    mLoader.unregisterOnLoadCanceledListener(this);
                    mLoader.stopLoading();
                    //调用stopLoading方法,onStopLoding被调用
                }
            }
        }

        boolean cancel() {
            if (DEBUG) Log.v(TAG, "  Canceling: " + this);
            if (mStarted && mLoader != null && mListenerRegistered) {
                final boolean cancelLoadResult = mLoader.cancelLoad();
                if (!cancelLoadResult) {
                    onLoadCanceled(mLoader);//回调被执行
                }
                return cancelLoadResult;
            }
            return false;
        }

        void destroy() {
            if (DEBUG) Log.v(TAG, "  Destroying: " + this);
            mDestroyed = true;
            boolean needReset = mDeliveredData;
            mDeliveredData = false;
            if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
                if (DEBUG) Log.v(TAG, "  Reseting: " + this);
                String lastBecause = null;
                if (mHost != null) {
                    lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
                    mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset";
                }
                try {
                    mCallbacks.onLoaderReset(mLoader);
                } finally {
                    if (mHost != null) {
                        mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
                    }
                }
            }
            mCallbacks = null;
            mData = null;
            mHaveData = false;
            if (mLoader != null) {
                if (mListenerRegistered) {
                    mListenerRegistered = false;
                    mLoader.unregisterListener(this);
                    mLoader.unregisterOnLoadCanceledListener(this);
                }
                mLoader.reset();
            }
            if (mPendingLoader != null) {
                mPendingLoader.destroy();
            }
        }

        @Override
        public void onLoadCanceled(Loader loader) {
            if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);

            if (mDestroyed) {
                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- destroyed");
                return;
            }

            if (mLoaders.get(mId) != this) {
                // This cancellation message is not coming from the current active loader.
                // We don't care about it.
                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- not active");
                return;
            }

            LoaderInfo pending = mPendingLoader;
            if (pending != null) {
                // There is a new request pending and we were just
                // waiting for the old one to cancel or complete before starting
                // it.  So now it is time, switch over to the new loader.
                if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
                mPendingLoader = null;
                mLoaders.put(mId, null);
                destroy();
                installLoader(pending);
            }
        }

        @Override
        public void onLoadComplete(Loader loader, Object data) {
            if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
            
            if (mDestroyed) {
                if (DEBUG) Log.v(TAG, "  Ignoring load complete -- destroyed");
                return;
            }

            if (mLoaders.get(mId) != this) {
                // This data is not coming from the current active loader.
                // We don't care about it.
                if (DEBUG) Log.v(TAG, "  Ignoring load complete -- not active");
                return;
            }
            
            LoaderInfo pending = mPendingLoader;
            if (pending != null) {
                // There is a new request pending and we were just
                // waiting for the old one to complete before starting
                // it.  So now it is time, switch over to the new loader.
                if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
                mPendingLoader = null;
                mLoaders.put(mId, null);
                destroy();
                installLoader(pending);
                return;
            }
            
            // Notify of the new data so the app can switch out the old data before
            // we try to destroy it.
            if (mData != data || !mHaveData) {
                mData = data;
                mHaveData = true;
                if (mStarted) {
                    callOnLoadFinished(loader, data);
                }
            }

            //if (DEBUG) Log.v(TAG, "  onLoadFinished returned: " + this);

            // We have now given the application the new loader with its
            // loaded data, so it should have stopped using the previous
            // loader.  If there is a previous loader on the inactive list,
            // clean it up.
            LoaderInfo info = mInactiveLoaders.get(mId);
            if (info != null && info != this) {
                info.mDeliveredData = false;
                info.destroy();
                mInactiveLoaders.remove(mId);
            }

            if (mHost != null && !hasRunningLoaders()) {
                mHost.mFragmentManager.startPendingDeferredFragments();
            }
        }

        void callOnLoadFinished(Loader loader, Object data) {
            if (mCallbacks != null) {
                String lastBecause = null;
                if (mHost != null) {
                    lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
                    mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
                }
                try {
                    if (DEBUG) Log.v(TAG, "  onLoadFinished in " + loader + ": "
                            + loader.dataToString(data));
                    //回调
                    mCallbacks.onLoadFinished(loader, data);
                } finally {
                    if (mHost != null) {
                        mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
                    }
                }
                mDeliveredData = true;
            }
        }
        
        @Override
        public String toString() {
            // ......
          }
        }

        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
            
        }
    }
    
    LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
        mWho = who;
        mHost = host;
        mStarted = started;
    }
    
    void updateHostController(FragmentHostCallback host) {
        mHost = host;
    }
    
    private LoaderInfo createLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks callback) {
        LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks)callback);
        //createLoader方法会回调onCreateLoader,这里需要用户自己实现onCreateLoader方法实现自己的loader
        Loader loader = callback.onCreateLoader(id, args);
        info.mLoader = (Loader)loader;
        return info;
    }
    
    private LoaderInfo createAndInstallLoader(int id, Bundle args,
            LoaderManager.LoaderCallbacks callback) {
        try {
            mCreatingLoader = true;
            LoaderInfo info = createLoader(id, args, callback);
            installLoader(info);
            return info;
        } finally {
            mCreatingLoader = false;
        }
    }
    
    void installLoader(LoaderInfo info) {
        mLoaders.put(info.mId, info);
        if (mStarted) {
            // The activity will start all existing loaders in it's onStart(),
            // so only start them here if we're past that point of the activitiy's
            // life cycle
            info.start();
        }
    }
    
    
    @SuppressWarnings("unchecked")
    public  Loader initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback) {
        if (mCreatingLoader) {
            throw new IllegalStateException("Called while creating a loader");
        }
        
        LoaderInfo info = mLoaders.get(id);
        
        if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);

        if (info == null) {
            // Loader doesn't already exist; create.
            info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks)callback);
            if (DEBUG) Log.v(TAG, "  Created new loader " + info);
        } else {
            if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
            info.mCallbacks = (LoaderManager.LoaderCallbacks)callback;
        }
        
        if (info.mHaveData && mStarted) {//如果已经有数据
            // If the loader has already generated its data, report it now.
            info.callOnLoadFinished(info.mLoader, info.mData);
        } 
        return (Loader)info.mLoader;
    }
    
 
    
    @SuppressWarnings("unchecked")
    public  Loader restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback) {
        if (mCreatingLoader) {
            throw new IllegalStateException("Called while creating a loader");
        }
        
        LoaderInfo info = mLoaders.get(id);
        if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
        if (info != null) {
            LoaderInfo inactive = mInactiveLoaders.get(id);
            if (inactive != null) {
                if (info.mHaveData) {
                    // This loader now has data...  we are probably being
                    // called from within onLoadComplete, where we haven't
                    // yet destroyed the last inactive loader.  So just do
                    // that now.
                    if (DEBUG) Log.v(TAG, "  Removing last inactive loader: " + info);
                    inactive.mDeliveredData = false;
                    inactive.destroy();
                    info.mLoader.abandon();
                    mInactiveLoaders.put(id, info);
                } else {
                    // We already have an inactive loader for this ID that we are
                    // waiting for! Try to cancel; if this returns true then the task is still
                    // running and we have more work to do.
                    if (!info.cancel()) {
                        // The current Loader has not been started or was successfully canceled,
                        // we thus have no reason to keep it around. Remove it and a new
                        // LoaderInfo will be created below.
                        if (DEBUG) Log.v(TAG, "  Current loader is stopped; replacing");
                        mLoaders.put(id, null);
                        info.destroy();
                    } else {
                        // Now we have three active loaders... we'll queue
                        // up this request to be processed once one of the other loaders
                        // finishes.
                        if (DEBUG) Log.v(TAG,
                                "  Current loader is running; configuring pending loader");
                        if (info.mPendingLoader != null) {
                            if (DEBUG) Log.v(TAG, "  Removing pending loader: " + info.mPendingLoader);
                            info.mPendingLoader.destroy();
                            info.mPendingLoader = null;
                        }
                        if (DEBUG) Log.v(TAG, "  Enqueuing as new pending loader");
                        info.mPendingLoader = createLoader(id, args, 
                                (LoaderManager.LoaderCallbacks)callback);
                        return (Loader)info.mPendingLoader.mLoader;
                    }
                }
            } else {
                // Keep track of the previous instance of this loader so we can destroy
                // it when the new one completes.
                if (DEBUG) Log.v(TAG, "  Making last loader inactive: " + info);
                info.mLoader.abandon();
                mInactiveLoaders.put(id, info);
            }
        }
        
        info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks)callback);
        return (Loader)info.mLoader;
    }
    
    /**
     * Rip down, tear apart, shred to pieces a current Loader ID.  After returning
     * from this function, any Loader objects associated with this ID are
     * destroyed.  Any data associated with them is destroyed.  You better not
     * be using it when you do this.
     * @param id Identifier of the Loader to be destroyed.
     */
    public void destroyLoader(int id) {
        if (mCreatingLoader) {
            throw new IllegalStateException("Called while creating a loader");
        }
        
        if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
        int idx = mLoaders.indexOfKey(id);
        if (idx >= 0) {
            LoaderInfo info = mLoaders.valueAt(idx);
            mLoaders.removeAt(idx);
            info.destroy();
        }
        idx = mInactiveLoaders.indexOfKey(id);
        if (idx >= 0) {
            LoaderInfo info = mInactiveLoaders.valueAt(idx);
            mInactiveLoaders.removeAt(idx);
            info.destroy();
        }
        if (mHost != null && !hasRunningLoaders()) {
            mHost.mFragmentManager.startPendingDeferredFragments();
        }
    }

    /**
     * Return the most recent Loader object associated with the
     * given ID.
     */
    @SuppressWarnings("unchecked")
    public  Loader getLoader(int id) {
        if (mCreatingLoader) {
            throw new IllegalStateException("Called while creating a loader");
        }
        
        LoaderInfo loaderInfo = mLoaders.get(id);
        if (loaderInfo != null) {
            if (loaderInfo.mPendingLoader != null) {
                return (Loader)loaderInfo.mPendingLoader.mLoader;
            }
            return (Loader)loaderInfo.mLoader;
        }
        return null;
    }
 
    void doStart() {
        if (DEBUG) Log.v(TAG, "Starting in " + this);
        if (mStarted) {
            RuntimeException e = new RuntimeException("here");
            e.fillInStackTrace();
            Log.w(TAG, "Called doStart when already started: " + this, e);
            return;
        }
        
        mStarted = true;

        // Call out to sub classes so they can start their loaders
        // Let the existing loaders know that we want to be notified when a load is complete
        for (int i = mLoaders.size()-1; i >= 0; i--) {
            mLoaders.valueAt(i).start();
        }
    }
    
    void doStop() {
        if (DEBUG) Log.v(TAG, "Stopping in " + this);
        if (!mStarted) {
            RuntimeException e = new RuntimeException("here");
            e.fillInStackTrace();
            Log.w(TAG, "Called doStop when not started: " + this, e);
            return;
        }

        for (int i = mLoaders.size()-1; i >= 0; i--) {
            mLoaders.valueAt(i).stop();
        }
        mStarted = false;
    }
    
    void doRetain() {
        if (DEBUG) Log.v(TAG, "Retaining in " + this);
        if (!mStarted) {
            RuntimeException e = new RuntimeException("here");
            e.fillInStackTrace();
            Log.w(TAG, "Called doRetain when not started: " + this, e);
            return;
        }

        mRetaining = true;
        mStarted = false;
        for (int i = mLoaders.size()-1; i >= 0; i--) {
            mLoaders.valueAt(i).retain();
        }
    }
    
    void finishRetain() {
        if (mRetaining) {
            if (DEBUG) Log.v(TAG, "Finished Retaining in " + this);

            mRetaining = false;
            for (int i = mLoaders.size()-1; i >= 0; i--) {
                mLoaders.valueAt(i).finishRetain();
            }
        }
    }
    
    void doReportNextStart() {
        for (int i = mLoaders.size()-1; i >= 0; i--) {
            mLoaders.valueAt(i).mReportNextStart = true;
        }
    }

    void doReportStart() {
        for (int i = mLoaders.size()-1; i >= 0; i--) {
            mLoaders.valueAt(i).reportStart();
        }
    }

    void doDestroy() {
        if (!mRetaining) {
            if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
            for (int i = mLoaders.size()-1; i >= 0; i--) {
                mLoaders.valueAt(i).destroy();
            }
            mLoaders.clear();
        }
        
        if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
        for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
            mInactiveLoaders.valueAt(i).destroy();
        }
        mInactiveLoaders.clear();
    }

    @Override
    public String toString() { 
        //......
    }

    @Override
    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { 
        //......
    }

    public boolean hasRunningLoaders() {
        boolean loadersRunning = false;
        final int count = mLoaders.size();
        for (int i = 0; i < count; i++) {
            final LoaderInfo li = mLoaders.valueAt(i);
            loadersRunning |= li.mStarted && !li.mDeliveredData;
        }
        return loadersRunning;
    }
}

 

                            
                        
                    
                    
                    

你可能感兴趣的:(android loader源码分析之一:整体交互流程)