react native在加载大量图片时小伙伴们会发现,内存一路飙升150M-200M那都不是问题,今天就来优化一下内存,降至40M左右。
1:实现一个module
import android.app.ActivityManager; import android.content.Context; import android.os.Build; import android.support.annotation.Nullable; import com.facebook.cache.common.CacheKey; import com.facebook.cache.disk.DiskCacheConfig; import com.facebook.common.internal.AndroidPredicates; import com.facebook.common.internal.Supplier; import com.facebook.common.soloader.SoLoaderShim; import com.facebook.common.util.ByteConstants; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory; import com.facebook.imagepipeline.cache.MemoryCacheParams; import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.facebook.imagepipeline.core.ImagePipelineFactory; import com.facebook.imagepipeline.listener.RequestListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.modules.common.ModuleDataCleaner; import com.facebook.react.modules.fresco.SystraceRequestListener; import com.facebook.react.modules.network.OkHttpClientProvider; import com.facebook.soloader.SoLoader; import java.util.HashSet; import okhttp3.OkHttpClient; public class MyFrescoModule extends ReactContextBaseJavaModule implements ModuleDataCleaner.Cleanable { private @Nullable ImagePipelineConfig mConfig; public MyFrescoModule(ReactApplicationContext reactContext) { this(reactContext, getDefaultConfig(reactContext, null, null)); } public MyFrescoModule(ReactApplicationContext reactContext, RequestListener listener) { this(reactContext, getDefaultConfig(reactContext, listener, null)); } public MyFrescoModule( ReactApplicationContext reactContext, RequestListener listener, DiskCacheConfig diskCacheConfig) { this(reactContext, getDefaultConfig(reactContext, listener, diskCacheConfig)); } public MyFrescoModule(ReactApplicationContext reactContext, ImagePipelineConfig config) { super(reactContext); mConfig = config; } @Override public void initialize() { super.initialize(); // Make sure the SoLoaderShim is configured to use our loader for native libraries. // This code can be removed if using Fresco from Maven rather than from source SoLoaderShim.setHandler(new MyFrescoModule.FrescoHandler()); Context context = getReactApplicationContext().getApplicationContext(); Fresco.initialize(context, mConfig); mConfig = null; } @Override public String getName() { return "FrescoModule"; } @Override public void clearSensitiveData() { // Clear image cache. ImagePipelineFactory imagePipelineFactory = Fresco.getImagePipelineFactory(); imagePipelineFactory.getBitmapMemoryCache().removeAll(AndroidPredicates.True()); imagePipelineFactory.getEncodedMemoryCache().removeAll(AndroidPredicates. True()); } private static ImagePipelineConfig getDefaultConfig( Context context, @Nullable RequestListener listener, @Nullable DiskCacheConfig diskCacheConfig) { HashSet requestListeners = new HashSet<>(); requestListeners.add(new SystraceRequestListener()); if (listener != null) { requestListeners.add(listener); } OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient(); ImagePipelineConfig.Builder builder = OkHttpImagePipelineConfigFactory.newBuilder(context.getApplicationContext(), okHttpClient); builder .setDownsampleEnabled(false) .setRequestListeners(requestListeners); if (diskCacheConfig != null) { builder.setMainDiskCacheConfig(diskCacheConfig); } final int maxCacheSize= getMaxCacheSize(context); builder.setBitmapMemoryCacheParamsSupplier(new Supplier () { @Override public MemoryCacheParams get() { return new MemoryCacheParams(maxCacheSize,100,0,Integer.MAX_VALUE, Integer.MAX_VALUE); } }); return builder.build(); } private static int getMaxCacheSize(Context context) { final ActivityManager activityManager=(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); final int maxMemory = Math.min(activityManager.getMemoryClass() * ByteConstants.MB, Integer.MAX_VALUE); if (maxMemory < 32 * ByteConstants.MB) { return 4 * ByteConstants.MB; } else if (maxMemory < 64 * ByteConstants.MB) { return 6 * ByteConstants.MB; } else { // We don't want to use more ashmem on Gingerbread for now, since it doesn't respond well to // native memory pressure (doesn't throw exceptions, crashes app, crashes phone) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return 8 * ByteConstants.MB; } else { return maxMemory / 4; } } } private static class FrescoHandler implements SoLoaderShim.Handler { @Override public void loadLibrary(String libraryName) { SoLoader.loadLibrary(libraryName); } } }
因为react native在android中使用fresco来加载图片,所以我们自定义自己的fresco来覆盖掉默认的。
2:继承MainReactPackage 实现getNativeMoudules方法 代码如下:
/** * Created by xq on 16/11/11. */ public class RNMainReactPackage extends MainReactPackage { @Override public ListgetNativeModules(ReactApplicationContext context) { return Arrays.asList( new ModuleSpec(AppStateModule.class, new Provider () { @Override public NativeModule get() { return new AppStateModule(context); } }), new ModuleSpec(AsyncStorageModule.class, new Provider () { @Override public NativeModule get() { return new AsyncStorageModule(context); } }), new ModuleSpec(CameraRollManager.class, new Provider () { @Override public NativeModule get() { return new CameraRollManager(context); } }), new ModuleSpec(ClipboardModule.class, new Provider () { @Override public NativeModule get() { return new ClipboardModule(context); } }), new ModuleSpec(DatePickerDialogModule.class, new Provider () { @Override public NativeModule get() { return new DatePickerDialogModule(context); } }), new ModuleSpec(DialogModule.class, new Provider () { @Override public NativeModule get() { return new DialogModule(context); } }), new ModuleSpec(MyFrescoModule.class, new Provider () { @Override public NativeModule get() { return new MyFrescoModule(context); } }), new ModuleSpec(I18nManagerModule.class, new Provider () { @Override public NativeModule get() { return new I18nManagerModule(context); } }), new ModuleSpec(ImageEditingManager.class, new Provider () { @Override public NativeModule get() { return new ImageEditingManager(context); } }), new ModuleSpec(ImageLoaderModule.class, new Provider () { @Override public NativeModule get() { return new ImageLoaderModule(context); } }), new ModuleSpec(ImageStoreManager.class, new Provider () { @Override public NativeModule get() { return new ImageStoreManager(context); } }), new ModuleSpec(IntentModule.class, new Provider () { @Override public NativeModule get() { return new IntentModule(context); } }), new ModuleSpec(LocationModule.class, new Provider () { @Override public NativeModule get() { return new LocationModule(context); } }), new ModuleSpec(NativeAnimatedModule.class, new Provider () { @Override public NativeModule get() { return new NativeAnimatedModule(context); } }), new ModuleSpec(NetworkingModule.class, new Provider () { @Override public NativeModule get() { return new NetworkingModule(context); } }), new ModuleSpec(NetInfoModule.class, new Provider () { @Override public NativeModule get() { return new NetInfoModule(context); } }), new ModuleSpec(PermissionsModule.class, new Provider () { @Override public NativeModule get() { return new PermissionsModule(context); } }), new ModuleSpec(ShareModule.class, new Provider () { @Override public NativeModule get() { return new ShareModule(context); } }), new ModuleSpec(StatusBarModule.class, new Provider () { @Override public NativeModule get() { return new StatusBarModule(context); } }), new ModuleSpec(TimePickerDialogModule.class, new Provider () { @Override public NativeModule get() { return new TimePickerDialogModule(context); } }), new ModuleSpec(ToastModule.class, new Provider () { @Override public NativeModule get() { return new ToastModule(context); } }), new ModuleSpec(VibrationModule.class, new Provider () { @Override public NativeModule get() { return new VibrationModule(context); } }), new ModuleSpec(WebSocketModule.class, new Provider () { @Override public NativeModule get() { return new WebSocketModule(context); } })); } }
3:在mainapplication的getpackages方法里面替换MainReactPackage
@Override protected ListgetPackages() { return Arrays. asList( new RNMainReactPackage(), ); }
4:运行ok. 亲测效果显著。
截图: