Glide源码分析之4.12

Glide生命周期管理
带着问题学Glide做了哪些优化?
Glide 源码学习,了解 Glide 图片加载原理
Glide源码解析一,初始化

集成

Gradle中的依赖
//implementation 'com.github.bumptech.glide:glide:4.12.0'
// 作为依赖库使用api
api 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
添加注解通过APT生成注解处理器文件

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}

Glide的使用

Glide.with(this)
 //  .asBitmap()//只允许加载静态图片,若传入gif图会展示第一帧(要在load之前)
 //  .asGif()//指定gif格式(要在load之前)
 //  .asDrawable()//指定drawable格式(要在load之前)
     .load(imageUrl)//被加载图像的url地址
     .placeholder(R.drawable.ic_placeholder)//占位图片
     .error(R.drawable.ic_error)//错误图片
     .transition(GenericTransitionOptions.with(R.anim.zoom_in))//图片动画
     .override(800,800)//设置加载尺寸
     .skipMemoryCache(true)//禁用内存缓存功能
     .diskCacheStrategy(DiskCacheStrategy.NONE)//不缓存任何内容
  // .diskCacheStrategy(DiskCacheStrategy.DATA)//只缓存原始图片
  // .diskCacheStrategy(DiskCacheStrategy.RESOURCE)//只缓存转换后的图片
  // .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有
  // .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)//Glide根据图片资源智能地选择使用哪一种缓存策略(默认)
     .listener(new RequestListener<Drawable>() {//监听图片加载状态
        //图片加载完成
         @Override
         public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
            return false;
         }
         //图片加载失败
         @Override
         public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
             return false;
         }
     })
    .into(imageView);//图片最终要展示的地方

Activity中调用Glide.with(this)流程

1、在Activity中调用Glide.with(this)的时候会创建一个空白的Fragment

Glide.java

@NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }
  
with中调用getRetriever()方法

->
getRetriever()方法内部调用get(context)方法
->
get(context)方法内部调用getAnnotationGeneratedGlideModules()和checkAndInitializeGlide()方法
->
getAnnotationGeneratedGlideModules()方法里面通过反射获取被@GlideModule注解生成的java文件通过类加载方式获取他的构造方法,获取实例对象
->checkAndInitializeGlide()方法内部调用->initializeGlide(context, generatedAppGlideModule);方法
->
initializeGlide()内部继续调用initializeGlide(不同参数的重载函数)方法
->
initializeGlide()调用builder.build(applicationContext);方法(重要,build()
->

GlideBuilder.java
->
build.build()方法很重要。build方法方法获得Glide对象,
该对象只创建这么一次,Glide添加了注解,生成的java文件会解析,对比3.x解析清单文件,如果注解有了就移除
清单文件的,在build里面创建缓存策略线程池,sourceExecutor,diskCacheExecutor,animationExecutor,memorySizeCalculator)
->
->

build()方法调用了构造方法 new RequestManagerRetriever()
->
RequestManagerRetriever()构造方法实例化了RequestManagerFactory(),
->
RequestManagerFactory()中实例化了new RequestManager()
->
RequestManager()实现了LifeCyclerListener,在构造方法中LifeCycle将RequestManager对象添加监听,而LifeCycle对应为多样,比如ActivityFragmentLifecycle,ApplicationLifecycle,
->
ActivityFragmentLifecycle中添加了RequestManager监听

->
也就完成了Frament的生命周期中调用了LifeCycle的生命周期方法,而Lifecycle生命周期中调用了LifeCycleListener的生命周期方法。对应于
->
SupportRequestManagerFragment->onstart()
->
ActivityFragmentLifecycle->onstart()
->
RequestManager->onstart()

 RequestManagerRetriever.java

@NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

