LoginSignup
12
13

More than 5 years have passed since last update.

DynamicRealmを使って、Realm Browserを作ってみましょう!

Last updated at Posted at 2015-12-08

最近realmはDynamic Reamsを含んだrealm0.86をリリースしました。Dynamic Realmsによって私たちはRealm Schemaにアクセスし、そしてオブジェクトを作り、文字列(モデルネームとフィールドネーム)を使ってフィールドに動的にアクセスできます。

Concept

Realm browserはテーブル、構造、コンテンツを見ることに使われます。このブラウザはAndroidデバイスによって提供されるローカルホストからアクセスすることができます。

NanoHTTP

NanoHTTPは他のアプリケーションに埋め込まれた軽量のHTTPサーバーで、修正BSDライセンスの下でリリースされました。

NanoHTTPD sample

public class HelloServer extends NanoHTTPD {

    public static void main(String[] args) {
        ServerRunner.run(HelloServer.class);
    }

    public HelloServer() {
        super(8080);
    }

    @Override
    public Response serve(IHTTPSession session) {
        String msg = "<html><body><h1>Hello server</h1></body></html>";

        return newFixedLengthResponse(msg);
    }
}

このシンプルなコードはHello serverテキストでHTMLページを作りそれはローカルホストのポート8080からアクセスできます。

DynamicRealm

最初に言ったように、Dynamic Realmsは従来のRealmsの柔軟なバージョンと言えます。Dynamic Realmsは従来のRealmで使っていた物と同じconfigurationを使えるが、どんなschema定義、migration、schemaのバージョンも無視します。

Dynamic Realmsを使ったら、モデル名とフィールド名が分かればコンテンツをアックセスすることができます。

DynamicRealmObject user = realm.createObject("User");
String name = user.getString("name");
int age = user.getString("age");

DynamicRealmは柔軟性のために型安全とパフォーマンスを犠牲にしています。

RealmBrowser

実装に関して

重要なコードだけを説明するので、フルコードを見たい場合は私のgithubリポジトリを見てください。

最初に前回のセッションからパラメーターがあるかないかチェックします。

Map<String, String> params = session.getParms();
String className = params.get("class_name");
String selectedView = params.get("selected_view");

そして、そのクラスがあるかないかチェックし、そのクラスがRealmObjectのサブクラスかじゃないかチェックします。

Class clazz = Class.forName(className);
if (RealmObject.class.isAssignableFrom(clazz)) {
    // Show structure or content
}

そのクラス名から普通のqueryを実行して、resultsを取ります。

RealmResults<DynamicRealmObject> realmResults = dynamicRealm.where(simpleTableName).findAll();

RealmSchemaからフィールド名を取れます。

RealmObjectSchema realmObjectSchema = dynamicRealm.getSchema().get(simpleTableName);
Set<String> fieldNames = realmObjectSchema.getFieldNames();

今フィールドタイプを直接取れるAPIはまだ実装されていませんが、私はgithub issueを登録して、realmチームが解決してくれたので次のバージョン(0.87)のリリースに入っているはずです。
そして、フィールドタイプを取るために私は他の方法を考えて、一つ一つのオブジェクトをタイプチェックを行います。

private RealmFieldType checkRealmFieldType(Object obj) {
    int nativeValue = -1;
    if (obj instanceof Long || obj instanceof Integer || obj instanceof Short || obj instanceof Byte) {
        nativeValue = 0;
    } else if (obj instanceof Boolean) {
        nativeValue = 1;
    } else if (obj instanceof String) {
        nativeValue = 2;
    } else if (obj instanceof byte[] || obj instanceof ByteBuffer) {
        nativeValue = 4;
    } else if (obj == null || obj instanceof Object[][]) {
        nativeValue = 5;
    } else if (obj instanceof Mixed) {
        nativeValue = 6;
    } else if (obj instanceof Date) {
        nativeValue = 7;
    } else if (obj instanceof Float) {
        nativeValue = 9;
    } else if (obj instanceof Double) {
        nativeValue = 10;
    }
    return RealmFieldType.fromNativeValue(nativeValue);
}

そして、さっきのresultsから一番目のオブジェクトを取って、さっき定義した機能でタイプチェックを行います。

int index = 0;
for (String fieldName : fieldNameArray) {
    Object object = realmResults.get(0).get(fieldName);
    realmFieldTypes[index] = checkRealmFieldType(object);
    index++;
}

最後にコンテンツを取るために、テーブルを反復して、フィールドタイプによってgetter機能でvalueを取ります。

for (int i = 0; i < tableSize; i++) {
    DynamicRealmObject dynamicRealmObject = realmResults.get(i);
    for (int j = 0; j < columnCount; j++) {
        String columnName = fieldNameArray[j];
        String value = "";
        switch (realmFieldTypes[j]) {
            case INTEGER:
                value = String.valueOf(dynamicRealmObject.getLong(columnName));
                break;
            case BOOLEAN:
                value = String.valueOf(dynamicRealmObject.getBoolean(columnName));
                break;
            case FLOAT:
                value = String.valueOf(dynamicRealmObject.getFloat(columnName));
                break;
            case DOUBLE:
                value = String.valueOf(dynamicRealmObject.getDouble(columnName));
                break;
            case DATE:
                value = dynamicRealmObject.getDate(columnName).toString();
                break;
            case STRING:
                value = dynamicRealmObject.getString(columnName);
                break;
        }
    }
}

使い方

このライブラリーの使い方はRealmBrowserのインスタンスを作って、RealmBrowser.start();という機能を呼んだらRealmBrowserが始まります。ポートを設定したい場合に、パラメーターを入れてください。使い終わったら RealmBrowser.stop();を呼んでください。

ブラウザからアックセスしたい場合に、realmBrowser.showServerAddress(this); という機能を呼んで、logcatでRealmBrowserのaddressが表示されます。

注意:AndroidデバイスとPCやMacが同じWi-Fiに接続していないとアクセスすることができません。

最後に

このライブラリーは改善の余地がまだまだあると思います。今週中に検索機能を追加したいと今度HTML Pageの作り方も直したいと思います。
今フルコードはgithubにあります。フィードバックや問題やプルリクエストは誠にありがたいです。

12
13
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13