React-Native实战之(清理app缓存+Redux合成)

前言:好久没写博客了,因为这段时间一直在搞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";//native代码模块的名字
    }
    /**
     * Promise相当于一个代理对象,当需要返回值的时候
     * promise.resolve(obj);这样js中就可以拿到这个代理对象了,在then方法中会返回
     * promise.reject(e);相当于native中报错了,没有拿到返回值,在erro方法中返回erro
     */
    @ReactMethod
    public void clearCache(Promise promise){
        try {
            //清理okhttp的缓存
            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[]{
                // Modules from third-party
                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()// Add this line
            );
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, /* native exopackage */ 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:

//
//  RCTHttpCache.h
//  RCTHttpCache

#import <React/RCTBridgeModule.h>
@interface RCTHttpCache : NSObject<RCTBridgeModule>

@end

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

RCTHttpCache.m:

//
//  RCTHttpCache.m
//  RCTHttpCache

#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');
 
 
  • 1
  • 1

(第二步)调用方法获取返回值

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;
            }
           */
        })
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

**这里解释一下: 
(我是这么理解的,可能我理解的有误,也希望大神能指正一下,谢谢啦~!!),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这么一个东西~~完美的解决了困扰我的这个问题哈!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值