Glide的with()過程和Glide的生命周期的源碼分析

??在Android開發(fā)中,或多或少你都會使用過很多的框架,但是沒有一個框架會像Glide一樣好用。Glide.with(context).load(url).into(imageView).一行代碼解決了很多問題,今天我們就來深入Glide的源碼,來看看這一行代碼背后的故事。先從Glide的with()方法開始我們的探索。

with()過程分析

Glide類里面的with()方法

 public static RequestManager with(Context context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(context);
    }
public static RequestManager with(Activity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
public static RequestManager with(FragmentActivity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
public static RequestManager with(android.app.Fragment fragment) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(fragment);
    }
/**
     * Begin a load with Glide that will be tied to the given {@link android.support.v4.app.Fragment}'s lifecycle and
     * that uses the given {@link android.support.v4.app.Fragment}'s default options.
     *
     * @param fragment The fragment to use.
     * @return A RequestManager for the given Fragment that can be used to start a load.
     */
public static RequestManager with(Fragment fragment) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(fragment);
    }

??Glide類里面有很多with()方法的重載,在with()方法中傳入不同類型的參數(shù),來調(diào)用不同的重載的with()方法??梢钥吹?,Glide為
Activity和Fragment(android.app.Fragment和v4包下的Fragment)都提供Glide的使用。
??通過看Glide的這幾個with()方法,可以發(fā)現(xiàn)里面都調(diào)用了RequestManageRetriever類的get()方法。

  • RequestManagerRetriever類:幫助拿到RequestManager對象,
    RequestManageRetriever類里面的get()方法
private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();
public static RequestManagerRetriever get() {
        return INSTANCE;
    }

??這個RequestManagerRetriever類里面的get()方法是一個static的靜態(tài)內(nèi)部方法,返回一個靜態(tài)RequestManagerRetriever對象,這是一個單例實現(xiàn)。
??在Glide類的這幾個重載的with()方法中,首先都是先得到了RequestManagerRetriever對象,緊接著都調(diào)用了RequestManagerRetriever對象的帶參數(shù)的實例get()方法,只不過不同的with()方法中傳入RequestManagerRetriever類的get()方法的參數(shù)類型不同罷了。

RequestManagerRetriever類中

private RequestManager getApplicationManager(Context context) {
        // Either an application context or we're on a background thread.
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {
                    // Normally pause/resume is taken care of by the fragment we add to the fragment or activity.
                    // However, in this case since the manager attached to the application will not receive lifecycle
                    // events, we must force the manager to start resumed using ApplicationLifecycle.
                    applicationManager = new RequestManager(context.getApplicationContext(),
                            new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }

        return applicationManager;
    }
public RequestManager get(Context context) {
        if (context == null) {
            throw new IllegalArgumentException("You cannot start a load on a null Context");
        } else if (Util.isOnMainThread() && !(context instanceof Application)) {
            if (context instanceof FragmentActivity) {
                return get((FragmentActivity) context);
            } else if (context instanceof Activity) {
                return get((Activity) context);
            } else if (context instanceof ContextWrapper) {
                return get(((ContextWrapper) context).getBaseContext());
            }
        }

        return getApplicationManager(context);
    }
public RequestManager get(FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            FragmentManager fm = activity.getSupportFragmentManager();
            return supportFragmentGet(activity, fm);
        }
    }
public RequestManager get(Fragment fragment) {
        if (fragment.getActivity() == null) {
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        if (Util.isOnBackgroundThread()) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            FragmentManager fm = fragment.getChildFragmentManager();
            return supportFragmentGet(fragment.getActivity(), fm);
        }
    }
public RequestManager get(Activity activity) {
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            android.app.FragmentManager fm = activity.getFragmentManager();
            return fragmentGet(activity, fm);
        }
    }
 public RequestManager get(android.app.Fragment fragment) {
        if (fragment.getActivity() == null) {
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            android.app.FragmentManager fm = fragment.getChildFragmentManager();
            return fragmentGet(fragment.getActivity(), fm);
        }
    }

??可以看到在RequestManagerRetriever類中,有很多get()實例方法的重載,歸根結(jié)底的分為傳入Application類型的和非Application類型的參數(shù)。
傳入Application類型的參數(shù)時,就會調(diào)用getApplicationManager()方法。在這個方法中會生成RequestManager對象并返回,這個RequestManager對象就是Glide類的with()方法中所返回的。
傳入非Application類型的參數(shù)時,會根據(jù)傳入的是Activity,還是Fragment(android.app.Fragment和v4包下的Fragment)來調(diào)用不同的get()方法。這些get()方法中傳入的參數(shù)類型不一樣,但是這些get()方法中的大致處理流程是一致的。我們選一個傳入v4包下的Fragment類型的get()方法來看。

傳入v4包下的Fragment到RequestManagerRetriever的實例get()方法

static final String FRAGMENT_TAG = "com.bumptech.glide.manager";
final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments =
            new HashMap<android.app.FragmentManager, RequestManagerFragment>();
private final Handler handler;
public RequestManager get(Fragment fragment) {
        if (fragment.getActivity() == null) {
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        //不在主線程中
        if (Util.isOnBackgroundThread()) {
          //調(diào)用Application類型參數(shù)的get()方法
            return get(fragment.getActivity().getApplicationContext());
        } else {
            //管理Fragment的FragmentManager
            FragmentManager fm = fragment.getChildFragmentManager();
            return supportFragmentGet(fragment.getActivity(), fm);
        }
    }
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
       // SupportRequestManagerFragment是一個無UI的Fragment
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }
SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
        SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(
            FRAGMENT_TAG);
        if (current == null) {
            current = pendingSupportRequestManagerFragments.get(fm);
            if (current == null) {
                current = new SupportRequestManagerFragment();
                pendingSupportRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }
 public boolean handleMessage(Message message) {
        boolean handled = true;
        Object removed = null;
        Object key = null;
        switch (message.what) {
            case ID_REMOVE_FRAGMENT_MANAGER:
                android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
                key = fm;
                removed = pendingRequestManagerFragments.remove(fm);
                break;
            case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
                FragmentManager supportFm = (FragmentManager) message.obj;
                key = supportFm;
                removed = pendingSupportRequestManagerFragments.remove(supportFm);
                break;
            default:
                handled = false;
        }
        if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Failed to remove expected request manager fragment, manager: " + key);
        }
        return handled;
    }
  • SupportRequestManagerFragment:是一個無UI的虛擬的Fragment,它是來輔助Glide來進行生命周期管理的。因為當(dāng)使用Glide加載圖片時,Glide不會感知到Activity的銷毀。通過這個虛擬的Fragment來感知到Activity的生命周期,并作出及時的反應(yīng)。
  • RequestManagerFragment與SupportRequestManagerFragment一樣,都是虛擬的Fragment,只不過前者是android.app.Fragment包下的Fragment,后者是v4包下的Fragment。

??分析一下這個過程,在RequestManagerRetriever類的get(Fragment fragment)方法中,先是進行判斷,不在主線程中就會調(diào)用調(diào)用Application類型參數(shù)的get()方法,否則生成一個管理Fragment的FragmentManager,然后調(diào)用supportFragmentGet()并將生成的FragmentManager對象傳入。
??在supportFragmentGet()方法中,先是調(diào)用了getSupportRequestManagerFragment()方法;那先進入這個方法中,在這個方法中,先是通過fm.findFragmentByTag( FRAGMENT_TAG)來尋找是否已經(jīng)存在這個SupportRequestManagerFragment,如果存在就直接返回。否則生成SupportRequestManagerFragment對象,并以FragmentManager為key,SupportRequestManagerFragment對象為value存入pendingRequestManagerFragments中,這個pendingRequestManagerFragments是一個HashMap。接著將剛剛生成的Fragment加入事物管理器中,但是緊接著又調(diào)用handel發(fā)送了一條消息,我們進入handleMessage()方法中,可以發(fā)現(xiàn)它將剛剛加入HashMap的Fragment又刪除了。
??怎么回事?剛剛加入進去,怎么緊接著又給刪除了。
??來分析一下這個過程。
??首先在Fragment和Activity綁定時,是通過開啟事務(wù)的方式來進行綁定的,也就是通過Hander來處理的。(感興趣這個過程的話可以通過看源碼來發(fā)現(xiàn))

Glide.with(context).load(url).into(image1);
Glide.with(context).load(url).into(image2);

