feat: add Resource Cache for loading the same resource

This commit is contained in:
pengfei.zhou 2021-11-18 18:15:36 +08:00 committed by osborn
parent 5b80e4e0e1
commit 3bedd8034c
4 changed files with 38 additions and 13 deletions

View File

@ -18,6 +18,7 @@ package pub.doric.resource;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -32,19 +33,19 @@ public class DoricResourceManager {
private final Map<String, DoricResourceLoader> mResourceLoaders = new HashMap<>(); private final Map<String, DoricResourceLoader> mResourceLoaders = new HashMap<>();
private final Map<String, DoricResource> cachedResources = new WeakHashMap<>(); private final Map<String, DoricResource> cachedResources = new WeakHashMap<>();
public void registerLoader(DoricResourceLoader loader) { public synchronized void registerLoader(DoricResourceLoader loader) {
mResourceLoaders.put(loader.resourceType(), loader); mResourceLoaders.put(loader.resourceType(), loader);
} }
public void unRegisterLoader(DoricResourceLoader loader) { public synchronized void unRegisterLoader(DoricResourceLoader loader) {
mResourceLoaders.remove(loader.resourceType()); mResourceLoaders.remove(loader.resourceType());
} }
@Nullable @Nullable
public DoricResource load(@NonNull DoricContext doricContext, public synchronized DoricResource load(@NonNull DoricContext doricContext,
@NonNull String resId, @NonNull String resId,
@NonNull String type, @NonNull String type,
@NonNull String identifier) { @NonNull String identifier) {
DoricResource resource = cachedResources.get(resId); DoricResource resource = cachedResources.get(resId);
if (resource == null) { if (resource == null) {
DoricResourceLoader loader = mResourceLoaders.get(type); DoricResourceLoader loader = mResourceLoaders.get(type);

View File

@ -25,7 +25,8 @@
- (void)unRegisterLoader:(id <DoricResourceLoader>)loader; - (void)unRegisterLoader:(id <DoricResourceLoader>)loader;
- (__kindof DoricResource *)load:(NSString *)identifier - (__kindof DoricResource *)load:(NSString *)resId
withIdentifier:(NSString *)identifier
withResourceType:(NSString *)resourceType withResourceType:(NSString *)resourceType
withContext:(DoricContext *)context; withContext:(DoricContext *)context;
@end @end

View File

@ -21,29 +21,48 @@
@interface DoricResourceManager () @interface DoricResourceManager ()
@property(nonatomic, strong) NSMutableDictionary <NSString *, id <DoricResourceLoader>> *loaders; @property(nonatomic, strong) NSMutableDictionary <NSString *, id <DoricResourceLoader>> *loaders;
@property(nonatomic, strong) NSMapTable <NSString *, __kindof DoricResource *> *cachedResources;
@property(nonatomic, strong) dispatch_queue_t mapQueue;
@end @end
@implementation DoricResourceManager @implementation DoricResourceManager
- (instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
_loaders = [NSMutableDictionary new]; _loaders = [NSMutableDictionary new];
_mapQueue = dispatch_queue_create("doric.resource", DISPATCH_QUEUE_SERIAL);
_cachedResources = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsCopyIn
valueOptions:NSPointerFunctionsWeakMemory
capacity:0];
} }
return self; return self;
} }
- (void)registerLoader:(id <DoricResourceLoader>)loader { - (void)registerLoader:(id <DoricResourceLoader>)loader {
self.loaders[loader.resourceType] = loader; dispatch_sync(self.mapQueue, ^{
self.loaders[loader.resourceType] = loader;
});
} }
- (void)unRegisterLoader:(id <DoricResourceLoader>)loader { - (void)unRegisterLoader:(id <DoricResourceLoader>)loader {
[self.loaders removeObjectForKey:loader.resourceType]; dispatch_sync(self.mapQueue, ^{
[self.loaders removeObjectForKey:loader.resourceType];
});
} }
- (__kindof DoricResource *)load:(NSString *)identifier - (__kindof DoricResource *)load:(NSString *)resId
withIdentifier:(NSString *)identifier
withResourceType:(NSString *)resourceType withResourceType:(NSString *)resourceType
withContext:(DoricContext *)context { withContext:(DoricContext *)context {
id <DoricResourceLoader> loader = self.loaders[resourceType]; __block __kindof DoricResource *resource;
return [loader load:identifier withContext:context]; dispatch_sync(self.mapQueue, ^() {
resource = [self.cachedResources objectForKey:resId];
if (!resource) {
id <DoricResourceLoader> loader = self.loaders[resourceType];
resource = [loader load:identifier withContext:context];
[self.cachedResources setObject:resource forKey:resId];
}
});
return resource;
} }
@end @end

View File

@ -238,8 +238,12 @@ - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id
if ([@"image" isEqualToString:name]) { if ([@"image" isEqualToString:name]) {
NSString *type = prop[@"type"]; NSString *type = prop[@"type"];
NSString *identifier = prop[@"identifier"]; NSString *identifier = prop[@"identifier"];
NSString *resId = prop[@"resId"];
DoricAsyncResult <NSData *> *asyncResult = [[self.doricContext.driver.registry.loaderManager DoricAsyncResult <NSData *> *asyncResult = [[self.doricContext.driver.registry.loaderManager
load:identifier withResourceType:type withContext:self.doricContext] fetchRaw]; load:resId
withIdentifier:identifier
withResourceType:type
withContext:self.doricContext] fetchRaw];
[asyncResult setResultCallback:^(NSData *imageData) { [asyncResult setResultCallback:^(NSData *imageData) {
[self.doricContext dispatchToMainQueue:^{ [self.doricContext dispatchToMainQueue:^{
#if DORIC_USE_YYWEBIMAGE #if DORIC_USE_YYWEBIMAGE