前言:好久没写博客了,因为这段时间一直在搞rn,程序员真是一个苦逼的职业啊,被逼着去学习了下React Native,这东西吧,感觉有点原生app开发经验的童鞋上手还是比较容易的,搞前端的就更不用说了~分分钟就上手了,说多了都是泪啊。。。废话不多说了,先上一篇RN实战中用的一些东西,不为别的,就当笔记了,顺便总结一下所学知识,(ps:实战项目是花了点钱去某宝买的视频,这哥们讲的还不错,需要的童鞋可以私聊我,无私奉献,嘿嘿!!~~)http://blog.csdn.net/vv_bug/article/details/54631655
(一)需求分析:
先上一张需求图:
项目中有一个清理缓存的功能,这功能吧很多app都有了,在原生app中清理缓存吧,其实很简单,就是清理一下存储在磁盘的一些图片,然后还有些网络框架有一些网络缓存,(当然,肯定不会把app中所有缓存清掉的,套路都懂得~)在原生app中,想必大家应该很快就可以实现了,但是rn中应该怎么做呢?
(二)实现思路
因为rn的api中根本就没有给我们提供任何清理缓存的方法,所以介于这种状况下,我们肯定是需要去实现原生app方法的(所以我说会原生app开发rn,其实还是很容易的!!),因为我是做Android的,我就以android为例子了。搞过rn的童鞋都知道,android部分网络请求用的是okhttp,图片加载用的是fresco,所以我们的目标就是清理一下okhttp的缓存,跟fresco的缓存就可以了(用过这两个框架的童鞋应该很容易就实现了)。我就直接贴代码了:
1、android中首先创建一个HttpCacheModule.Java的文件:
package cn.reactnative.httpcache;import android.content.Intent;import com.facebook.cache.disk.DiskStorageCache;import com.facebook.cache.disk.FileCache;import com.facebook.drawee.backends.pipeline.Fresco;import com.facebook.imagepipeline.core.ImagePipelineFactory;import com.facebook.react.bridge.Callback;import com.facebook.react.bridge.Promise;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.bridge.ReactContextBaseJavaModule;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.modules.network.OkHttpClientProvider;import okhttp3.Cache;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.ArrayList;public class HttpCacheModule extends ReactContextBaseJavaModule { public HttpCacheModule(ReactApplicationContext context) { super(context); } @Override public String getName() { return "RCTHttpCache"; } /** * Promise相当于一个代理对象,当需要返回值的时候 * promise.resolve(obj);这样js中就可以拿到这个代理对象了,在then方法中会返回 * promise.reject(e);相当于native中报错了,没有拿到返回值,在erro方法中返回erro */ @ReactMethod public void clearCache(Promise promise){ try { Cache cache = OkHttpClientProvider.getOkHttpClient().cache(); if (cache != null) { cache.delete(); } promise.resolve(null); } catch(IOException e){ promise.reject(e); } } /** * 获取okhttp缓存的大小 */ @ReactMethod public void getHttpCacheSize(Promise promise){ try { Cache cache = OkHttpClientProvider.getOkHttpClient().cache(); promise.resolve(cache != null ? ((double)cache.size()) : 0); } catch(IOException e){ promise.reject(e); } } /** * 因为防止fresco还没有初始化的时候,去拿缓存大小的话,这个时候还没有去计算缓存大小 * 所以直接拿磁盘缓存大小可能为0,其源码中有一个方法去通知更新一下获取缓存大小 */ static Method update; private void updateCacheSize(DiskStorageCache cache) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { if (update == null){ update = DiskStorageCache.class.getDeclaredMethod("maybeUpdateFileCacheSize"); update.setAccessible(true); } update.invoke(cache); } @ReactMethod public void getImageCacheSize(Promise promise){ FileCache cache1 = ImagePipelineFactory.getInstance().getMainDiskStorageCache(); long size1 = cache1.getSize(); if (size1 < 0){ try { updateCacheSize((DiskStorageCache)cache1); } catch (Exception e){ promise.reject(e); return; } size1 = cache1.getSize(); } FileCache cache2 = ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache(); long size2 = cache2.getSize(); if (size2 < 0){ try { updateCacheSize((DiskStorageCache)cache2); } catch (Exception e){ promise.reject(e); return; } size2 = cache2.getSize(); } promise.resolve(((double)(size1+size2))); } @ReactMethod public void clearImageCache(Promise promise){ FileCache cache1 = ImagePipelineFactory.getInstance().getMainFileCache(); cache1.clearAll(); FileCache cache2 = ImagePipelineFactory.getInstance().getSmallImageFileCache(); cache2.clearAll(); promise.resolve(null); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
2、我们还需要创建一个HttpCachePackage.java文件,目的就是将我们写的native代码载入到reactnative中,让js调取:
package cn.reactnative.httpcache;import com.facebook.react.ReactPackage;import com.facebook.react.bridge.JavaScriptModule;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.uimanager.ViewManager;import java.util.Arrays;import java.util.Collections;import java.util.List;public class HttpCachePackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { return Arrays.asList(new NativeModule[]{ new HttpCacheModule(reactContext), }); } public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
3、最后在项目的application中注册一下:
package com.businessstore2;import android.app.Application;import com.businessstore2.reactutils.VersionAndroidPackage;import com.facebook.react.ReactApplication;import com.facebook.react.ReactNativeHost;import com.facebook.react.ReactPackage;import com.facebook.react.shell.MainReactPackage;import com.facebook.soloader.SoLoader;import java.util.Arrays;import java.util.List;import cn.reactnative.httpcache.HttpCachePackage;public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override protected boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new VersionAndroidPackage(), new HttpCachePackage() ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); SoLoader.init(this, false); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
好啦!!!android原生代码中就搞定了。。
(二)现在进入iOS模块中(ps:因为ios不懂啊,所以就让同事写了一下,发现ios真是不要太简单啊!!!!)
在项目中添加如下两个文件(不要问我咋弄,我也不懂啊,嘿嘿):
RCTHttpCache.h:
#import <React/RCTBridgeModule.h>@interface RCTHttpCache : NSObject<RCTBridgeModule>@end
RCTHttpCache.m:
#import "RCTHttpCache.h"@implementation RCTHttpCache@synthesize bridge = _bridge;RCT_EXPORT_MODULE(HttpCache);RCT_EXPORT_METHOD(getHttpCacheSize:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject){ NSURLCache *httpCache = [NSURLCache sharedURLCache]; resolve(@([httpCache currentDiskUsage]));}RCT_EXPORT_METHOD(clearCache:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject){ NSURLCache *httpCache = [NSURLCache sharedURLCache]; [httpCache removeAllCachedResponses]; resolve(nil);}RCT_EXPORT_METHOD(getImageCacheSize:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject){ resolve(@0);}RCT_EXPORT_METHOD(clearImageCache:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject){ resolve(nil);}@end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
ok!!!!ios算是搞好了,是不是soeasy啊!!真是苦逼了我们这群android程序员啊!!!
下面说说rn中怎么调用了~~~
(第一步)引入native模块:
var {NativeModules}=require('react-native');
(第二步)调用方法获取返回值
NativeModules.RCTHttpCache.getCacheSize().then((value)=> {/** 对应原生模块中的代码:promise.resolve(((double)(size1+size2)));*/ let size=Math.round((value / 1024 / 1024) * 100) / 100 + 'M'; }, (erro)=> { /** 对应原生中的代码: try(){}catch (Exception e){ promise.reject(e); return; } */ })
**这里解释一下:
(我是这么理解的,可能我理解的有误,也希望大神能指正一下,谢谢啦~!!),android中是直接返回的Promise对象,但是原生跟js交互肯定是耗时操作的,所以我们在js中获取值的时候有点像异步操作了,(当然,我不知道rn底下具体实现方式,但是经过本人断点测试,getCacheSize().then((value)中的value会过一段时间才获取到值,跟js中的渲染感觉不是在同一个线程中,所以也造成了在js中获取promise对象的value的值的时候,需要用像fetch网络请求的方式获取了。。。好吧!!我也就是猜猜,就像官网所说的just do your things!!管它是咋实现的呢~~~~)**
到此,我们的缓存清理模块已经实现了!!!是不是也没有想象中的那么难呢??
但是这里出现了一个问题,也一直困扰着我哈,需求是这样的:
整个app图片:
更多:
底下的四个模块我用的是TabNavigator,用过的童鞋都知道,第一次进入app的时候,TabNavigator就会把四个页面都加载进来,然后就是隐藏谁显示谁了,在rn中我们页面刷新用到的是state这个东西,但是如果我们需要处理view与与之间的数据处理,state就不好管理了,因为我无法在一个页面拿到另外一个页面的state,所以也无法更新另外一个页面的state,那rn中该怎么处理那种频繁的页面与页面之间的数据交互的呢????
就比如这样,我如何在首页点击某个按钮然后调一下获取app缓存的大小的方法,然后把结果显示在更多页面呢?
好吧!!经过大神指点,认识到有redux这么一个东西~~完美的解决了困扰我的这个问题哈!!!