2、这个Fragment为SupportRequestManagerFragment ,在RequestManagerRetriever.java中会调用它的get()方法,get方法会调用supportFragmentGet()或者fragmentGet()方法。

 RequestManagerRetriever.java
  @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      if (isParentVisible) {
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

3、在supportFragmentGet()方法中会创建空白的Fragment(1,通过Tag查找,2,通过集合里面取,3,直接new SupportRequestManagerFragment()),将创建的空白Fragment跟RequestManager绑定起来,

 private static final RequestManagerFactory DEFAULT_FACTORY =
      new RequestManagerFactory() {
        @NonNull
        @Override
        public RequestManager build(
            @NonNull Glide glide,
            @NonNull Lifecycle lifecycle,
            @NonNull RequestManagerTreeNode requestManagerTreeNode,
            @NonNull Context context) {
            //1创建RequestManager的构造方法,
          return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
        }
      };

//2,RequestManager实现了LifecycleListener,被LifeCycle生命周期拥有者添加了监听,而LifeCycle里面的
addListener()方法内部调用了LifecycleListener的addListener()方法。
 RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;

    connectivityMonitor =
        factory.build(
            context.getApplicationContext(),
            new RequestManagerConnectivityListener(requestTracker));

    if (Util.isOnBackgroundThread()) {
      Util.postOnUiThread(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);

    defaultRequestListeners =
        new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }

public RequestManagerRetriever(
      @Nullable RequestManagerFactory factory, GlideExperiments experiments) {
    //2
    this.factory = factory != null ? factory : DEFAULT_FACTORY;
    handler = new Handler(Looper.getMainLooper(), this /* Callback */);

    frameWaiter = buildFrameWaiter(experiments);
  }  

requestManager =
    //3
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
   

4、RequestManager 实现了LifecycleListener接口,LifecycleListener接口有onstart,onstop,ondestory方法。
5、SupportRequestManagerFragment这个Fragment中持有生命周期拥有者ActivityFragmentLifeCycle,该类实现了LifeCycle接口,LifeCycle中存在onstart,onstop,ondestory方法。
6、 在Fragment生命周期发生变化时,该生命周期拥有者ActivityFragmentLifecycle 会调用它自身的onstart,onstop,ondestory等方法,ActivityFragmentLifecycle 中的onstart,onstop,ondestory方法会调用LifecycleListener的onstart,onstop,ondestory方法。
监听者LifecycleListener会调用它自身的onstart,onstop等方法,可以添加和移除实现了LifecycleListener接口的监听,而RequestManager实现了LifecycleListener,也就是Fragment生命周期变化的时候RequestManager内部实现的LifecycleListener接口的onstart,onstop,ondestory会被调用。

    GlideApp.with(this).load("").into(mDataBinding.imageview);
   
    Glide.with(this).load("")
                .placeholder(R.drawable.ic_launcher_background)
                .error("")
                .into(mDataBinding.imageview);

Glide.java
  @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }
  
RequestManagerRetriever.java
  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

....java
    /**
    *该方法获取RequestManager,里面存储了当前Glide.with(this)的fragment,
    *
    */
 @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    //1
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
//而在构建RequestManager的时候,传进去了一个current.getGlideLifecycle()
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    
      if (isParentVisible) {
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
/**
*先通过tag取,取不到的情况,下在集合里面取,实在取不到就new SupportRequestManagerFragment,返回到1处
*/
@NonNull
  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }


Glide.with(this)绑定了Activity的生命周期。在获取Glide对象时,通过GlideBuilder.build()方法初始化缓存线程池。在Activity内新建了一个无UI的Fragment,这个Fragment持有一个Lifecycle,通过Lifecycle在Fragment关键生命周期通知RequestManager进行相关从操作。在生命周期onStart时继续加载,onStop时暂停加载,onDestory时停止加载任务和清除操作。

build方法里面是对glide的各种配置,比如上面的:

