add resId to cache DoricResource on native

This commit is contained in:
pengfei.zhou 2021-11-18 17:39:01 +08:00 committed by osborn
parent d746c5b4d4
commit 5b80e4e0e1
17 changed files with 107 additions and 23 deletions

View File

@ -29,6 +29,7 @@ import pub.doric.performance.DoricPerformanceProfile;
import pub.doric.plugin.AnimatePlugin; import pub.doric.plugin.AnimatePlugin;
import pub.doric.plugin.CoordinatorPlugin; import pub.doric.plugin.CoordinatorPlugin;
import pub.doric.plugin.DoricJavaPlugin; import pub.doric.plugin.DoricJavaPlugin;
import pub.doric.plugin.ImageDecoderPlugin;
import pub.doric.plugin.KeyboardPlugin; import pub.doric.plugin.KeyboardPlugin;
import pub.doric.plugin.ModalPlugin; import pub.doric.plugin.ModalPlugin;
import pub.doric.plugin.NavBarPlugin; import pub.doric.plugin.NavBarPlugin;
@ -114,6 +115,7 @@ public class DoricRegistry {
this.registerNativePlugin(NotchPlugin.class); this.registerNativePlugin(NotchPlugin.class);
this.registerNativePlugin(KeyboardPlugin.class); this.registerNativePlugin(KeyboardPlugin.class);
this.registerNativePlugin(ResourceLoaderPlugin.class); this.registerNativePlugin(ResourceLoaderPlugin.class);
this.registerNativePlugin(ImageDecoderPlugin.class);
this.registerViewNode(RootNode.class); this.registerViewNode(RootNode.class);
this.registerViewNode(TextNode.class); this.registerViewNode(TextNode.class);

View File

@ -15,10 +15,12 @@
*/ */
package pub.doric.plugin; package pub.doric.plugin;
import com.bumptech.glide.Glide;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JavaValue; import com.github.pengfeizhou.jscore.JavaValue;
import java.util.HashMap;
import java.util.Map;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.async.AsyncResult; import pub.doric.async.AsyncResult;
import pub.doric.extension.bridge.DoricMethod; import pub.doric.extension.bridge.DoricMethod;
@ -34,6 +36,7 @@ import pub.doric.utils.DoricLog;
*/ */
@DoricPlugin(name = "resourceLoader") @DoricPlugin(name = "resourceLoader")
public class ResourceLoaderPlugin extends DoricJavaPlugin { public class ResourceLoaderPlugin extends DoricJavaPlugin {
private Map<String, DoricResource> cachedResources = new HashMap<>();
public ResourceLoaderPlugin(DoricContext doricContext) { public ResourceLoaderPlugin(DoricContext doricContext) {
super(doricContext); super(doricContext);
@ -41,11 +44,16 @@ public class ResourceLoaderPlugin extends DoricJavaPlugin {
@DoricMethod @DoricMethod
public void load(JSObject resource, final DoricPromise promise) { public void load(JSObject resource, final DoricPromise promise) {
final String resId = resource.getProperty("resId").asString().value();
final String type = resource.getProperty("type").asString().value(); final String type = resource.getProperty("type").asString().value();
final String identifier = resource.getProperty("identifier").asString().value(); final String identifier = resource.getProperty("identifier").asString().value();
DoricResource doricResource = getDoricContext().getDriver().getRegistry().getResourceManager().load(getDoricContext(), type, identifier); DoricResource doricResource = getDoricContext().getDriver().getRegistry().getResourceManager().load(
getDoricContext(),
resId,
type,
identifier);
if (doricResource != null) { if (doricResource != null) {
doricResource.fetchRaw().setCallback(new AsyncResult.Callback<byte[]>() { doricResource.fetch().setCallback(new AsyncResult.Callback<byte[]>() {
@Override @Override
public void onResult(byte[] rawData) { public void onResult(byte[] rawData) {
promise.resolve(new JavaValue(rawData)); promise.resolve(new JavaValue(rawData));

View File

@ -26,6 +26,7 @@ import pub.doric.async.AsyncResult;
public abstract class DoricResource { public abstract class DoricResource {
protected final DoricContext doricContext; protected final DoricContext doricContext;
protected final String identifier; protected final String identifier;
private AsyncResult<byte[]> rawResult;
public DoricResource(DoricContext doricContext, String identifier) { public DoricResource(DoricContext doricContext, String identifier) {
this.doricContext = doricContext; this.doricContext = doricContext;
@ -33,4 +34,11 @@ public abstract class DoricResource {
} }
public abstract AsyncResult<byte[]> fetchRaw(); public abstract AsyncResult<byte[]> fetchRaw();
public AsyncResult<byte[]> fetch() {
if (rawResult == null) {
rawResult = fetchRaw();
}
return rawResult;
}
} }

View File

@ -17,6 +17,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 androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -29,6 +30,7 @@ import pub.doric.DoricContext;
*/ */
public class DoricResourceManager { 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<>();
public void registerLoader(DoricResourceLoader loader) { public void registerLoader(DoricResourceLoader loader) {
mResourceLoaders.put(loader.resourceType(), loader); mResourceLoaders.put(loader.resourceType(), loader);
@ -39,11 +41,18 @@ public class DoricResourceManager {
} }
@Nullable @Nullable
public DoricResource load(@NonNull DoricContext doricContext, @NonNull String type, @NonNull String identifier) { public DoricResource load(@NonNull DoricContext doricContext,
DoricResourceLoader loader = mResourceLoaders.get(type); @NonNull String resId,
if (loader != null) { @NonNull String type,
return loader.load(doricContext, identifier); @NonNull String identifier) {
DoricResource resource = cachedResources.get(resId);
if (resource == null) {
DoricResourceLoader loader = mResourceLoaders.get(type);
if (loader != null) {
resource = loader.load(doricContext, identifier);
cachedResources.put(resId, resource);
}
} }
return null; return resource;
} }
} }

View File

@ -397,11 +397,13 @@ public class ImageNode extends ViewNode<ImageView> {
return; return;
} }
JSObject resource = prop.asObject(); JSObject resource = prop.asObject();
final String resourceId = resource.getProperty("resId").asString().value();
final String type = resource.getProperty("type").asString().value(); final String type = resource.getProperty("type").asString().value();
final String identifier = resource.getProperty("identifier").asString().value(); final String identifier = resource.getProperty("identifier").asString().value();
DoricResource doricResource = getDoricContext().getDriver().getRegistry().getResourceManager().load(getDoricContext(), type, identifier); DoricResource doricResource = getDoricContext().getDriver().getRegistry().getResourceManager()
.load(getDoricContext(), resourceId, type, identifier);
if (doricResource != null) { if (doricResource != null) {
doricResource.fetchRaw().setCallback(new AsyncResult.Callback<byte[]>() { doricResource.fetch().setCallback(new AsyncResult.Callback<byte[]>() {
@Override @Override
public void onResult(byte[] imageData) { public void onResult(byte[] imageData) {
loadIntoTarget(Glide.with(getContext()).load(imageData)); loadIntoTarget(Glide.with(getContext()).load(imageData));

View File

@ -2145,11 +2145,13 @@ var __extends$f = (undefined && undefined.__extends) || (function () {
})(); })();
var Resource = /** @class */ (function () { var Resource = /** @class */ (function () {
function Resource(type, identifier) { function Resource(type, identifier) {
this.resId = uniqueId("resource");
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
} }
Resource.prototype.toModel = function () { Resource.prototype.toModel = function () {
return { return {
resId: this.resId,
type: this.type, type: this.type,
identifier: this.identifier, identifier: this.identifier,
}; };

View File

@ -1610,11 +1610,13 @@ function text(config) {
class Resource { class Resource {
constructor(type, identifier) { constructor(type, identifier) {
this.resId = uniqueId("resource");
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
} }
toModel() { toModel() {
return { return {
resId: this.resId,
type: this.type, type: this.type,
identifier: this.identifier, identifier: this.identifier,
}; };

View File

@ -3138,11 +3138,13 @@ function text(config) {
class Resource { class Resource {
constructor(type, identifier) { constructor(type, identifier) {
this.resId = uniqueId("resource");
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
} }
toModel() { toModel() {
return { return {
resId: this.resId,
type: this.type, type: this.type,
identifier: this.identifier, identifier: this.identifier,
}; };

2
doric-js/index.d.ts vendored
View File

@ -1688,8 +1688,10 @@ declare module 'doric/lib/src/util/resource' {
export abstract class Resource implements Modeling { export abstract class Resource implements Modeling {
type: string; type: string;
identifier: string; identifier: string;
resId: string;
constructor(type: string, identifier: string); constructor(type: string, identifier: string);
toModel(): { toModel(): {
resId: string;
type: string; type: string;
identifier: string; identifier: string;
}; };

View File

@ -1,6 +1,9 @@
import { Resource } from "../util/resource"; import { Resource } from "../util/resource";
import { BridgeContext } from "../runtime/global"; import { BridgeContext } from "../runtime/global";
export declare function imageDecoder(context: BridgeContext): { export declare function imageDecoder(context: BridgeContext): {
getBitmapInfo: (resource: Resource) => Promise<ArrayBuffer>; decode: (resource: Resource) => Promise<{
decodeToPixels: (resource: Resource) => Promise<ArrayBuffer>; width: number;
height: number;
format: string;
}>;
}; };

View File

@ -13,13 +13,23 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
export function imageDecoder(context) { export function imageDecoder(context) {
return { return {
getBitmapInfo: (resource) => { decode: (resource) => __awaiter(this, void 0, void 0, function* () {
return context.callNative('imageDecoder', 'getBitmapInfo', resource); yield context.callNative('imageDecoder', 'loadResource', resource);
}, const imageInfo = yield context.callNative('imageDecoder', 'getImageInfo', resource.resId);
decodeToPixels: (resource) => { const pixels = yield context.callNative('imageDecoder', 'decodeToPixels', resource.resId);
return context.callNative('imageDecoder', 'decode', resource); yield context.callNative('imageDecoder', 'releaseResource', resource.resId);
}, return Object.assign(Object.assign({}, imageInfo), { pixels });
}),
}; };
} }

View File

@ -2,8 +2,10 @@ import { Modeling } from "./types";
export declare abstract class Resource implements Modeling { export declare abstract class Resource implements Modeling {
type: string; type: string;
identifier: string; identifier: string;
resId: string;
constructor(type: string, identifier: string); constructor(type: string, identifier: string);
toModel(): { toModel(): {
resId: string;
type: string; type: string;
identifier: string; identifier: string;
}; };

View File

@ -1,10 +1,13 @@
import { uniqueId } from "./uniqueId";
export class Resource { export class Resource {
constructor(type, identifier) { constructor(type, identifier) {
this.resId = uniqueId("resource");
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
} }
toModel() { toModel() {
return { return {
resId: this.resId,
type: this.type, type: this.type,
identifier: this.identifier, identifier: this.identifier,
}; };

View File

@ -19,11 +19,26 @@ import { BridgeContext } from "../runtime/global"
export function imageDecoder(context: BridgeContext) { export function imageDecoder(context: BridgeContext) {
return { return {
getBitmapInfo: (resource: Resource) => { decode: async (resource: Resource) => {
return context.callNative('imageDecoder', 'getBitmapInfo', resource) as Promise<ArrayBuffer> await context.callNative('imageDecoder', 'loadResource', resource);
}, const imageInfo = await context.callNative(
decodeToPixels: (resource: Resource) => { 'imageDecoder',
return context.callNative('imageDecoder', 'decode', resource) as Promise<ArrayBuffer> 'getImageInfo',
resource.resId) as Promise<
{
width: number,
height: number,
format: string,
}>;
const pixels = await context.callNative(
'imageDecoder',
'decodeToPixels',
resource.resId) as Promise<ArrayBuffer>;
await context.callNative('imageDecoder', 'releaseResource', resource.resId);
return {
...imageInfo,
pixels,
};
}, },
} }
} }

View File

@ -1,14 +1,17 @@
import { Modeling } from "./types"; import { Modeling } from "./types";
import { uniqueId } from "./uniqueId";
export abstract class Resource implements Modeling { export abstract class Resource implements Modeling {
type: string; type: string;
identifier: string; identifier: string;
resId = uniqueId("resource");
constructor(type: string, identifier: string) { constructor(type: string, identifier: string) {
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
} }
toModel() { toModel() {
return { return {
resId: this.resId,
type: this.type, type: this.type,
identifier: this.identifier, identifier: this.identifier,
} }

View File

@ -3212,11 +3212,13 @@ function text(config) {
class Resource { class Resource {
constructor(type, identifier) { constructor(type, identifier) {
this.resId = uniqueId("resource");
this.type = type; this.type = type;
this.identifier = identifier; this.identifier = identifier;
} }
toModel() { toModel() {
return { return {
resId: this.resId,
type: this.type, type: this.type,
identifier: this.identifier, identifier: this.identifier,
}; };

File diff suppressed because one or more lines are too long