React Native調(diào)用原生端sqlite數(shù)據(jù)庫(kù)

在app開(kāi)發(fā)過(guò)程中數(shù)據(jù)存儲(chǔ)是必不可少的着撩,RN中數(shù)據(jù)存儲(chǔ)一般都用AsyncStorage。但是對(duì)于大批量的數(shù)據(jù)持久化存儲(chǔ)刁笙,最好還是用數(shù)據(jù)庫(kù)來(lái)存膨蛮。RN中并沒(méi)有提供直接的數(shù)據(jù)庫(kù)存儲(chǔ)API,需要我們自己根據(jù)iOS和Android進(jìn)行封裝調(diào)用竖慧。

Github上有個(gè)庫(kù)提供了對(duì)原生sqlite數(shù)據(jù)庫(kù)的操作封裝react-native-sqlite-storage嫌套,看過(guò)之后我覺(jué)得還是自己分別在Android和iOS原生端來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)存儲(chǔ)更好,原生端數(shù)據(jù)庫(kù)API非常簡(jiǎn)單圾旨,尤其是Android踱讨,iOS也可以借助第三方FMDB來(lái)實(shí)現(xiàn)。不過(guò)對(duì)于不熟悉Android或者iOS的人來(lái)說(shuō)砍的,直接使用這個(gè)庫(kù)是最好的選擇痹筛。

在我之前的文章《RN與原生交互(二)——數(shù)據(jù)傳遞》中已經(jīng)說(shuō)明了RN如何調(diào)用原生端方法獲取數(shù)據(jù),這里RN調(diào)用原生sqlite數(shù)據(jù)庫(kù)原理也一樣,都是在原生端寫(xiě)好所有的封裝操作帚稠,以Native Module的形式供RN端調(diào)用谣旁。

我寫(xiě)了個(gè)簡(jiǎn)單的Demo,實(shí)現(xiàn)了數(shù)據(jù)庫(kù)的創(chuàng)建和基本的增刪改查操作滋早,效果如下:


demo.gif

下面來(lái)說(shuō)說(shuō)具體實(shí)現(xiàn)方式榄审。

Android端

Android端sqlite數(shù)據(jù)庫(kù)的使用非常簡(jiǎn)單,官方提供了SQLiteDatabase和SQLiteOpenHelper等相關(guān)類來(lái)操作數(shù)據(jù)庫(kù)杆麸,API非常簡(jiǎn)單搁进。Android端具體實(shí)現(xiàn)步驟如下:

  1. 先創(chuàng)建一個(gè)DBHelper類繼承SQLiteOpenHelper,重寫(xiě)onCreate和onUpgrade方法昔头,并創(chuàng)建該類的構(gòu)造函數(shù):
public class DBHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "StudentDB.db"; //數(shù)據(jù)庫(kù)名稱
    private static final int version = 1; //數(shù)據(jù)庫(kù)版本
    public static final String STUDENT_TABLE = "Student";

    public DBHelper(Context context) {
        super(context, DB_NAME, null, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table if not exists " + STUDENT_TABLE +
                " (studentName text primary key, schoolName text, className text)";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String sql = "DROP TABLE IF EXISTS " + STUDENT_TABLE;
        db.execSQL(sql);
        onCreate(db);
    }
}
  1. 創(chuàng)建DBManager類饼问,將所有數(shù)據(jù)庫(kù)的增刪改查操作放到這里面來(lái)。
    數(shù)據(jù)的查詢使用Cursor揭斧,插入數(shù)據(jù)使用android的ContentValues莱革,非常簡(jiǎn)單,這點(diǎn)比iOS原生的API好用一百倍讹开。部分核心代碼如下:
public class DBManager {
    private static final String TAG = "StudentDB";
    private DBHelper dbHelper;

    private final String[] STUDENT_COLUMNS = new String[] {
            "studentName",
            "schoolName",
            "className",
    };

    public DBManager(Context context) {
        this.dbHelper = new DBHelper(context);
    }

    /**
     * 是否存在此條數(shù)據(jù)
     * @return bool
     */
    public boolean isStudentExists(String studentName) {
        boolean isExists = false;

        SQLiteDatabase db = null;
        Cursor cursor = null;
        try {
            db = dbHelper.getReadableDatabase();
            String sql = "select * from Student where studentName = ?";
            cursor = db.rawQuery(sql, new String[]{studentName});
            if (cursor.getCount() > 0) {
                isExists = true;
            }
        } catch (Exception e) {
            Log.e(TAG, "isStudentExists query error", e);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
            if (db != null) {
                db.close();
            }
        }
        return isExists;
    }

