activeandroid は、データベースの操作をより便利かつ簡単にするオープンソースのデータベース フレームワークです。
1: 依存関係を追加します。
a: プロジェクトの build.gradle ファイルを追加します。
allprojects { リポジトリ { google() jcenter() mavenCentral() maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } }
b: アプリの build.gradle ファイルに依存関係を追加します。
実装「com.michaelpardo:activeandroid:3.1.0-SNAPSHOT」
2: 構成データベースの名前とバージョン番号。
a: 独自の Application オブジェクトを android.app.Application ではなく com.activeandroid.app.Application から継承させます。他のライブラリからApplicationを継承する必要がある場合は、Application内でActiveAndroidを初期化して処理する必要があります。
public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); ActiveAndroid.initialize(this); @Override public void onTerminate() { super.onTerminate (); ActiveAndroid.dispose(); } }
b:AndroidManifest.xml
ファイルにデータベース名とデータベースのバージョン番号を設定します。
<メタデータ <マニフェスト ...> <アプリケーション android:name=".MyApp" ...> ...
<メタデータ android:name="AA_DB_NAME" android:value="test-aa.db" /> <メタデータ android:name="AA_DB_VERSION" android:value="1" />
</アプリケーション> </マニフェスト>
3: エンティティ クラスである独自のテーブルを作成します。エンティティ クラスは Model から継承する必要があるため、クラス名はテーブル名になります。クラス名をテーブル名として使用したくない場合は、@Table を使用してテーブル名を定義できます。@Column は列名の定義に使用されます。
@Table(name = "Myperson",id = "_id") public class Person extends Model { @Column(name = "person_id") private int personId; //プライベート int ID; @Column(name = "person_name") private 文字列名; @Column(name = "person_describe") private String 説明; public int getPersonId() { 人物 ID を返します。 public void setPersonId(int personId) { this.personId = personId; public String getName() { 名前を返します。 public void setName(String name) { this.name = 名前; } public String getDescribe() { 戻り値の説明; public void setDescribe(String description) { this.describe = description; } @Override public String toString() { return "<personId: " + personId + "、Name: '" + name + '\'' + "、Describe: '" + description + '\'' + '>'; } }
MyPersonal はテーブルの名前であり、activeAndroid は各テーブルの主キーとして自己増加する ID を割り当てます。この自己増加リストはデフォルトで ID と呼ばれます。この列に名前を付けることができます。
@Table(name = "Myperson",id = "_id")
もちろん、parson_id を主キーとして指定することもできます。(フレームワークによって割り当てられた ID を主キーとして使用すると、同じ personId がテーブルに複数回挿入されることになり、結果としてデータが冗長になるためです。)
@Column(name = "person_id",unique = true) private int personId;
列にインデックスを作成できることを指定するには、その注釈にindex = trueを追加します。
@Column(name = "person_id",unique = true,index = true) private int personId;
他の属性については、依存関係パッケージの com.activeandroid.annotation.Column をクエリできます。
さらに、モデルには getId というメソッドがあるため、エンティティ クラスの属性には id という属性を含めることはできません。id という属性があると、get メソッドと set メソッドを書き換えるときにメソッドと競合するためです。親クラスの。次に、元の JSON に ID が含まれている場合、たとえば、{"id":"1","name":"zmm","describe":"zmm は良い人です"}
Gson を使用して解析するとき、エンティティ クラス person を定義するときに、id を記述する必要があります。このフレームワークでは id を使用できません。どうすればよいですか。パニックにならないでください。実際、Gson は @SerializedName という注釈を提供します。 ("id ")、つまり、json 内の id をエンティティ クラスの personId に変換します。
@SerializedName("id") @Column(name = "person_id") private int personId;
これは普通に解析できます。
4: このステップでは、ActiveAndroid の起動速度を最適化します (オプション)
AndroidManifest.xml文件里,添加标签:
<メタデータ
android:name="AA_MODELS" android:value="com.example.zongm.testapplication.bean.person" />
この時点で、データを追加、削除、変更、確認できます。
5: データ処理
A: 追加、削除、変更、確認
新しい Manager クラスを作成し、データのすべての追加、削除、変更、クエリをこのクラスに入れることができます。
Save: この保存メソッドには、現在挿入されているデータの ID を表す戻り値があります。
public boolean add(person person) { if (person == null) は false を返します。 person.save() > 0 を返します。 }
バッチ保存:
public boolean add(List<person> items) { Log.d(TAG, "アイテムの追加 : " + (items == null ? "null" : items.size()); if (items == null || items.size() == 0) は false を返します。 ブール値の成功 = true; ActiveAndroid.beginTransaction(); try { for (人物 item : items) { success &= add(item); ActiveAndroid.setTransactionSuccessful() ; 成功 &= true; } catch (例外 e) { e.printStackTrace(); 成功 &= false; Log.e(TAG, "addAll : エラー : " + e.getClass()); 最後に { ActiveAndroid.endTransaction(); 成功を返します。 }
もちろん、個別に循環して保存することも可能ですが、その場合は遅くなります。保存するトランザクションを開いて、1 を高速化できます。2: 1 つの保存が失敗した場合は、ロールバックできます。もちろん、削除や更新などの他の操作も、バッチ操作であればトランザクションを開くことで実行できます。
消去:
// 最初のタイプの削除 public void delete(Personal item) { Log.d(TAG, "Delete : " + item); if (item == null) { return; } item.delete(); }
// 2 番目のタイプの削除
public void delete(int personId){ new Delete().from(person.class).where("person_id=?",personId).execute(); }
修正:(同じ理由で2つの方法もあります)
public void update(String personName, String newpersonName) { new Update(person.class).set("person_name = ?", newpersonName).where("person_name = ?", personName); }
お問い合わせ:
//1: 個人内のすべてのデータをチェックアウトします。
@NonNull public List<person> getAll() { return getAll(Integer.MAX_VALUE); } private List<Person> getAll(int count) { return new Select().from(Person.class).limit(count).execute(); }
//2: 条件付きクエリ。
//a: ID に基づいて人物をチェックする
public Person getPersonById(int id) { return new Select().from(Person.class).where("person_id=?", id).executeSingle(); }
//b; ID のグループから構成される ID に従って人のグループを検索します。ID の形式は 1、2、3、4、である必要があることに注意してください。
public List<Person> getPersonListByIds(String ids) { if (TextUtils.isEmpty(ids)) は null を返します。 List<Person> items = new Select().from(Person.class).where(" person_id in (" + ids + ")").execute(); 返却商品; }
実際、このフレームワークにより作業が大幅に簡素化されます。クエリは SQLite のネイティブ クエリ ステートメントに非常に似ており、ほぼすべてのコマンドをカバーしており、基本的にすべての条件付きクエリもサポートされています。SQL ステートメントを覚えていれば、それを次のクエリに置くことができます。 where 記述できる SQL 文はもちろん、関連付けられたクエリもサポートしています 具体的な使用方法については、githubのテストケースを参照してください。
B: タイプシーケンス
ActiveAndroid はデフォルトでいくつかのタイプを処理します。カスタム データ型を処理する必要がある場合は、TypeSerializer を継承し、そのメソッドをオーバーライドします。たとえば、Date 型を格納用に Long 型に変換し、読み取り時に Date 型を直接取得したいとします。
1:
/** * @author zongm on 2019/8/15 */ public class DateUtilSerializer extends TypeSerializer { /** * シーケンスのクラスを返します */ @Override public Class<?> getDeserializedType() { return Date.class; } /* * * データベースに格納されている型を返します */ @Override public Class<?> getSerializedType() { return long.class; } /** * 使用するデータ型を ActiveAndroid に格納されているデータ型に変換します */ @ public Object Serialize(Object data) { if (data == null) { return null; }をオーバーライドします。 return ((Date) data).getTime(); } /** *保存されたデータを使用するデータ型に変換します */ @Override public Object deserialize(Object data) { if (data == null) { return null; } 新しい日付を返します((長い)データ); } }
2: 次に、カスタム シリアル化タイプを登録し、AndroidManifest.xml で宣言します。
<メタデータ android:name="AA_SERIALIZERS" android:value="com.example.zongm.testapplication.DateUtilSerializer"/>
次に、ActiveAndroid に付属する TypeSerializer です。
C: データベースのアップグレード (適用対象: A: 元のデータ テーブルに基づいてフィールドを追加しますが、ユーザーが保存した元のデータが心配なので、元のデータ テーブルを削除してからテーブルを再構築したくない、B:元のデータベースにフィールドを追加して新しいテーブルを作成します)
A: ユースケースA
1. まず、AndroidManifest.xml 内のデータベースのバージョン番号 AA_DB_VERSION を変更する必要があります (前のバージョン番号より大きい正の整数である必要があります) 2. 次に、
asset ディレクトリに SQL ファイルを作成する必要があります。 app/main/assets/migrations/upgraded versionnumber.sql) にデータベース変更の SQL ステートメントをファイルに記述する必要があります (1 行と 1 つの SQL ステートメント)。 MyPerson テーブルの場合は、次のように記述する必要があります。
ALTER TABLE Myperson ADD COLUMN person_age INTEGER;
3. 最後に、対応するフィールドを Person オブジェクトに追加する必要があります (追加のフィールドがある場合は、ルールの追加について上記のデータベース モデルの作成を参照してください)
@Column(name = "person_age") private int age;
B: B の場合を使用します。
1. A と同じ状況での最初のステップ
2. AndroidManifest.xml の AA_MODELS タグの下に追加したテーブル名を追加するだけです。
<メタデータ android:name="AA_MODELS" android:value="com.example.zongm.testapplication.bean.person, com.example.zongm.testapplication.bean.person2" />
最後に、使用プロセスで発生した問題について説明します。
1: 保存中にエラーが報告されます。
原因: java.lang.SecurityException: ユーザー 0 のプロバイダー null が見つかりませんでした。この機関の有効な ContentProvider が見つかることが期待されます
理由:
8.0 または 8.1 システムで SDK バージョン 26 以降を使用する場合、ContentResolver の NoticeChange メソッドを呼び出してデータの更新を通知するか、ContentResolver の registerContentObserver メソッドを呼び出してデータの変更を監視すると、例外が発生します。 lang.SecurityException: ユーザー 0 のプロバイダー < 権限 > が見つかりませんでした。これら 2 つのメソッドは SDK 26 より前のバージョンでは正常に動作します。
具体的な理由については、この兄貴のブログに移動してください: https://blog.csdn.net/weixin_37077539/article/details/80067073
解決策: AndroidManifest.xml ファイルを見つけて、アプリケーション ノードの下に次のコードを追加します。
<プロバイダー android:name="com.activeandroid.content.ContentProvider" android:authorities="${applicationId}" android:enabled="true" android:exported="false"></provider>
2: エンティティ クラスにパラメーターを含むコンストラクターがある場合、save を再度呼び出すと、エラーが報告されます。
原因: java.lang.RuntimeException: モデル com.example.zongm.testapplication.bean.person はデフォルトのコンストラクターを定義していません。ORM モデルを設定するプロセスは次のとおりであるため、ActiveAndroid モデルでは現時点ではデフォルト コンストラクターが必要です。 1. デフォルト モデルをインスタンス化する 2. フィールドにデータを設定する
理由: ActiveAndroid のモデルにはパラメーターのないコンストラクターがあるため、私たちの Person は Model のサブクラスです。パラメーターを含むコンストラクターを作成しました。その場合、パラメーターのないデフォルトのコンストラクターは存在しません。ActiveAndroid のソース コード、processCursor( ) SQLiteUtils:
public static <T extends Model> List<T> processCursor(Class<? extends Model> type, Cursor Cursor) { TableInfo tableInfo = Cache.getTableInfo(type); 文字列 idName = tableInfo.getIdName(); 最終的な List<T> エンティティ = new ArrayList<T>(); try { Constructor<?>entityConstructor = type.getConstructor(); if (cursor.moveToFirst()) { /** * 問題 #106 を修正するために順序付けられた列を取得します (https://github.com/pardom/ActiveAndroid/issues/106) * カーソルに同じ名前の複数の列が取得された場合結合テーブルから。 */ List<String> columnsOrdered = new ArrayList<String>(Arrays.asList(cursor.getColumnNames())); モデル エンティティ = Cache.getEntity(type,cursor.getLong(columnsOrdered.indexOf(idName))); if (entity == null) { entity = (T)entityConstructor.newInstance(); エンティティ .loadFromCursor(カーソル); entities.add((T) エンティティ); while (cursor.moveToNext()); } } catch (NoSuchMethodException e) { throw new RuntimeException( "あなたのモデル " + type.getName() + " はデフォルトを定義していません " + " コンストラクター。" + " ORM モデルを設定する プロセスは次のとおりであるため、ActiveAndroid モデルではデフォルト " + "1. デフォルト モデルをインスタンス化します。" + "2. フィールドを設定します。" } catch (Exception e) { Log.e("カーソルの処理に失敗しました。", e); エンティティを返します 。 }
まずLruCacheキャッシュにModelクラスが存在するかを確認し、存在しない場合は反映してエンティティを作成します。
entityConstructor.newInstance(); Class.class をクリックします。newInstance()メソッドはネイティブメソッドなので具体的にどう書くのかは見当たりませんが、コメントを見るとおそらくパラメータなしの構築方法でオブジェクトを取得するという説明になっていると思います。
したがって、パラメータのない構築方法を通じてオブジェクトを反映する必要があります。パラメータ付きの構築メソッドを記述したため、パラメータなしのデフォルトの構築メソッドは存在しないため、手動で記述する必要があります。
解決:
Person エンティティ クラスでパラメーターなしのコンストラクターを明示的に定義します。
たった今:
パブリック パーソン() { } パブリック パーソン(int personId) { this.personId = personId; }
3: データは常にデータベースに繰り返し保存されます。
この理由は上で述べましたが、主キーが定義されていないことが原因である可能性があります。エンティティ クラスの一意の属性を主キーとして設定します。これは通常、エンティティ クラスの ID です。
4: データを繰り返し保存するため、保存する前にすべての Xiao Kuo Ai がチェックされ、存在する場合は削除してから保存するとエラーが発生します。
注: Delete をexecuteSingle と一緒に使用しないでください。次の 2 つの落とし穴が避けられないためです。
- デフォルトでは、SQLite は DELETE と LIMIT の共存をサポートしていないため、ExecuteSingle は Limt 1 ステートメントを使用します。
- DeleteとexecuteSingleを連携させて実際にはSELETE操作を実行してからModelのdelte操作を実行しますが、ActiveAndroidのソースコードにはnull判定が存在せず、nullポインタとなってしまいます。
詳細については、http: //ju.outofmemory.cn/entry/341803を参照してください。
5: これは gson 解析の問題です。Gson が json データを解析するときに、属性値が null の場合、例外エラーが報告されます。
解決策は、new Gson() の代わりにGsonBuilderを使用して Gson インスタンスを作成することです。
Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC, Modifier.FINAL).create();
GsonBuilder の使用方法は多数ありますので、ご自身で検索してください。
日々の記録: すべての条件付けされたダルマは夢や泡のようなもので、露や電気のようなものであり、そのように見るべきです。
シングルサイクル「Only Love Xijing」