??我們看上面的兩行代碼,在同一個Activity中分別為兩個ImageView加載圖片。
??當(dāng)?shù)谝恍写a運行到getSupportRequestManagerFragment()方法時,由于之前沒有SupportRequestManagerFragment實例,這個時候會生成一個新的SupportRequestManagerFragment實例,并保存在HashMap中,生成新的SupportRequestManagerFragment實例時,就會發(fā)Fragment于Activity的綁定,Handler會發(fā)送消息來進行綁定,假設(shè)這個消息為m1,緊接著在getSupportRequestManagerFragment()方法中,就會使用Handler來發(fā)送從HashMap中刪除保存的SupportRequestManagerFragment實例對象的消息,假設(shè)這個消息為m2。
??在Handler處理消息時,如果在m1與m2消息之前,Handler的消息隊列中還存在其他的消息,此時m1與m2還沒有得到處理,就是此時還沒有進行Fragment與Activity的綁定。第二行Glide.with(context).load(url).into(image2);代碼已經(jīng)進行到了getSupportRequestManagerFragment()方法了,如果此時我們不將Fragment存入HashMap中,就會重新生成一個SupportRequestManagerFragment,這是Glide所不允許的,每一個Activity或者Fragment在使用Glide時,只能有一個所依附的虛擬的Fragment。所以將之前所生成的SupportRequestManagerFragment存儲到HashMap中,這樣就不會重復(fù)生成SupportRequestManagerFragment,等到SupportRequestManagerFragment與Activity綁定完成后,也就是消息m1處理完成后,再將SupportRequestManagerFragment從HashMap中銷毀。
??這個過程分析完了,之后在getSupportRequestManagerFragment()方法中將Fragment返回,接著回到supportFragmentGet()方法中。在這個方法中,接著就生成了RequestManager對象。注意到,在生成這個RequestManager對象時構(gòu)造器中傳入的是剛剛從getSupportRequestManagerFragment()方法中返回的SupportRequestManagerFragment對象中的一些東西。
??Glide的with()過程分析完了,最終得到了Gilde類的with()方法中需要的RequsetManager對象。

Glide的生命周期

??從SupportRequestManagerFragment類開始吧。
??來看一下SupportRequestManagerFragment類。

SupportRequestManagerFragment類

private final ActivityFragmentLifecycle lifecycle;
//在SupportRequestManagerFragment類的構(gòu)造方法中生成ActivityFragmentLifecycle對象
public SupportRequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
    }
public SupportRequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }
  • ActivityFragmentLifecycle類是生命周期回調(diào)的管理類,它實現(xiàn)了LifeCycle接口,會將LifecycleListener的接口加入到ActivityFragmentLifecycle類中的Set集合中,當(dāng)SupportRequestManagerFragment的生命周期的方法觸發(fā)時,會調(diào)用ActivityFragmentLifeCycle的相應(yīng)方法。

ActivityFragmentLifeCycle的相應(yīng)方法

private final Set<LifecycleListener> lifecycleListeners =
            Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;
@Override
    public void addListener(LifecycleListener listener) {
        lifecycleListeners.add(listener);

        if (isDestroyed) {
            listener.onDestroy();
        } else if (isStarted) {
            listener.onStart();
        } else {
            listener.onStop();
        }
    }
void onStart() {
        isStarted = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onStart();
        }
    }

void onStop() {
        isStarted = false;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onStop();
        }
    }

 void onDestroy() {
        isDestroyed = true;
        for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
            lifecycleListener.onDestroy();
        }
    }

SupportRequestManagerFragment類中

@Override
    public void onStart() {
        super.onStart();
        lifecycle.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
        lifecycle.onStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        lifecycle.onDestroy();
    }

??可以看到當(dāng)SupportRequestManagerFragment類中的相應(yīng)的生命周期的方法調(diào)用時就會調(diào)用ActivityFragmentLifeCycle的相應(yīng)方法。
??繼續(xù)SupportRequestManagerFragment類。

SupportRequestManagerFragment類中

private final RequestManagerTreeNode requestManagerTreeNode =
            new SupportFragmentRequestManagerTreeNode();
private final HashSet<SupportRequestManagerFragment> childRequestManagerFragments =
        new HashSet<SupportRequestManagerFragment>();
