プログラミングで何か作ってみる

現在プログラミングにハマっている人がツールやゲームを公開するブログ

androidでデータ保存する方法(gson)

どうも!
早速android開発中に引っかかった部分があったのでメモ
※記事中のコードは動作確認していないのでスペルミスあるかも

androidにて設定やデータを保存したいとき、基本的にSQLiteデータベースを使うかSharedPreferenceとかを使ってアプリの固有領域に保存します
でも、正直保存したいデータが自作クラスでまとまってるとき(特に他のクラスを持ってるクラス)、上の2つだと保存が大変です
どちらもキー:値の形で保存するので、大量のクラス変数があるときキーの管理が大変になって行きます
なのでもっとかんたんな方法としてGsonというGoogleさんの便利なライブラリを使って保存すると楽です

Gsonとは

Gsonはクラスをそのままjson形式に変えてくれるものです。
jsonは文字列なのでそのままSharedPreferenceに好きなキー1つを使って保存すればクラスごと保存できます

導入は簡単で以下をbuild.gradle(Module:...)のdependenciesに追加でok
implementation 'com.google.code.gson:gson:2.8.6'
バージョンはその都度最新版に変えてください(執筆時点では2.8.6)

やり方はクラスの種類によって変わります

1.単純なクラス
2.クラスのリスト
3.クラスのリスト(抽象クラス)

1.単純なクラス

GsonによってJsonに変換するのでもちろんJsonにならない値がクラスにあると変換できません
基本的に変換できるのはintなどの数値や、Stringなどの文字列です
変換できるクラス変数しかないものを単純クラスと勝手に言ってます



なのでContext,Drawableなどは保存できません。これらは工夫して保存しなくてはいけません
これは後ほど記事にしようかなって思ってます

保存
MyClass myClass = new MyClass;

Gson gson = new Gson();
String json = gson.toJson(myClass); //MyClassをJsonに変換

//あとはこれをSharedPreferenceで保存するだけ


読み込み
//json = SharedPreferenceから読みだしたjson
Gson gson = new Gson();
MyClass myClass = gson.fromJson(json, MyClass.class); //JsonをMyClassに変換


2.クラスのリスト


単純なクラスのリスト(ArrayList<>)は保存は同じですが読み込みが少し違うだけです

保存
ArrayList<MyClass> myClassList = new ArrayList<>();

Gson gson = new Gson();
String json = gson.toJson(myClassList); //MyClassListをJsonに変換

//SharedPreferenceで保存


読み込み
//json = SharedPreferenceから読みだしたjson
Gson gson = new Gson();
ArrayList<MyClass> myClassList = (ArrayList<MyClass>) gson.fromJson(json, new TypeToken<ArrayList<MyClass>>(){}.getType()); //JsonをMyClassListに変換


どうにかこうにかしてListに変換してるだけです

3.クラスのリスト(抽象クラス)

これが一番ややこしいかもです
抽象クラスで複数のクラスが以下のようになっているとき
public abstract class Shape{
int x, y;
public Shape(x, y){
this.x = x;
this.y = y;
}
}

