feat: add Resource Cache for loading the same resource
This commit is contained in:
		| @@ -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); | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user