private SupportRequestManagerFragment rootRequestManagerFragment;
@Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        rootRequestManagerFragment = RequestManagerRetriever.get()
                .getSupportRequestManagerFragment(getActivity().getSupportFragmentManager());
        if (rootRequestManagerFragment != this) {
            rootRequestManagerFragment.addChildRequestManagerFragment(this);
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        if (rootRequestManagerFragment != null) {
            rootRequestManagerFragment.removeChildRequestManagerFragment(this);
            rootRequestManagerFragment = null;
        }
    }

 private void addChildRequestManagerFragment(SupportRequestManagerFragment child) {
        childRequestManagerFragments.add(child);
    }

    private void removeChildRequestManagerFragment(SupportRequestManagerFragment child) {
        childRequestManagerFragments.remove(child);
    }

 public Set<SupportRequestManagerFragment> getDescendantRequestManagerFragments() {
        if (rootRequestManagerFragment == null) {
            return Collections.emptySet();
        } else if (rootRequestManagerFragment == this) {
            return Collections.unmodifiableSet(childRequestManagerFragments);
        } else {
            HashSet<SupportRequestManagerFragment> descendants =
                new HashSet<SupportRequestManagerFragment>();
            for (SupportRequestManagerFragment fragment
                : rootRequestManagerFragment.getDescendantRequestManagerFragments()) {
                if (isDescendant(fragment.getParentFragment())) {
                    descendants.add(fragment);
                }
            }
            return Collections.unmodifiableSet(descendants);
        }
    }

private boolean isDescendant(Fragment fragment) {
        Fragment root = this.getParentFragment();
        while (fragment.getParentFragment() != null) {
            if (fragment.getParentFragment() == root) {
                return true;
            }
            fragment = fragment.getParentFragment();
        }
        return false;
    }

private class SupportFragmentRequestManagerTreeNode implements RequestManagerTreeNode {
        @Override
        public Set<RequestManager> getDescendants() {
            Set<SupportRequestManagerFragment> descendantFragments = getDescendantRequestManagerFragments();
            HashSet<RequestManager> descendants = new HashSet<RequestManager>(descendantFragments.size());
            for (SupportRequestManagerFragment fragment : descendantFragments) {
                if (fragment.getRequestManager() != null) {
                    descendants.add(fragment.getRequestManager());
                }
            }
            return descendants;
        }
    }

??在SupportRequestManagerFragment剛剛和Activity建立連接的時候即在onAttach()方法中,會初始化rootRequestManagerFragment實例變量。

  rootRequestManagerFragment = RequestManagerRetriever.get()
                .getSupportRequestManagerFragment(getActivity().getSupportFragmentManager());

??注意這個初始化的過程,在getSupportRequestManagerFragment()方法中傳入的是getActivity().getSupportFragmentManager()。

  • 如果在Glide.with()時傳入的是Activity類型的參數(shù),則會得到Activity的SupportRequestManagerFragment也就是自己。如果在Glide.with()時傳入的是Fragment類型的參數(shù),則rootRequestManagerFragment指向的是該Fragment所依賴的Activity的SupportRequestManagerFragment。如果Fragment所依賴的SupportRequestManagerFragment存在則直接調(diào)用,否則為該Fragment所依賴的Activity創(chuàng)建SupportRequestManagerFragment。
  • rootRequestManagerFragment指向根Activity的SupportRequestManagerFragment。

??在onAttach()方法中,如果rootRequestManagerFragment不是本身,即rootRequestManagerFragment指向根Activity,則將本身保存到childRequestManagerFragments集合中。也就是在這個集合中保存了Activity的所有的子Fragment的SupportRequestManagerFragment。

??當(dāng)Fragment銷毀時,在這個Fragment中的子Fragment會怎么樣?當(dāng)然也是會銷毀啊。也就是父Fragment的生命周期的方法被調(diào)用時,子Fragment的生命周期的方法也要會被調(diào)用。

  • RequestManagerTreeNode接口:這個接口用來保存請求樹節(jié)點,SupportFragmentRequestManagerTreeNode類繼承于這個接口.
public interface RequestManagerTreeNode {
    /**
     * Returns all descendant {@link RequestManager}s relative to the context of the current {@link RequestManager}.
     */
    Set<RequestManager> getDescendants();
}