1、加载源数据的线程池
2、加载磁盘缓存中数据的线程池(不能用来加载url网络数据)
3、动画加载请求器
4、内存计算器
5、网络状态检测器
6、bitmap缓存池(避免不断不断创建与回收bitmap导致内存抖动)
7、数组资源缓存池
8、内存缓存,缓存完成加载和显示的图片数据资源
9、本地磁盘缓存,默认存储在app内部私密目录

然后创建图片加载引擎。new Engine();最后再将上面的缓存池,引擎等作为参数,构建一个Glide()

这个Glide中的构造函数非常长,我们只挑一些重点的来讲,其它的可以类推:

1、创建各种decoder,也就是解码器,比如:
将ByteBuffer解码为GifDrawable。
ByteBufferGifDecoder byteBufferGifDecoder =
        new ByteBufferGifDecoder(context, imageHeaderParsers, bitmapPool, arrayPool);

将资源uri解码为Drawable:
ResourceDrawableDecoder resourceDrawableDecoder = new ResourceDrawableDecoder(context);
2、创建各种factory,即模型装换器,比如:
ResourceLoader.StreamFactory resourceLoaderStreamFactory =
        new ResourceLoader.StreamFactory(resources);
将Android资源ID转换为Uri,在加载成为InputStream
 ResourceLoader.UriFactory resourceLoaderUriFactory = new ResourceLoader.UriFactory(resources);
  

将资源ID转换为Uri

3、创建各种Transcoder,即转码器,比如

 BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();
将Bitmap转码为Byte arrays
GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();

将将GifDrawable转码为Byte arrays

4、创建各种encoder,即编码器,比如:

BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);

将Bitmap数据缓存为File

5、注册:注册将Byte数据缓存为File的编码器,注册将InputStream缓存为File的编码器。将ByteBuffer解码为Bitmap的解码器,将inputStreams解码为Bitmap的编码器。

 registry
        .append(ByteBuffer.class, new ByteBufferEncoder())
        .append(InputStream.class, new StreamEncoder(arrayPool))
        /* Bitmaps */
        .append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
        .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder);

load()

inito()

RequestBuilder.java

1、从into()->into()->buildRequest()获取一个Request。
2、在buildRequest中调用buildRequestRecursive()方法,这个方法里面有主要的请求和错误的请求,我们看主要的mainRequest的实例化,会调用到buildThumbnailRequestRecursive()这个方法拿到Request。
3、在上面方法中会得到fullRequest和thumbRequest,分别通过obtainRequest()和buildRequestRecursive()方法。
4、先看obtainRequest()方法,可以看到会调用到SingleRequest的obtain()方法。得到SingleRequest的对象。
接下来就是SingleRequest.java里面的内容
5、SingleRequest中的obtain()会调用到SingleRequest()的构造方法,实例化SingleRequest对象。
6、在步骤1中第二个into的时候,获取了request对象,into里面会调用previous.begin();或者requestManager.track(target, request);方法。
7、begin()方法直接请求网络
8、requestManager.track()方法会执行RequestTracker的runRequest()方法
接下来就是在RequestTracker.java中
9、接下来也是执行Request中的begin()方法。
10、在begin()方法中回调用onSizeReady(),而onSizeReady回调用Engin的load()方法。 loadStatus =engine.load()
接下来就是在Engin.java类中
11、Engin.load()在load方法中会调用,waitForExistingOrStartNewJob()方法,在这个方法里面有两个关键类,EnginJob(内部类EngineJobFactory)和DecodeJob(内部类DecodeJobFactory)。
接下来看EnginJob。java
12、EngineJob<R> engineJob =engineJobFactory.build(),接着在build()中调用init()
接下来看DecodeJob。java
13、DecodeJob>builder().init()->DecodeHelper.init()
14、接着回到11步骤的waitForExistingOrStartNewJob()方法,在获取了EngineJob和DecodeJob后会启动以下关键代码。EngineJob会给到DecodeJob的build中作为参数


   jobs.put(key, engineJob);
  
    engineJob.addCallback(cb, callbackExecutor);
    engineJob.start(decodeJob);