    /**
     * 保存數(shù)據(jù)
     */
    public void saveStudent(String studentName, String schoolName, String className) {
        SQLiteDatabase db = null;
        try {
            db = dbHelper.getWritableDatabase();

            ContentValues cv = new ContentValues();
            cv.put("studentName", studentName);
            cv.put("schoolName", schoolName);
            cv.put("className", className);

            db.insert(DBHelper.STUDENT_TABLE, null, cv);
        } catch (Exception e) {
            Log.e(TAG, "saveStudent error", e);
        } finally {
            if (db != null) {
                db.close();
            }
        }
    }
}
  1. 創(chuàng)建module類繼承ReactContextBaseJavaModule驮吱,將DBManager中的增刪改查方法導(dǎo)出供RN端直接調(diào)用。部分核心代碼:
public class DBManagerModule extends ReactContextBaseJavaModule {

    private ReactContext mReactContext;

    public DBManagerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mReactContext = reactContext;
    }

    @Override
    public String getName() {
        return "DBManagerModule";
    }

    @ReactMethod
    public void saveStudent(String studentName, String schoolName, String className) {
        DBManager dbManager = new DBManager(mReactContext);
        if (!dbManager.isStudentExists(studentName)) {
            dbManager.saveStudent(studentName, schoolName, className);
        }
    }
}
  1. 創(chuàng)建package類繼承ReactPackage萧吠,實(shí)現(xiàn)這個(gè)接口的方法左冬,將上面創(chuàng)建的module類在createNativeModules方法中實(shí)例化。
public class DBManagerPackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> nativeModules = new ArrayList<>();
        nativeModules.add(new DBManagerModule(reactContext));
        return nativeModules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

這樣在RN端就可以調(diào)用Android的數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)了纸型。

iOS端

iOS端數(shù)據(jù)庫(kù)的存儲(chǔ)一般都不使用原生api拇砰,因?yàn)樗鷄pi不那么友好。我們一般使用FMDB來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的存儲(chǔ)操作狰腌,用CoreData也可以除破,原理都一樣,這里以FMDB為例琼腔。

  1. 創(chuàng)建Podfile瑰枫,使用CocoaPods安裝FMDB。
  2. 在項(xiàng)目的Build Phases ——> Link Binary With Libraries中添加libsqlite3.tbd庫(kù)丹莲。
  3. 創(chuàng)建DBHelper類
    不同于Android可以直接繼承SQLiteOpenHelper直接重寫(xiě)方法就OK了光坝,iOS數(shù)據(jù)庫(kù)的存儲(chǔ)操作還是需要我們自己完成。

創(chuàng)建DBHelper的單例甥材,指定數(shù)據(jù)庫(kù)文件盯另,創(chuàng)建數(shù)據(jù)庫(kù)和表,核心代碼如下:

+ (DBHelper *)sharedDBHelper {
  static DBHelper *instance = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    instance = [[self alloc] init];
  });
  return instance;
}

- (instancetype)init {
  self = [super init];
  if (self) {
    _db = [[FMDatabase alloc] initWithPath:[self getDBFilePath]];
    [self createTables];
  }
  return self;
}

- (NSString *)getDBFilePath {
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *documentsDirectory = [paths objectAtIndex:0];
  NSString *storePath = [documentsDirectory stringByAppendingPathComponent:@"StudentDB.db"];
  return storePath;
}

- (void)createTables {
  if ([_db open]) {
    
    NSMutableString *sql = [NSMutableString string];
    [sql appendString:@"create table if not exists Student ("];
    [sql appendString:@"studentName text primary key, "];
    [sql appendString:@"schoolName text, "];
    [sql appendString:@"className text);"];
    BOOL result = [_db executeUpdate:sql];
    if (result) {
      NSLog(@"create table Student successfully.");
    }
    [_db close];
  }
}
  1. 創(chuàng)建module類洲赵,這里module類名字應(yīng)該與Android端一致鸳惯,方便RN端調(diào)用的時(shí)候統(tǒng)一商蕴。這里名字起為DBManagerModule,iOS端module類只需要實(shí)現(xiàn)RCTBridgeModule協(xié)議就可以了芝发,這一步比Android要更簡(jiǎn)單绪商。DBManagerModule核心代碼:
@implementation DBManagerModule

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(saveStudent:(NSDictionary *)dict) {
  [[DBHelper sharedDBHelper] saveStudent:dict];
}

RCT_EXPORT_METHOD(deleteStudent:(NSString *)studentName) {
  [[DBHelper sharedDBHelper] deleteStudentByName:studentName];
}