public Rect extends Shape{
int w, h;
public Rect(x, y, w, h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
}

public Cirlce extends Shape{
int radius;
public Circle(x, y, radius){
this.x = x;
this.y = y;
this.radius = radius;
}
}


このShapeクラスのリストにRectもCircleクラスも持っている場合は、読み込む際に分別しないといけません。
やり方としてはGsonに分別処理を追加するだけなのですが、この分別処理をしてくれるクラスはすでにGsonのGithubにあるのでコピーして使いましょう
RuntimeTypeAdapterFactory.java
このクラスの使い方は以下のように簡単に書けます
RuntimeTypeAdapterFactory<Shape> adapter = RuntimeTypeAdapterFactory.of(Shape.class)    //親クラスを登録
.registerSubtype(Rect.class) //子クラスを登録
.registerSubtype(Circle.class);

Gson gson = new GsonBuilder().registerTypeAdapterFactory(adapter).create();
ArrayList<Shape> shapeList = (ArrayList<Shape>)gson.fromJson(json, new TypeToken<ArrayList<Shape>>(){}.getType());

親クラスと子クラスをすべて登録したあとにその分別処理ができるGsonを作ってからJson化すると動作します
ちなみにですが、クラス変数にこういった抽象クラスのリストがある場合も新しいAdapterを作って登録すれば動作します

保存は変わらないので省略

まとめ

最後の方は多少難しいかもしれなかったですが、比較的簡単に保存できるので現状一番便利な方法だと思います
あとはクラスを保存できる形式に変えられるかの勝負なのでそれはまた後ほど

ちなみにUriクラスを保存形式にするのは有志の方が作っているものがあります( UriTypeHierarchyAdapter.java )
GsonBuilderのregisterTypeHierarchyAdapterを使って登録すると動作します
他にもあるかも

参考文献

こちらも見てみよう
gson-list - 開発者ドキュメント
SharedPreferenceに自作クラスオブジェクトを保存する方法(Gsonの使用方法) | Androidアプリ開発
GSONの基本的な使い方 - Qiita
スポンサーサイト



お久しぶりです

まっちゃです
元気にしてますが最近は絵を描くことを多くなりました…かといってプログラミングをしてないわけではないですが!
現在はtwitterにて絵の活動をしています

ココ↓
https://twitter.com/Ryokusasa

ちなみに最近のプログラミングはpythonの深層学習, javascriptのゲーム開発, androidアプリ開発が自分の中で流行っています

中学の頃にはじめたこのブログを見ている人はいるかしりませんが、現在もう大学院生で時間が立つのは早い気もします
なのでそろそろこのブログも削除するかなぁと思ってます
それか開発の際に見つけたtipsなどを乗せるだけのよくわからんブログになってもいいかもしれない

テスト

js版ドットレイン

【Android】動的に作成するCostomViewのサイズを変える

今回は動的に作成するCostomViewのサイズを変える方法です。(前回の記事からすっ飛んでたり足りない知識があったりですみません。)
例えばViewを継承してCanvasなどで絵を描いたViewを継承したクラスを作りたいとき(自分の場合はただの●とか?)、ただ単にonDrawで絵を描いただけのクラスでは大きさが画面いっぱいに取られてしまいます。
こうした状態だと、このCostomViewを他レイアウトにaddViewなどするとそれ以下のViewオブジェクトにクリックリスナーが伝わらないとかいう自体に…
こんな感じに大きさを変えたいのですが、コンストラクタに処理を書けばよいのでは?と自分は思ったのですが、全く変わりませんでした…。原因は多分親ViewGroupのonCreate()中に書いてるのでLayoutメソッドだけでは親ViewGroupにはサイズなどが伝わってないとかそんな感じです(曖昧で申し訳ないです)。
そこで、ViewにはonMeasure()という関数がViewのサイズを決めるときに呼ばれるので、その中でサイズを指定してあげます。(参考サイト:カスタムビューを作る際に重要なonMeasure()とは?
参考サイト様を見ていただいても良いのですが、こちらでもざっくり説明します。
以下のソースコードはマルを描いただけのCostomViewを作る際のonMeasure()です。

//ViewGroupに大きさを伝える処理
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
//今回は親より絶対小さいのでモードによる分岐はなし
//radiusはこのCostomViewの半径
int width = MeasureSpec.makeMeasureSpec(radius*2, MeasureSpec.getMode(widthMeasureSpec));
setMeasuredDimension(width, width);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}


onMeasureをOverrideして使用するのですが、その際の引数はwidthMeasureSpecとheightMesureSpecの2つです。
その名の通り横幅と縦幅を持った引数なのですが、ただの数値ではなく、上位2ビットは制約条件(モード)が、下位30ビットはサイズが格納されています。
でもわざわざビット演算しなくてもすでにMeasureSpec.getSize(int mesureSpec)やMesureSpec.getMode(int measureSpec)という便利な関数があるのでありがたく使います。
この際引数にはモードがあり、そのモードに従ってサイズを指定しないといけませんが、今回は親ViewGroupよりも小さいViewを作るので無視しています。(良い子は真似しないでね)このモードの詳細は説明する時間がないので省きます(参考サイト様を参考にしてください)。
setMeasuredDimension()でサイズをCostomViewに伝え、最後にsuperを実行することによってサイズを親に伝えます(ここらへんも詳しいことは参考サイト様にあります)。



ということで今回はこんな感じです。また今度時間あるときに自分がつまずいたことを書いていきたいと思います。

【Android】ViewGroupについて

今回はAndroid開発の基本、ViewGroupについてまとめてみようと思います。 間違っている部分もないとは言えないので過信はしないようお願いします。
ViewGroupはその名の通り、復数のViewを持ったものです。
ConstraintLayoutやLinearLayoutとかもViewGroupの一つです。そしてViewGroupもViewの一つなのでViewGroupの中にViewGroupも可能です(ConstraintLayoutの中にLinearLayoutが入るように)。
そしてViewの種類にはTextViewやButtonがあります。これはViewGroupでないのでもちろんViewを子に持つことはできません。
基本的にはこれらによってandroidの画面が成り立ってます。

ココらへんをわかっておくとViewあたりの操作もだいぶ楽になってきます。基本中の基本なので初心者の人は抑えておきましょう。(俺が言えたことじゃない!)
ちなみに自分がつまずいたのはViewを継承したクラスを作るときですかね…。Viewを動的に作ったは良いものの、どうやってどこに追加するのか全くわからない…という本当時間がもったいないことをしてしまった
addViewなどでLayoutに追加するのも基本です。

 | HOME |  古い記事へ »

文字サイズの変更

プロフィール

まっちゃ

Author:まっちゃ
いろいろなゲーム、ツール、プログラミングのTipsを公開しようと思っています
中一からずっとプログラミング。
基本的にフリーソフトしか作っていません
裏では絵描いてます

なお、このブログにて公開されたソフトやフラッシュやソースコードは無断転載禁止です(ただし毎月プログラミングを除く)

公開ゲーム・ツール集リンク

以下のリンクにあります
本気?なやつ

公開ゲーム・ツール集


こちらはシンプルなやつです。現在更新停止中

毎月プログラミング


最新記事

ツリーカテゴリー

Script by Lc-Factory
(詳細:Lc-Factory/雑記)

最新コメント

カウンター

リンク

応援したい方、是非クリックお願いします

FC2Blog Ranking

メールフォーム

名前:
メール:
件名:
本文:

ブロとも申請フォーム

この人とブロともになる

designed by たけやん