本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/73252999
Glide.with(this).load(url).into(imageview);
看下.with(this)
做了什么
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
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);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
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);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm); // ←←←
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
先调用Util.isOnMainThread()
判断是否在主线程
public static boolean isOnMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
- 判断是否在主线程,原来是通过判断是否是主线程的Looper来判断的
assertNotDestroyed(activity)
断言Activity还没有Destroy, 然后调用activity.getFragmentManager()
获得一个FragmentManager调用getRequestManagerFragment(fm)
获得RequestManagerFragment
, 这个其实是一个用于实现生命周期管理的Fragment, 通过Fragment的回调管理RequestManager
public class RequestManagerFragment extends Fragment {
@SuppressLint("ValidFragment")
RequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
}
可见RequestManager
实现了LifecycleListener
public class RequestManager implements LifecycleListener {
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;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();
ConnectivityMonitor connectivityMonitor = factory.build(context,
new RequestManagerConnectivityListener(requestTracker));
// If we're the application level request manager, we may be created on a background thread. In that case we
// cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
// ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
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);
}
@Override
public void onStart() {
// onStart might not be called because this object may be created after the fragment/activity's onStart method.
resumeRequests();
}
@Override
public void onStop() {
pauseRequests();
}
@Override
public void onDestroy() {
requestTracker.clearRequests();
}
}
上面我们得到了RequestManager
的对象,接着调用.load(url)
public DrawableTypeRequest load(String string) {
return (DrawableTypeRequest) fromString().load(string);
}
@Override
public DrawableRequestBuilder load(ModelType model) {
super.load(model);
return this;
}
public GenericRequestBuilder load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
GenericRequestBuilder
初始化值, 并返回了DrawableRequestBuilder
接着看.into(imageview)
@Override
public Target into(ImageView view) {
return super.into(view);
}
public > Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
// ↓↓↓
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
// ↓↓↓
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}
Request previous = target.getRequest()
获取就的Request,如果有就删除他, 然后(buildRequest(target)
)构建新的Request, 进行绑定与(requestTracker.runRequest(request)
)发起请求, 并返回TargetrequestTracker.runRequest(request)
是如何执行的呢?
public class RequestTracker {
private final Set requests = Collections.newSetFromMap(new WeakHashMap());
private final List pendingRequests = new ArrayList();
private boolean isPaused;
public void runRequest(Request request) {
requests.add(request); // ←←←
if (!isPaused) {
request.begin(); // ←←←
} else {
pendingRequests.add(request);
}
}
}
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback, ResourceCallback {
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight); // ←←←
} else {
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable()); // ←←←
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING; // ←←←
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader modelLoader = loadProvider.getModelLoader();
final DataFetcher dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
// ↓↓↓
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
}
Status.WAITING_FOR_SIZE
,并调用onSizeReady(overrideWidth, overrideHeight)
将状态改为Status.RUNNING
,计算了一个四舍五入的宽高,然后将engine.load()发起了请求loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
里做了什么?
priority, isMemoryCacheable, diskCacheStrategy, this);
public LoadStatus load(Key signature, int width, int height, DataFetcher fetcher,
DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
EngineResource> cached = loadFromCache(key, isMemoryCacheable); // ←←←
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable); // ←←←
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob decodeJob = new DecodeJob(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
EngineResource> cached = loadFromCache(key, isMemoryCacheable)
他会先去缓存(内存缓存)里找资源
private EngineResource> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource> cached = getEngineResourceFromCache(key); // ←←←
if (cached != null) {
cached.acquire();
activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
}
return cached;
}
private static class ResourceWeakReference extends WeakReference<EngineResource>> {
private final Key key;
public ResourceWeakReference(Key key, EngineResource> r, ReferenceQueue super EngineResource>> q) {
super(r, q);
this.key = key;
}
}
private EngineResource> getEngineResourceFromCache(Key key) {
Resource> cached = cache.remove(key); // ←←←
final EngineResource result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource) cached;
} else {
result = new EngineResource(cached, true /*isCacheable*/);
}
return result;
}
public class LruCache<T, Y> {
private final LinkedHashMap cache = new LinkedHashMap(100, 0.75f, true);
public Y remove(T key) {
final Y value = cache.remove(key);
if (value != null) {
currentSize -= getSize(value);
}
return value;
}
}
- 如果`getEngineResourceFromCache(key)`找到资源,则该资源会被用`WeakReference`(弱引用)一层,然后添加到activeResources
- 调用`Resource> cached = cache.remove(key)`获取的资源是从LruCache获取的
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);
找不到的话,在到Active里找资源
private EngineResource> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource> active = null;
WeakReference> activeRef = activeResources.get(key);
if (activeRef != null) {
active = activeRef.get();
if (active != null) {
active.acquire();
} else {
activeResources.remove(key);
}
}
return active;
}
getEngineResourceFromCache(key)
向activeResources
(弱引用资源)添加的资源还在吗?如果已经被回收了,就删除key,然后返回资源EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable)
如果内存和弱引用集合都没有就创建EngineJob, EngineJob有diskCacheService和sourceService两个线程池
class EngineJob implements EngineRunnable.EngineRunnableManager {
private final Key key;
private final ExecutorService diskCacheService;
private final ExecutorService sourceService;
public EngineJob(Key key, ExecutorService diskCacheService, ExecutorService sourceService, boolean isCacheable,
EngineJobListener listener) {
this(key, diskCacheService, sourceService, isCacheable, listener, DEFAULT_FACTORY);
}
public void start(EngineRunnable engineRunnable) {
this.engineRunnable = engineRunnable;
future = diskCacheService.submit(engineRunnable); // ←←←
}
}
class EngineRunnable implements Runnable, Prioritized {
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource> resource = null;
try {
resource = decode(); // ←←←
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception); // ←←←
} else {
onLoadComplete(resource); // ←←←
}
}
private Resource> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache(); // ←←←
} else {
return decodeFromSource(); // ←←←
}
}
private boolean isDecodingFromCache() {
return stage == Stage.CACHE;
}
private Resource> decodeFromCache() throws Exception {
Resource> result = null;
try {
result = decodeJob.decodeResultFromCache(); // ←←←
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Exception decoding result from cache: " + e);
}
}
if (result == null) {
result = decodeJob.decodeSourceFromCache(); // ←←←
}
return result;
}
}
result = decodeJob.decodeResultFromCache()
从处理过的资源磁盘缓存找, 没有找到, 则result = decodeJob.decodeSourceFromCache()
在从原图磁盘缓存找如果都没找到, 则执行onLoadFailed(exception)
private void onLoadFailed(Exception e) {
if (isDecodingFromCache()) {
stage = Stage.SOURCE;
manager.submitForSource(this);
} else {
manager.onException(e);
}
}
@Override
public void submitForSource(EngineRunnable runnable) {
future = sourceService.submit(runnable);
}
sourceService
线程池中并执行状态从Stage.CACHE
变为了Stage.SOURCE
, 于是decode()里执行decodeFromSource()
class DecodeJob {
private Resource> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
public Resource decodeFromSource() throws Exception {
Resource decoded = decodeSource(); // ←←←
return transformEncodeAndTranscode(decoded); // ←←←
}
private Resource decodeSource() throws Exception {
Resource decoded = null;
try {
long startTime = LogTime.getLogTime();
final A data = fetcher.loadData(priority); // ←←←
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data); // ←←←
} finally {
fetcher.cleanup();
}
return decoded;
}
private Resource decodeFromSourceData(A data) throws IOException {
final Resource decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data); // ←←←
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
private Resource cacheAndDecodeSourceData(A data) throws IOException {
long startTime = LogTime.getLogTime();
SourceWriter writer = new SourceWriter(loadProvider.getSourceEncoder(), data); // ←←←
diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer); // ←←←
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Wrote source to cache", startTime);
}
startTime = LogTime.getLogTime();
Resource result = loadFromCache(resultKey.getOriginalKey());
if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
logWithTimeAndKey("Decoded source from cache", startTime);
}
return result;
}
private Resource transformEncodeAndTranscode(Resource decoded) {
long startTime = LogTime.getLogTime();
Resource transformed = transform(decoded); // ←←←
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transformed resource from source", startTime);
}
writeTransformedToCache(transformed); // ←←←
startTime = LogTime.getLogTime();
Resource result = transcode(transformed); // ←←←
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Transcoded transformed from source", startTime);
}
return result;
}
}
public class HttpUrlFetcher implements DataFetcher<InputStream> {
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map headers)
throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new IOException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(2500);
urlConnection.setReadTimeout(2500);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (statusCode / 100 == 2) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (statusCode / 100 == 3) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new IOException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else {
if (statusCode == -1) {
throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
}
throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
}
}
}
Resource decoded = decodeSource()
进行获取数据,然后执行transformEncodeAndTranscode(decoded)
进行处理数据:Resource transformed = transform(decoded)
剪裁,writeTransformedToCache(transformed)
写入磁盘,Resource result = transcode(transformed)
转码decodeSource()
里会执行final A data = fetcher.loadData(priority)
来获取数据,然后执行decoded = decodeFromSourceData(data)
来解析并保存数据fetcher.loadData(priority)
代码,我们发现原来是用urlConnection发起的网络请求decodeFromSourceData(data)
, 执行了decoded = cacheAndDecodeSourceData(data)
将图片资源保存到磁盘在来看看onLoadComplete(resource);
做了什么?
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
class EngineJob implements EngineRunnable.EngineRunnableManager {
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
@Override
public void onResourceReady(final Resource> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget(); // ←←←
}
}
可见是用Handler发了一个消息, 那么接着看看消息是怎么处理的
private static class MainThreadCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message message) {
if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
EngineJob job = (EngineJob) message.obj;
if (MSG_COMPLETE == message.what) {
job.handleResultOnMainThread(); // ←←←
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
// synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource); // ←←←
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
}
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource> resource) {
if (resource == null) {
onException(new Exception("Expected to receive a Resource with an object of " + transcodeClass
+ " inside, but instead got null."));
return;
}
Object received = resource.get(); // ←←←
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
onException(new Exception("Expected to receive an object of " + transcodeClass
+ " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
+ " inside Resource{" + resource + "}."
+ (received != null ? "" : " "
+ "To indicate failure return a null Resource object, "
+ "rather than a Resource object containing null data.")
));
return;
}
if (!canSetResource()) {
releaseResource(resource);
// We can't set the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
onResourceReady(resource, (R) received); // ←←←
}
private void onResourceReady(Resource> resource, R result) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstResource)) {
GlideAnimation animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
target.onResourceReady(result, animation); // ←←←
}
notifyLoadSuccess();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
+ (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
}
}
@Override
public void onResourceReady(Z resource, GlideAnimation super Z> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource); // ←←←
}
}
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource); // ←←←
}
XXX管理的代码
package me.luzhuo.glidedemo.other.lifecycle;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import me.luzhuo.glidedemo.other.lifecycle.inter.Lifecycle;
import me.luzhuo.glidedemo.other.lifecycle.inter.LifecycleListener;
public class Manager implements LifecycleListener {
private final String TAG = Manager.class.getSimpleName();
private final Context context;
private final Lifecycle lifecycle;
public Manager(Context context, final Lifecycle lifecycle) {
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
if (!Utils.isOnMainThread()) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
lifecycle.addListener(Manager.this);
}
});
} else {
lifecycle.addListener(this);
}
}
public static Manager with(Context context) {
ManagerRetriever retriever = ManagerRetriever.get();
return retriever.get(context);
}
@Override
public void onStart() {
Log.e(TAG, "Manager 将开始工作");
}
@Override
public void onStop() {
Log.e(TAG, "Manager 将暂停工作");
}
@Override
public void onDestroy() {
Log.e(TAG, "Manager 将停止工作");
}
}
ManagerRetriever主要做的是构建Fragment,并绑定鉴定,这里的代码多,是因为传入Content做相应的Fragment生成和管理
public class ManagerRetriever {
Manager applicationManager;
static final String FRAGMENT_TAG = "me.luzhuo.glidedemo";
private static final ManagerRetriever INSTANCE = new ManagerRetriever();
public static ManagerRetriever get() {
return INSTANCE;
}
public Manager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Utils.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 Manager get(FragmentActivity activity) {
if (!Utils.isOnMainThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return fragmentGet(activity, fm);
}
}
public Manager get(Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (!Utils.isOnMainThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet(fragment.getActivity(), fm);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public Manager get(Activity activity) {
if (!Utils.isOnMainThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet2(activity, fm);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static void assertNotDestroyed(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public Manager 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 (!Utils.isOnMainThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return get(fragment.getActivity().getApplicationContext());
} else {
android.app.FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet2(fragment.getActivity(), fm);
}
}
private Manager getApplicationManager(Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
applicationManager = new Manager(context.getApplicationContext(), getLifecycle);
}
}
}
return applicationManager;
}
Lifecycle getLifecycle = new Lifecycle() {
@Override
public void addListener(LifecycleListener listener) {
listener.onStart();
}
};
Manager fragmentGet(Context context, FragmentManager fm) {
LifecycleFragment current = getManagerFragment(fm);
Manager manager = current.getManager();
if (manager == null) {
manager = new Manager(context, current.getLifecycle());
current.setManager(manager);
}
return manager;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
Manager fragmentGet2(Context context, android.app.FragmentManager fm) {
LifecycleFragment2 current = getManagerFragment2(fm);
Manager manager = current.getManager();
if (manager == null) {
manager = new Manager(context, current.getLifecycle());
current.setManager(manager);
}
return manager;
}
LifecycleFragment getManagerFragment(final FragmentManager fm) {
LifecycleFragment current = (LifecycleFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
if (current == null) {
current = new LifecycleFragment();
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
}
}
return current;
}
LifecycleFragment2 getManagerFragment2(final android.app.FragmentManager fm) {
LifecycleFragment2 current = (LifecycleFragment2) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
if (current == null) {
current = new LifecycleFragment2();
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
}
}
return current;
}
}
Utils就一个isOnMainThread()方法,根据Looper判断是否是主线程
public class Utils {
public static boolean isOnMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
}
有两个Fragment,由于代码一样,仅仅是Fragment的包的引用不同,这里就写一份吧
package me.luzhuo.glidedemo.other.lifecycle.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.support.v4.app.Fragment;
import android.util.Log;
import me.luzhuo.glidedemo.other.lifecycle.Manager;
import me.luzhuo.glidedemo.other.lifecycle.inter.LifecycleImpl;
public class LifecycleFragment extends Fragment{
private static final String TAG = LifecycleFragment.class.getSimpleName();
private Manager manager;
private final LifecycleImpl lifecycle;
public LifecycleFragment() {
this(new LifecycleImpl());
}
// For testing only.
@SuppressLint("ValidFragment")
public LifecycleFragment(LifecycleImpl lifecycle) {
this.lifecycle = lifecycle;
}
public LifecycleImpl getLifecycle() {
return lifecycle;
}
public void setManager(Manager manager) {
this.manager = manager;
}
public Manager getManager() {
return this.manager;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.e(TAG, "onAttach");
}
@Override
public void onDetach() {
super.onDetach();
Log.e(TAG, "onDetach");
}
@Override
public void onStart() {
super.onStart();
Log.e(TAG, "onStart");
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
Log.e(TAG, "onStop");
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
lifecycle.onDestroy();
}
@Override
public void onLowMemory() {
Log.e(TAG, "onLowMemory");
super.onLowMemory();
}
}
接下来是定义的一些接口,和接口的实现
public interface Lifecycle {
void addListener(LifecycleListener listener);
}
public class LifecycleImpl implements Lifecycle {
private final List lifecycleListeners = new ArrayList();
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();
}
}
public void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : lifecycleListeners) {
lifecycleListener.onStart();
}
}
public void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : lifecycleListeners) {
lifecycleListener.onStop();
}
}
public void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : lifecycleListeners) {
lifecycleListener.onDestroy();
}
}
}
public interface LifecycleListener {
void onStart();
void onStop();
void onDestroy();
}
public class LifecycleTestActivity extends AppCompatActivity {
private static final String TAG = "Test";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Manager.with(this);
}
@Override
protected void onStart() {
super.onStart();
Log.e(TAG, "onStart");
}
@Override
protected void onStop() {
super.onStop();
Log.e(TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
}
}
首先看下该数据结构的构造方法
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
private transient LinkedHashMapEntry header;
private final boolean accessOrder;
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
@Override
void init() {
header = new LinkedHashMapEntry<>(-1, null, null, null);
header.before = header.after = header;
}
}
- 我们可以看到有一个`LinkedHashMapEntry header`**头结点**,还有一个布尔类型的`accessOrder`用来控制是否按访问顺序排序
看数据结构,当然必须先把结点理清楚
private static class LinkedHashMapEntry<K,V> extends HashMapEntry<K,V> {
// These fields comprise the doubly linked list used for iteration.
LinkedHashMapEntry before, after;
LinkedHashMapEntry(int hash, K key, V value, HashMapEntry next) {
super(hash, key, value, next);
}
/**
* Removes this entry from the linked list.
*/
private void remove() {
before.after = after;
after.before = before;
}
/**
* Inserts this entry before the specified existing entry in the list.
*/
private void addBefore(LinkedHashMapEntry existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
/**
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered, it moves the entry
* to the end of the list; otherwise, it does nothing.
*/
void recordAccess(HashMap m) {
LinkedHashMap lm = (LinkedHashMap)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}
void recordRemoval(HashMap m) {
remove();
}
}
链式的数据结构基本讲解的差不多了, 接下来简单的讲下 增删查
增加
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMapEntry old = table[bucketIndex];
LinkedHashMapEntry e = new LinkedHashMapEntry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
}
删
public void clear() {
super.clear();
header.before = header.after = header;
}
查(获取)
public V get(Object key) {
LinkedHashMapEntry e = (LinkedHashMapEntry)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
基本使用;
LruCache使用代码:
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.v4.util.LruCache;
import android.util.Log;
public class ImageCache {
// 使用最大可用内存值的1/5作为缓存的大小。
private static final int MAXSIZE = (int) (Runtime.getRuntime().maxMemory() / 5);
private static ImageCache cache = new ImageCache();
public static ImageCache getInstance() {
return cache;
}
// LruCache<标记, 图片>
private LruCache
测试代码:
package me.luzhuo.lrucachedemo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.io.File;
import me.luzhuo.lrucachedemo.utils.ImageCache;
import static android.R.attr.bitmap;
import static android.R.attr.key;
public class MainActivity extends AppCompatActivity {
private ListView listview;
private int key;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 添加到内存缓存
Bitmap bitmap = BitmapFactory.decodeFile(new File(Environment.getExternalStorageDirectory(),"abc.jpg").getPath());
// hashcode的计算方法
key = bitmap.hashCode();
key = 31 * key + MainActivity.class.getSimpleName().hashCode();
ImageCache.getInstance().put(key, bitmap);
initView();
initData();
}
private void initView() {
listview = (ListView) findViewById(R.id.listView);
}
private void initData() {
listview.setAdapter(new ImageAdapter());
}
class ImageAdapter extends BaseAdapter {
@Override
public int getCount() {
return 100;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
class ViewHodler{
TextView textview;
ImageView imageview;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHodler viewHodler;
if(convertView==null){
viewHodler = new ViewHodler();
convertView = View.inflate(MainActivity.this, R.layout.item, null);
viewHodler.textview = (TextView) convertView.findViewById(R.id.textview);
viewHodler.imageview = (ImageView) convertView.findViewById(R.id.imageview);
convertView.setTag(viewHodler);
}else{
viewHodler = (ViewHodler) convertView.getTag();
}
viewHodler.textview.setText("第"+position+"张");
// 从内存缓存获取数据
Bitmap bitmap = ImageCache.getInstance().get(key);
viewHodler.imageview.setImageBitmap(bitmap);
return convertView;
}
}
}
源码解析:
首先看下构造方法
public class LruCache<K, V> {
private final LinkedHashMap map;
/** Size of this cache in units. Not necessarily the number of elements. */
private int size;
private int maxSize;
private int putCount;
private int createCount;
private int evictionCount;
private int hitCount;
private int missCount;
/**
* @param maxSize for caches that do not override {@link #sizeOf}, this is
* the maximum number of entries in the cache. For all other caches,
* this is the maximum sum of the sizes of the entries in this cache.
*/
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap(0, 0.75f, true);
}
}
maxSize
用于限制资源最大的可使用内存, 用LinkedHashMap map
来存储资源,并且要求LinkedHashMap访问记录接着看下添加资源的方法
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);
return previous;
}
可见添加资源时,会回调safeSizeOf(key, value)
获取该资源的大小,然后加到size, 然后调用LinkedHashMap的put()方法添加资源,返回previous
在LinkedHashMap中没有put()方法,看来是调用了HashMap的put()方法
public V put(K key, V value) {
// ...
for (HashMapEntry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
调用HashMap的put(),如果这个key已经存在则返回旧元素,否则会调用addEntry()添加元素,然后返回null
void addEntry(int hash, K key, V value, int bucketIndex) {
// ...
createEntry(hash, key, value, bucketIndex);
}
然后会调用LinkedHashMap中的createEntry()方法,因为LinkedHashMap重写了该方法,该方法创建了一个结点,并将其添加到链表末尾
我们继续往下看,如果previous返回不为null,说明这个元素存在,调用了size -= safeSizeOf(key, previous)
,把加上的资源大小减掉
entryRemoved(false, key, previous, value)
告知该资源没有添加到LruCache里,第一个boolean值表示该资源是否是因为超过限制而被移除,false表示不是,true表示是内存不足而删除.然后调用trimToSize(maxSize)
,我们看下做了什么
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize || map.isEmpty()) {
break;
}
Map.Entry toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
size <= maxSize || map.isEmpty()
为止,删除数据是从LinkedHashMap第一个数据开始删的,因为被访问的元素都在链表末尾,第一个元素恰恰是最少被访问的然后在看下获取资源的方法
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
// ...
}
清空缓存
public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}