RCT_EXPORT_METHOD(getAllStudent:(RCTResponseSenderBlock)callback) {
  NSArray *students = [[DBHelper sharedDBHelper] getAllStudent];
  callback(@[students]);
}

RCT_EXPORT_METHOD(deleteAllStudent) {
  [[DBHelper sharedDBHelper] deleteAllStudent];
}

@end

到這里RN端就可以直接調(diào)用module類中的方法操作iOS數(shù)據(jù)庫(kù)了。

RN端的用法
比如查詢所有數(shù)據(jù):

DBManagerModule.getAllStudent((result) => {
      let students = [];
      if (result != null) {
        students = result;
        this.setState({
          studentList: students
        })
      }
    });

總結(jié)

  1. RN端量小的數(shù)據(jù)可以使用AsyncStorage辅鲸,大數(shù)據(jù)量需要存儲(chǔ)還是要用數(shù)據(jù)庫(kù)格郁。
  2. 經(jīng)過(guò)實(shí)踐,我覺(jué)得還是直接在原生端操作數(shù)據(jù)庫(kù)更好瓢湃,api簡(jiǎn)單也方便維護(hù)。第三方庫(kù)react-native-sqlite-storage
    也是在原生端的基礎(chǔ)上做的封裝赫蛇,好處是方便RN端調(diào)用绵患,不熟悉原生的可以直接按照配置說(shuō)明來(lái)使用,缺點(diǎn)也很明顯悟耘,配置繁瑣落蝙,使用過(guò)程中出了問(wèn)題也不容易解決。

PS:

推薦一下demo中用到的RN第三方庫(kù):

  1. react-native-navigation 基于原生的導(dǎo)航庫(kù)
  2. teaset非常好的React Native UI組件庫(kù)
  3. react-native-vector-iconsiconfont組件庫(kù)
  4. react-native-swipe-list-view仿iOS列表側(cè)滑顯示更多操作的React Native列表組件暂幼。雖然有bug筏勒,但不影響使用。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旺嬉,一起剝皮案震驚了整個(gè)濱河市管行,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邪媳,老刑警劉巖捐顷,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異雨效,居然都是意外死亡迅涮,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)徽龟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)叮姑,“玉大人,你說(shuō)我怎么就攤上這事据悔〈福” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵极颓,是天一觀的道長(zhǎng)旷祸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)讼昆,這世上最難降的妖魔是什么托享? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任骚烧,我火速辦了婚禮,結(jié)果婚禮上闰围,老公的妹妹穿的比我還像新娘赃绊。我一直安慰自己,他們只是感情好羡榴,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布碧查。 她就那樣靜靜地躺著,像睡著了一般校仑。 火紅的嫁衣襯著肌膚如雪忠售。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天迄沫,我揣著相機(jī)與錄音稻扬,去河邊找鬼。 笑死羊瘩,一個(gè)胖子當(dāng)著我的面吹牛泰佳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尘吗,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼逝她,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了睬捶?” 一聲冷哼從身側(cè)響起黔宛,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎擒贸,沒(méi)想到半個(gè)月后宁昭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酗宋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年积仗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜕猫。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寂曹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出回右,到底是詐尸還是另有隱情隆圆,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布翔烁,位于F島的核電站渺氧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蹬屹。R本人自食惡果不足惜侣背,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一白华、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贩耐,春花似錦弧腥、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至铡买,卻和暖如春更鲁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奇钞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工澡为, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛇券。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓缀壤,卻偏偏與公主長(zhǎng)得像樊拓,于是被迫代替她去往敵國(guó)和親纠亚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,756評(píng)論 25 707
  • 斯蒂芬·霍金離世:那個(gè)被關(guān)在果殼之中的人,仍是無(wú)限空間之王 首發(fā):沐遙詩(shī)雨(MoyleSY) 作者:李沐遙 據(jù)英國(guó)...
    李沐遙閱讀 564評(píng)論 -1 5
  • 今天開(kāi)車和別人的車相碰了条篷,賠了150元作為教訓(xùn)骗随。我回想了一下,主要還是我和張志琴聊天的太集中了吧赴叹,沒(méi)有判斷前面車的...
    高剛高剛閱讀 152評(píng)論 0 0
  • 自律鸿染,指遵循法律并以此為基礎(chǔ)進(jìn)行的自我約束。 什么是自我控制乞巧?自我控制涨椒,是一種抵御外界的感性誘惑,堅(jiān)定實(shí)現(xiàn)理性目標(biāo)...
    暢暢_閱讀 190評(píng)論 0 1