15、engineJob的addCallBack方法会把线程池和cd传递过去执行了CallResourceReady这个实现了Runnable接口的线程,不知道执行了一大堆什么乱七八糟的
16、接下来看engineJob的start(decodeJob)方法,该方法会有一个GlideExecutor线程池,而decodeJob也实现了Runnable接口。 GlideExecutor.execute(decodeJob);就会执行到decodeJob的run()方法。
继续再DecodeJob中来看
17、DeccorderJob中的run()方法中回调用runWrapped()方法,该方法会调用到runGenerators()方法。
18、在runGenerators中会有个while循环,会调用currentGenerator.startNext(),而currentGenerator是DataFetcherGenerator.java的对象,DataFetcherGenerator接口有三个实现类,我们选取SourceGenerator来看下,反正也不知道是什么一坨。。。


image.png

接下来看SourceGenerator。java
19、SourceGenerator中的startNext()中回调用startNextLoad()方法,该方法中会调用 loadData.fetcher.loadData(x,new DataCallback()),其中loadData为ModelLoader的内部类LoadData,fetcher为DataFetcher。而DataFetcher的实现类挺多,可以随意找一个,比如现在要看into的网络请求HttpUrlFetcher.java类。。。。emmm......


image.png

接下来就看HttpUrlFetcher。java
20、HttpUrlFetcher中的loadData()方法,内部会调用loadDataWithRedirects()会返回一个InputStream,猜测就是网络请求拿到的图片结果。
21、loadDataWithRedirects()方法中,会有一个HttpUrlConnection用于网络请求,通过buildAndConfigureConnection()得到该HttpUrlConnection的对象,·

private HttpURLConnection buildAndConfigureConnection(URL url, Map<String, String> headers)
      throws HttpException {
    HttpURLConnection urlConnection;
    try {
      urlConnection = connectionFactory.build(url);
    } catch (IOException e) {
      throw new HttpException("URL.openConnection threw", /*statusCode=*/ 0, e);
    }
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);
    // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
    // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
    urlConnection.setInstanceFollowRedirects(false);
    return urlConnection;
  }
```java
好了,综上假装上述主线流程没有问题,那么就拿到了图片流。。。

### ImageView设置图片的主线流程
1、RequestBuilder中的into()方法,内部调用了 requestManager.track(target, request);,接下来看RequestManager中的track方法。
2、RequestManager的track()会调用RequestTracker的runRequest()方法,接着会调用  request.begin();而SingleRequest实现了Request的begin()方法。
3、接下来看SingleRequest的begin(),可以看到会调用onResourceReady()方法
4、onResourceReady中会继续调用onResourceReady()第二个 onResourceReady回调用target.onResourceReady(result, animation);方法,而ImageVIewTarget实现了接口Target的onResourceReady方法,在该ImageViewTarget中可以看到setResourceInternal()方法。
```java
if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }

5、setResourceInternal()调用了 setResource(resource)抽象方法,实现了该ImageVIewTarget的setResource抽象方法均为设置ImageView的ImageDrawable属性。

  @Override
  protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
  }

以上粗略认为是into设置的图片主线。

Glide为什么对Fragment做缓存?

 private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
//添加到Map缓存中(防止fragment重复创建)
        pendingSupportRequestManagerFragments.put(fm, current);
///将fragment绑定到activity
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
////添加后发送清理缓存的消息
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

一个场景:通过Glide加载两张图片并设置到两个ImageView上。

Glide.with(this).load(imageUrl1).into(imageView1);//msg1
Glide.with(this).load(imageUrl2).into(imageView2);//msg2

执行到getRequestManagerFragment这个方法时,会通过开启事务的方式绑定fragment到activity,绑定操作最终是通过主线程的handler发送消息处理的,Handler中的消息时按照顺序执行的。如果不把msg1构建的RequestManagerFragment放到pendingRequestManagerFragments中,那么在执行msg2的时候会重新创建一个重复的fragment并add。最后发消息清理缓存(避免内存泄漏和减少内存压力),因为消息是按照顺序执行的,执行清理缓存的时候msg1和msg2已经执行完毕。