??看一下SupportFragmentRequestManagerTreeNode類,這個類只有一個getDescendants()方法,先是利用getDescendantRequestManagerFragments()方法得到一個SupportRequestManagerFragment的集合。
??一個例子,一個Activity有兩個Fragment,分別為F1和F2,Activity有一個SRMF(SupportRequestManagerFragment),F1和F2分別有一個SRFM,F(xiàn)1和F2分別又有兩個Fragment,分別為F11,F12,F21,F22,這4個Fragment分別擁有SRMF。所以一共有6個SRMF保存在上面所說的rootRequestManagerFragment所指向的集合中。所以當(dāng)F1生命周期要做出反應(yīng)時,它的子Fragment分別為F11和F12對應(yīng)的SRMF也要有相應(yīng)的反應(yīng)。但F2的子Fragment的SRMF不做出反應(yīng)。那怎么得到F1的子Fragment的SRMF,這就是SupportFragmentRequestManagerTreeNode類的作用了。
??接著看。
??在getDescendantRequestManagerFragments()方法中,如果自己不是rootRequestManagerFragment就會在for()循環(huán)中遍歷返回的rootRequestManagerFragment所指向的集合,這個集合中保存了根Activity的所有的子Fragment的SRMF。接著每遍歷一次,就會調(diào)用isDescendant()方法進行判斷,比如說這個本身的SupportRequestManagerFragment是F1,所有每次都會遍歷返回的集合的SPMF是不是F1的子Fragment的SRMF。如果是的話,就將這個SRMF加入集合。
??最后在SupportFragmentRequestManagerTreeNode類getDescendants()方法中得到的都是Fragment的子Fragment的SRMF,最后將子Fragment的SRMF中的RequestManager對象的集合返回。
??所以SupportFragmentRequestManagerTreeNode類getDescendants()方法返回的是Fragment的子Fragment的SRMF的RequestManager對象的集合。

??接著來看RequestManager類

  • RequestManager類實現(xiàn)了LifecycleListener接口??梢詥?,停止,管理Glide的Request請求,是實現(xiàn)Glide加載資源的管理類,是Glide生命周期實現(xiàn)的關(guān)鍵類 。

RequestManager類

private final Context context;
private final Lifecycle lifecycle;
private final RequestManagerTreeNode treeNode;
private final RequestTracker requestTracker;
public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
        this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
    }

    RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
            RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
        this.context = context.getApplicationContext();
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
        ......
        if (Util.isOnBackgroundThread()) {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    lifecycle.addListener(RequestManager.this);
                }
            });
        } else {
            lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
    }

??可以看見,在RequestManager的構(gòu)造器中將RequestManager對象加入到ActivityLifeCycle中去。
??再看看RequestManager類實現(xiàn)的LifeCycleListener接口的方法。

RequestManager類實現(xiàn)的LifeCycleListener接口的方法(onStop)

public boolean isPaused() {
        Util.assertMainThread();
        return requestTracker.isPaused();
    }
 public void pauseRequests() {
        Util.assertMainThread();
        requestTracker.pauseRequests();
    }
@Override
    public void onStop() {
        pauseRequests();
    }

??可以看見在這些方法中真正起作用的是RequestTracker。

  • RequestTracker類:所有請求的真正執(zhí)行者

??來捋一下思路,首先是Glide為了管理生命周期,創(chuàng)建了一個無UI的虛擬的Fragment,在這個Fragment創(chuàng)建的時候就生成了ActivityFragmentLifeCycle生命周期的管理的對象,當(dāng)Fragment的生命周期變化時就會調(diào)用ActivityFragmentLifeCycle的相應(yīng)的方法。而RequestManager類實現(xiàn)了LifeCycleListener接口,在RequestManager的構(gòu)造器中會將創(chuàng)建的RequestManager對象加入到
ActivityFragmentLifeCycle的管理LifeCycleListener接口的集合中去,所以當(dāng)ActivityFragmentLifeCycle的相應(yīng)的方法調(diào)用時就會調(diào)用RequestManager對象的相應(yīng)方法,而在RequestManager對象的相應(yīng)方法真正的執(zhí)行者是RequestTracker。

參考

Android圖片加載框架最全解析(二),從源碼的角度理解Glide的執(zhí)行流程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容