Glide如何监听网络变化?

在构建RequestManager的时候通过lifecycle.addListener(connectivityMonitor);添加网络变化的监听 ,Fragment生命周期的变化会通知到默认实现类DefaultConnectivityMonitor中对应的方法。在onStart中registerReceiver(注册监听手机网络变化的广播), 在onStop中unregisterReceiver。有网络重连后重启请求。

/** Uses {@link android.net.ConnectivityManager} to identify connectivity changes. */
final class DefaultConnectivityMonitor implements ConnectivityMonitor {
  private static final String TAG = "ConnectivityMonitor";
  private final Context context;

  @SuppressWarnings("WeakerAccess")
  @Synthetic
  final ConnectivityListener listener;

  @SuppressWarnings("WeakerAccess")
  @Synthetic
  boolean isConnected;

  private boolean isRegistered;

  private final BroadcastReceiver connectivityReceiver =
      new BroadcastReceiver() {
        @Override
        public void onReceive(@NonNull Context context, Intent intent) {
          boolean wasConnected = isConnected;
          isConnected = isConnected(context);
          if (wasConnected != isConnected) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
              Log.d(TAG, "connectivity changed, isConnected: " + isConnected);
            }

            listener.onConnectivityChanged(isConnected);
          }
        }
      };

  DefaultConnectivityMonitor(@NonNull Context context, @NonNull ConnectivityListener listener) {
    this.context = context.getApplicationContext();
    this.listener = listener;
  }

  private void register() {
    if (isRegistered) {
      return;
    }

    // Initialize isConnected.
    isConnected = isConnected(context);
    try {
      // See #1405
      context.registerReceiver(
          connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
      isRegistered = true;
    } catch (SecurityException e) {
      // See #1417, registering the receiver can throw SecurityException.
      if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(TAG, "Failed to register", e);
      }
    }
  }

  private void unregister() {
    if (!isRegistered) {
      return;
    }

    context.unregisterReceiver(connectivityReceiver);
    isRegistered = false;
  }

  @SuppressWarnings("WeakerAccess")
  @Synthetic
  // Permissions are checked in the factory instead.
  @SuppressLint("MissingPermission")
  boolean isConnected(@NonNull Context context) {
    ConnectivityManager connectivityManager =
        Preconditions.checkNotNull(
            (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
    NetworkInfo networkInfo;
    try {
      networkInfo = connectivityManager.getActiveNetworkInfo();
    } catch (RuntimeException e) {
      // #1405 shows that this throws a SecurityException.
      // b/70869360 shows that this throws NullPointerException on APIs 22, 23, and 24.
      // b/70869360 also shows that this throws RuntimeException on API 24 and 25.
      if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(TAG, "Failed to determine connectivity status when connectivity changed", e);
      }
      // Default to true;
      return true;
    }
    return networkInfo != null && networkInfo.isConnected();
  }

  @Override
  public void onStart() {
    register();
  }

  @Override
  public void onStop() {
    unregister();
  }

  @Override
  public void onDestroy() {
    // Do nothing.
  }
}

回调ConnectivityListener的onConnectivityChanged来处理请求

 private class RequestManagerConnectivityListener
      implements ConnectivityMonitor.ConnectivityListener {
    @GuardedBy("RequestManager.this")
    private final RequestTracker requestTracker;

    RequestManagerConnectivityListener(@NonNull RequestTracker requestTracker) {
      this.requestTracker = requestTracker;
    }

    @Override
    public void onConnectivityChanged(boolean isConnected) {
      if (isConnected) {
        synchronized (RequestManager.this) {
          //网络重连后重启请求
          requestTracker.restartRequests();
        }
      }
    }
  }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容