SQLの窓

2016年10月03日


Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。(orderByChild 使う場合は、getChildren してから)

2016/10/03 : orderByChild の処理 を追加しました
記事末に、@IgnoreExtraProperties アノテーションの説明を追加しました。
記事末に、『JSON データを直接使用する』もあります。

ArrayList として取得
HashMap として取得
Userクラスとして取得
全体ソース
まず、環境とプロジェクトの作成方法は、『Firebase API + Android Studio : Database 処理の基本設定』にまとめました。そちらを参照して下さい。 Firebase の Database は、JSON をイメージした格納方法になっており、データはツリー構造の末端にあると考えて、そこまでのパスを指定して読み出します。ここでは、以下のようなデータを想定しており、0、1、2、の部分は配列のインデックスを意味しています。 ArrayList として取得 users を パスとして与えて取得すると、その下は配列なので ArrayList として取得する事ができます。また、users/0 のパスで取得するデータは クラス(User)を作成して、User.class を使用して Userクラスのインスタンスに直接セットする事ができます。そして、users を パス とした場合は ArrayList<User> としても取得する事ができます。
GenericTypeIndicator<ArrayList<User>> t = new GenericTypeIndicator<ArrayList<User>>() {};

ArrayList<User> user = dataSnapshot.getValue(t);
Iterator<User> it = user.iterator();
while( it.hasNext() ) {
	User work = it.next();
	Log.i("lightbox", work.getCode() );
	Log.i("lightbox", work.getName() );
}


DataSnapshot dataSnapshot は、Database のデータを取得する onDataChange イベントのパラメータとして使用可能なもので、この中にデータがセットされています。

そして、ArrayList は 以下のようにして配列に変換して利用してもいいでしょう。
User[] users = user.toArray(new User[0]);

for( int i = 0; i < users.length; i++){
	Log.i("lightbox", users[i].getCode() );
	Log.i("lightbox", users[i].getName() );
}


HashMap として取得

User クラスを作成しない場合、users を パスとした場合の一般的な方法として ArrayList<HashMap<String,Object> として取得する事ができます。
GenericTypeIndicator<ArrayList<HashMap<String,Object>>> t2
	= new GenericTypeIndicator<ArrayList<HashMap<String,Object>>>() {};

ArrayList<HashMap<String,Object>> useList = dataSnapshot.getValue(t2);

Iterator<HashMap<String,Object>> it2 = useList.iterator();
while( it2.hasNext()) {
	HashMap<String,Object> userMap = it2.next();
	Log.i( "lightbox", userMap.get("code").toString() );
	Log.i( "lightbox", userMap.get("name").toString() );
}


Userクラスとして取得
User user = dataSnapshot.getValue(User.class);

TextView tv1 = (TextView) MainActivity.this.findViewById(R.id.textCode);
tv1.setText(user.getCode());
TextView tv2 = (TextView) MainActivity.this.findViewById(R.id.textName);
tv2.setText(user.getName());

※ クラスで定義するフィールドの整数は long で定義して下さい。(関連 API ドキュメント情報)

クラス内の変数は、public のフィールドで定義してもかまいませんし、setter / getter で定義してもかまいません。排除したいフィールドは、@Exclude アノテーションを使用できます。

また、クラスには引数の無い処理の無いデフォルトコンストラクタを定義しておいて下さい。以下のような但し書きがあります
Default constructor required for calls to DataSnapshot.getValue(User.class)
※ 概要印刷用 PDF ※ ソース全体印刷用 PDF データを取得する為の addListenerForSingleValueEvent ドキュメントには、『Read data once』とタイトルして解説されていますが、必要な時にデータを取得する為のイベントの登録処理です。他のリスナーは、状態が変化した時に取得可能なもので、上のリンク先のページの『Listen for events』で解説されています。 addListenerForSingleValueEvent は、一般的にサーバよりデータを取得するメソッドとして使用され、この中のイベントで DataSnapshot を使ってデータにアクセスします。 3種類の取得パターンの全体ソース
public class MainActivity extends AppCompatActivity {

	private FirebaseDatabase database;
	private DatabaseReference mDatabase;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		database = FirebaseDatabase.getInstance();
		mDatabase = database.getReference();

		Button readButton = (Button) MainActivity.this.findViewById(R.id.readButton);
		readButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", dataSnapshot.getValue().toString());
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {

					}
				});


				mDatabase.child("users").addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", "-- users の状態");
							Log.i("lightbox", dataSnapshot.getValue().toString());
							Log.i("lightbox", "-- ArrayList<User>");

							GenericTypeIndicator<ArrayList<User>> t = new GenericTypeIndicator<ArrayList<User>>() {};
							ArrayList<User> user = dataSnapshot.getValue(t);
							Iterator<User> it = user.iterator();
							while( it.hasNext() ) {
								User work = it.next();
								Log.i("lightbox", work.getCode() );
								Log.i("lightbox", work.getName() );
							}

							Log.i("lightbox", "-- 配列");

							User[] users = user.toArray(new User[0]);
							for( int i = 0; i < users.length; i++){
								Log.i("lightbox", users[i].getCode() );
								Log.i("lightbox", users[i].getName() );
							}

							Log.i("lightbox", "-- ArrayList<HashMap<String,Object>>");

							GenericTypeIndicator<ArrayList<HashMap<String,Object>>> t2
								= new GenericTypeIndicator<ArrayList<HashMap<String,Object>>>() {};
							ArrayList<HashMap<String,Object>> useList = dataSnapshot.getValue(t2);
							Iterator<HashMap<String,Object>> it2 = useList.iterator();
							while( it2.hasNext()) {
								HashMap<String,Object> userMap = it2.next();
								Log.i( "lightbox", userMap.get("code").toString() );
								Log.i( "lightbox", userMap.get("name").toString() );
							}
						}
						else {
							Log.i("lightbox","データを読み込めませんでした");
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {
						Log.i("lightbox","onCancelled");
						StringWriter sw = new StringWriter();
						PrintWriter pw = new PrintWriter(sw);
						databaseError.toException().printStackTrace(pw);
						pw.flush();
						String stackTrace = sw.toString();
						Log.i("lightbox",stackTrace);

					}
				});

			}
		});

		Button readUserButton = (Button) MainActivity.this.findViewById(R.id.readUserButton);
		readUserButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				mDatabase.child(String.format("users/%d",0)).addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", dataSnapshot.getValue().toString());

							User user = dataSnapshot.getValue(User.class);

							TextView tv1 = (TextView) MainActivity.this.findViewById(R.id.textCode);
							tv1.setText(user.getCode());
							TextView tv2 = (TextView) MainActivity.this.findViewById(R.id.textName);
							tv2.setText(user.getName());
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {

					}
				});

			}
		});


	}

	public static class User {

		private String code;
		private String name;

		public User() {}

		public User(String code, String name) {
			this.code = code;
			this.name = name;
		}

		public String getCode() {
			return code;
		}
		public String getName() {
			return name;
		}
		public void setCode(String code) {
			this.code = code;
		}
		public void setName(String name) {
			this.name = name;
		}

	}

}


orderByChild の処理

ツリーが 配列では無くHashMap で構成されているデータは、直接 HashMap に格納できますが、順序が保証されないので、orderByChild メソッドを使用してデータをソートしてから取得します。その場合は、DataSnapshot から getChildren メソッドで一覧を取得する必要があります
				mDatabase.child("class").orderByChild("code").addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {

							userList = new ArrayList<User>();

							Iterator<DataSnapshot> child = dataSnapshot.getChildren().iterator();
							while(child.hasNext()) {
								DataSnapshot next = child.next();
								User user = next.getValue(User.class);

								userList.add(user);
							}


						}
						else {
							Log.i("lightbox","データを読み込めませんでした");
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {
						Log.i("lightbox","onCancelled");

					}
				});


※ 印刷用 PDF
※ 印刷用 PDF(Module Gradle)

@IgnoreExtraProperties アノテーションについて



結局付けても付けなくても直接の動作には影響ありません。ただ、付けない場合はログにワーニングが表示され、付けるとワーニングは表示されません。

これは、開発中に Database 側にあって、クラス側に無いデータをクラスを使って読み込んだ時に確認できる内容になると思います。

Firebase ドキュメント : Update your Java model objects

@Exclude アノテーションについて

上のリンク先では、@Exclude についても記述されています。これを使用すると、意図的にそのフィールドを排除できます。サンプルでは、public なフィールドに設定されていますが、setter/getter に対して指定できます。

補足 : JSON データを直接使用する

データベースのルールが ".read": true になっている場合は、Firebase のプロジェクトの Database の URL で直接 JSON 文字列を使用できます。ルートは https://プロジェクトid.firebaseio.com/.json で取得でき、他のパスは、.json を拡張子として付加すると取得できます。
※ ?print=pretty というパラメータを指定できます(整形します)

▼ 公開サンプル
https://json-sample-b69b7.firebaseio.com/.json?print=pretty
https://json-sample-b69b7.firebaseio.com/users/0.json
▼ JSONLint にて整形
http://jsonlint.com/?json=https://json-sample-b69b7.firebaseio.com/.json

また、このアクセスは、Access-Control-Allow-Origin:* を返すので、jQuery で簡単に利用可能です。(ルールが要ログインの場合は、アクセストークンが必要になり、Android だけで利用するのは結構面倒になります)

関連する記事

Firebase API + Android Studio : Database にデータを保存は単純で、DatabaseReference の setValue メソッドを使用します

Firebase API + Android Studio : Database 処理の基本設定

Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出る場合の対処方法



posted by lightbox at 2016-10-03 19:04 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする

2016年09月27日


Android : Data Binding + Firebase API で ListView にデータを表示する

ListView の扱いとしては、『Android : Data Binding で ListView へのデータ表示を凄く簡単にする』 の拡張です。

Firebase 部分のセットアップは、『Firebase API + Android Studio : Database 処理の基本設定』を参照して下さい。

Firebase API で Databaseデータ を読み込む方法に関しては『Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。』を参照して下さい

Firebase の ArrayList データを使用したソース
public class MainActivity extends Activity {

	private FirebaseDatabase database;
	private DatabaseReference mDatabase;
	private ArrayList<Item> users;
	private User user;

	TestArrayAdapter<Item> adapter = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		database = FirebaseDatabase.getInstance();
		mDatabase = database.getReference();

		ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
		user = new User();
		user.setFirstName("山田");
		user.setLastName("タロウ");
		binding.setUser(user);

		adapter = new TestArrayAdapter<Item>(
				MainActivity.this,
				R.layout.myitem,
				new TestArrayAdapter.OnGetViewListener() {
					@Override
					public View onGetViewListener(int position, View convertView, ViewGroup parent) {

						MyitemBinding myitem;

						if ( convertView == null ) {
							LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService
								(Context.LAYOUT_INFLATER_SERVICE);
							myitem = DataBindingUtil.inflate(inflater, R.layout.myitem, parent, false);
						}
						else {
							myitem = DataBindingUtil.getBinding(convertView);
						}


						ListView lv = (ListView)parent;
						TestArrayAdapter taa = (TestArrayAdapter)lv.getAdapter();
						myitem.setItem(  taa.getItem(position) );

						// ここが重要です
						return myitem.getRoot();
					}
				}
		);

		((ListView)MainActivity.this.findViewById(R.id.listView)).setAdapter(adapter);

		// Firebase Database より読み込み
		MainActivity.this.findViewById(R.id.buttonFirebase).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				mDatabase.child("users").addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", dataSnapshot.getValue().toString());

							GenericTypeIndicator<ArrayList<Item>> t = new GenericTypeIndicator<ArrayList<Item>>() {};
							users = dataSnapshot.getValue(t);

							adapter.clear();
							adapter.addAll(users);

						}
						else {
							Log.i("lightbox","データを読み込めませんでした");
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {
						Log.i("lightbox","onCancelled");
						StringWriter sw = new StringWriter();
						PrintWriter pw = new PrintWriter(sw);
						databaseError.toException().printStackTrace(pw);
						pw.flush();
						String stackTrace = sw.toString();
						Log.i("lightbox",stackTrace);

					}
				});
			}
		});

		// ボタンを押して、オブジェクトの変更のみで反映されます
		MainActivity.this.findViewById(R.id.buttonSetValue).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				user.setFirstName("鈴木");
				user.setLastName("ジロウ");
				if ( users != null ) {
					users.get(0).setText("getView での記述が簡単になりました");
					users.get(1).setText("しかも、オブジェクトを変更すると ListView も変わります");
				}
			}
		});
	}

	// バインド用クラス(1)
	public static class User extends BaseObservable {
		private String firstName;
		private String lastName;

		@Bindable
		public String getFirstName() {
			return this.firstName;
		}
		@Bindable
		public String getLastName() {
			return this.lastName;
		}

		public void setFirstName(String firstName) {
			this.firstName = firstName;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.firstName);
		}
		public void setLastName(String lastName) {
			this.lastName = lastName;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.lastName);
		}
	}

	// バインド用クラス(2) : ListView 用
	public static class Item extends BaseObservable {
		private String title;
		private String text;
		private boolean flg = false;

		public Item() {}

		public Item(String text,String title) {
			this.text = text;
			this.title = title;
		}

		@Bindable
		public String getText() {
			return this.text;
		}
		@Bindable
		public String getTitle() {
			return this.title;
		}

		public void setText(String text) {
			this.text = text;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.text);
		}

		public void seTitle(String title) {
			this.title = title;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.title);
		}

		public String getCode() {
			return title;
		}
		public String getName() {
			return text;
		}
		public void setCode(String code) {
			this.title = code;
		}
		public void setName(String name) {
			this.text = name;
		}

	}

}

Item クラスに、Firebase で定義したデータを使用する為に、Firebase 用の Setter を作成して、元々のデータ処理と互換性を持たせています。

setText と setTitle 側で、notifyPropertyChanged を使っているので、そちらでデータの変更を行っています。

このデータは、以下のようなフォーマットであり、ArrayList として直接取得しています。



しかし、個別のデータとしては上記データは特殊な部類になるので、以下のようなデータで ListView にデータをセットします。



Firebase の HashMap データを使用したソース
public class MainActivity extends Activity {

	private FirebaseDatabase database;
	private DatabaseReference mDatabase;
	private HashMap<String,Item> users;
	private ArrayList<Item> userList;
	private User user;

	TestArrayAdapter<Item> adapter = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		database = FirebaseDatabase.getInstance();
		mDatabase = database.getReference();

		ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
		user = new User();
		user.setFirstName("山田");
		user.setLastName("タロウ");
		binding.setUser(user);

		adapter = new TestArrayAdapter<Item>(
				MainActivity.this,
				R.layout.myitem,
				new TestArrayAdapter.OnGetViewListener() {
					@Override
					public View onGetViewListener(int position, View convertView, ViewGroup parent) {

						MyitemBinding myitem;

						if ( convertView == null ) {
							LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService
								(Context.LAYOUT_INFLATER_SERVICE);
							myitem = DataBindingUtil.inflate(inflater, R.layout.myitem, parent, false);
						}
						else {
							myitem = DataBindingUtil.getBinding(convertView);
						}

						ListView lv = (ListView)parent;
						TestArrayAdapter taa = (TestArrayAdapter)lv.getAdapter();
						myitem.setItem(  taa.getItem(position) );

						// ここが重要です
						return myitem.getRoot();
					}
				}
		);

		((ListView)MainActivity.this.findViewById(R.id.listView)).setAdapter(adapter);

		// Firebase Database より読み込み
		MainActivity.this.findViewById(R.id.buttonFirebase).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				mDatabase.child("class").addListenerForSingleValueEvent(new ValueEventListener() {
					@Override
					public void onDataChange(DataSnapshot dataSnapshot) {
						if ( dataSnapshot.exists() ) {
							Log.i("lightbox", dataSnapshot.getValue().toString());

							GenericTypeIndicator<HashMap<String,Item>> t = new GenericTypeIndicator<HashMap<String,Item>>() {};
							users = dataSnapshot.getValue(t);

							// 必要ならば、ここでデータ順序の変更が必要です
							userList = new ArrayList<Item>(users.values());

							adapter.clear();
							adapter.addAll(userList);

						}
						else {
							Log.i("lightbox","データを読み込めませんでした");
						}
					}

					@Override
					public void onCancelled(DatabaseError databaseError) {
						Log.i("lightbox","onCancelled");
						StringWriter sw = new StringWriter();
						PrintWriter pw = new PrintWriter(sw);
						databaseError.toException().printStackTrace(pw);
						pw.flush();
						String stackTrace = sw.toString();
						Log.i("lightbox",stackTrace);

					}
				});
			}
		});

		// ボタンを押して、オブジェクトの変更のみで反映されます
		MainActivity.this.findViewById(R.id.buttonSetValue).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				user.setFirstName("鈴木");
				user.setLastName("ジロウ");
				if ( userList != null ) {
					userList.get(0).setText("getView での記述が簡単になりました");
					userList.get(1).setText("しかも、オブジェクトを変更すると ListView も変わります");
				}
			}
		});
	}

	// バインド用クラス(1)
	public static class User extends BaseObservable {
		private String firstName;
		private String lastName;

		@Bindable
		public String getFirstName() {
			return this.firstName;
		}
		@Bindable
		public String getLastName() {
			return this.lastName;
		}

		public void setFirstName(String firstName) {
			this.firstName = firstName;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.firstName);
		}
		public void setLastName(String lastName) {
			this.lastName = lastName;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.lastName);
		}
	}

	// バインド用クラス(2) : ListView 用
	public static class Item extends BaseObservable {
		private String title;
		private String text;
		private boolean flg = false;

		public Item() {}

		public Item(String text,String title) {
			this.text = text;
			this.title = title;
		}

		@Bindable
		public String getText() {
			return this.text;
		}
		@Bindable
		public String getTitle() {
			return this.title;
		}

		public void setText(String text) {
			this.text = text;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.text);
		}

		public void seTitle(String title) {
			this.title = title;
			notifyPropertyChanged(sample.lightbox.myapplication.BR.title);
		}

		public String getCode() {
			return title;
		}
		public String getName() {
			return text;
		}
		public void setCode(String code) {
			this.title = code;
		}
		public void setName(String name) {
			this.text = name;
		}

	}

}




posted by lightbox at 2016-09-27 20:36 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする

2016年09月26日


Firebase API + Android Studio : Database 処理の基本設定

Firebase のデータベースは、JSON データです。読み込みはイベントを使用し、保存は API の呼び出しで直接行います。

具体的には、DatabaseReference のスーパークラス である Query の addListenerForSingleValueEvent 経由で DataSnapshot を取得してその中からデータを取得します。

読込み記事
Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。

保存は、DatabaseReference のメソッドを使用する事によって完結します。もちろん、更新された事のイベントを取得はできますが、最初のアプローチとしてはこの二つを設定するだけでいいと思います。

書込み記事
Firebase API + Android Studio : Database にデータを保存は単純で、DatabaseReference の setValue メソッドを使用します

Android Studio に必要なもの

1) Google Play services を SDK マネージャからインストールしておきます。



2) Google APIs を含む System Image を SDK マネージャからインストールしておきます。

実機であれば必要ありませんが、エミュレータから実行する場合に必要です。この System Image を使用して AVD を作成しておく必要があります。


※ 経験則上、Use Host GPU をチェックしておくと、エミュレータを正しく回転してくれます。
※ 時々インストールしたアプリは削除したほうがいいです。

3) Android Studio の Settings で、Instant Run を無効にする

▼ 2.2 がリリースされたので、アップデートした場合は必要ないです


これは、Android Studio 2.2 以降で使用可能な機能の絡みで、Database 機能に直接は関係無いようですが コアなライブラリと関係しているようなので設定しておきます。

▼ 関連
Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出る場合の対処方法

※ 手順確認用 PDF 

Android Studio プロジェクトの準備手順

Firebase のドキュメントページで、『Install the Firebase SDK.』という記述が出て来ますが、これは プロジェクトレベルの Gradle に 『classpath 'com.google.gms:google-services:3.0.0'』を追加する事を指します。また、目的の API によって Module レベルの Gradle にライブラリを追加する作業が必要です。

1) Firebase コンソールで プロジェクトを作成

Firebase でログインすると、右上に『コンソールへ移動』とあるのでクリックして移動します。そこで『新規プロジェクトを作成』からプロジェクトを作成します。

2) Android Studio に Firebase 用の新しいプロジェクトを作成

Firebase に『新しいアプリ』を作成して、Android Studio と関係付ける必要があるのですが、Firebase 側の登録処理で、Android Studio のパッケージ名が必要になります。

3) Android アプリに Firebase を追加

作業的には、Firebase に追加するのですが、目的として 『Android アプリから参照可能な Firebase API を追加する作業』という意味になります。Android Studio のパッケージ名を入力して進めると、google-services.json のダウンロードが始まるので、Android Studio で作成したプロジェクトの app フォルダ内へダウンロードします。



4) プロジェクト build.gradle と app build.gradle の変更


▼ クリックするとクリップボードへコピーします


上が、『Install the Firebase SDK』です。この画像には、Module(アプリ) レベルの変更として apply plugin について書いてありますが、これは最後の行です。つまりは、以下を参考にして下さい。
apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "lightbox.sep.fire3"
        minSdkVersion 19
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile 'com.google.firebase:firebase-core:9.4.0'
    compile 'com.google.firebase:firebase-database:9.4.0'
}

apply plugin: 'com.google.gms.google-services'
※ 印刷用 PDF

firebase のライブラリとして core と database を追加しています。使用する処理によっていろいろなライブラリが用意されており、こちらから一覧を参照できます。


5) AndroidManifest の変更

インターネットアクセスが必要なので、android.permission.INTERNET を追加しておきます。

6) Firebase Database のセキュリティ設定の変更

デフォルトでは、ログイン処理をしないとアクセスできないので、最初は無条件にアクセス可能にしておきます。ルールタブから以下のように変更して下さい。



7) データの作成(サンプル)

以下のデータは、JSON 的には配列データです。Firebase では、表現上以下のようになります。途中のインデックスが飛んでしまうと、そこは null のデータが設定された事になり、インデックスとしては存在する事になります。



作成後、右上のメニューからエクスポートとして内容を確認して下さい。
{
  "users" : [ {
    "code" : "0001",
    "name" : "浦岡 友也"
  }, {
    "code" : "0002",
    "name" : "山村 洋代"
  }, {
    "code" : "0003",
    "name" : "多岡 冬行"
  } ]
}


※ 手順確認用 PDF


関連する記事

Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。

Firebase API + Android Studio : Database にデータを保存は単純で、DatabaseReference の setValue メソッドを使用します

Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出る場合の対処方法





posted by lightbox at 2016-09-26 15:30 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする

2016年09月21日


Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出る場合の対処方法

org.gradle.jvmargs=-Xmx1536m をコメントにすると動くようになります。

元々あったプロジェクトは普通に動作しました。その場合の gradle.properties は以下のようになっていました。
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
新しいプロジェクトは以下のようになりました。
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
なので、コメントにすると動くようになります。また、1536 は 1536x1024 = 1572864 で、エラーメッセージの数値です。Xmx は最大値の指定なので、設定が大きすぎるという事です。テストすると、-Xmx1380m までは動作しました。 何故こうなるのかは不明ですが、コメントにするほうが無難なような気はします。
タグ:Android Studio
posted by lightbox at 2016-09-21 21:41 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする

2016年09月20日


Firebase API + Android Studio : Database にデータを保存は単純で、DatabaseReference の setValue メソッドを使用します

環境とプロジェクトの作成方法は、『Firebase API + Android Studio : Database 処理の基本設定』にまとめています。そちらを参照して下さい。

データの読み出し方法については、『Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります』をご覧ください。

DatabaseReference で更新場所の参照を作成

child メソッドでパス文字列を渡すか、child メソッドの戻り値も DatabaseReference なので、さらに child メソッドでツリーをチェーンして参照を作成します。データベースへの更新は、基本的にこの DatabaseReference で参照した場所に対して setValue を実行する事によって、サーバへ反映されます。

setValue の引数の形式

単純な setValue は、Object を引数として一般的なオブジェクトに加えて、以下のデータ型を使用する事ができます。
Boolean
Long
Double
Map<String, Object>
List<Object>
また、setValue に対してのサーバーのステータスは、意図的にイベントを追加する必要がありますが、多くの場合そこまでの処理を行う必要は無いと思います。ただ、パーミッションによって、アクセスできない事を想定した処理が必要な場合は以下のようにします。 databaseError が null の場合、正常に更新されているはすです。一つ目の参照は、fri に対する更新の DatabaseReference が返って来るので、更新した内容のみ表示しています。二つ目の参照は、getParent によって、データ全体の内容を表示しています。 これに対して、書き込み結果を考慮しない場合は以下のように単純になります。 setValue の戻り値(Task)よりイベントを作成する 成功か失敗かを知りたいだけならば、こつらのほうがすっきりした印象があります。もちろん、task より、Exception を知る事ができるので、再度の参照を行わないのであればイベント内だけで全てが完結します。 データの削除 データの削除は、setValue に null をセットする事によって 簡潔に実行できます。但し、誤ってツリーの途中を削除してしまうと、その下位にあるデータは全て削除されるので注意が必要です クラスによる保存 データの構造を クラスで定義して、そのクラスを使用して保存する事ができます。データは、public なフィールドまたは、setter / getter で定義します。さらに、@Exclude アノテーションによって、メソッドの実行対象からフィールドを除外する事ができます。
public class MyUser {

	public String code;
	public String name;
	public String furi;
	public long kyuyo;
	private long teate = 10000;

	public MyUser() {}

	public MyUser(String code, String name, String furi, long kyuyo) {
		this.code = code;
		this.name = name;
		this.furi = furi;
		this.kyuyo = kyuyo;
		this.teate = 0;
	}

	long getTeate(){
		return this.teate;
	}
	@Exclude
	void setTeate(long teate){
		this.teate = teate;
	}

}


push メソッドによる、ユニークキーの作成

ツリーにデータ構造をクラスで保存する際、ユニークなキーをサーバ側で追加して、その下にデータを保存できます。



▼ 結果サンプル


ArrayList とクラスを使用した一括更新

他のWEBから取得して JSON フォーマットのデータを、Google Gson を使用してデシリアライズ(fromJson)して更新に使用できると思います。



updateChildren メソッドよる、HashMap での更新

固定フォーマットではない場合、HashMap を使用する事によって、自由度の高いデータを作成する事もできます






ソースコード
public class MainActivity extends AppCompatActivity {

	private DatabaseReference mDatabase;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mDatabase = FirebaseDatabase.getInstance().getReference();

		Button saveButton1 = (Button) MainActivity.this.findViewById(R.id.saveButton1);
		saveButton1.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("lightbox","単純データ保存");

				// 書き込み結果を考慮しない
				mDatabase.child("users/3/code").setValue("0004");
				mDatabase.child("users/3/kyuyo").setValue(10000);

				// setValue の戻り値(Task<Void>) の addOnCompleteListener で処理を行う
				// ( 通常、パーミッションによる書き込みの失敗を対処 )
				mDatabase
					.child("users")
					.child("3")
					.child("name")
					.setValue("高田 冬美")
					.addOnCompleteListener(new OnCompleteListener<Void>() {
					@Override
					public void onComplete(@NonNull Task<Void> task) {
						if (task.isSuccessful()) {
							Log.i("lightbox", "書き込みに成功しました");
							Log.i("lightbox", task.toString());
						}
						else {
							Log.i("lightbox", task.getException().toString());
							task.getException().printStackTrace();
						}
					}
				});

				// setValue の第二引数にイベントを登録する
				// ( 通常、パーミッションによる書き込みの失敗を対処 )
				mDatabase
					.child("users")
					.child("3")
					.child("fri")
					.setValue("タカタ フユミ", new DatabaseReference.CompletionListener() {
						@Override
						public void onComplete(DatabaseError databaseError,
											   DatabaseReference databaseReference) {
							if (databaseError == null) {
								Log.i("lightbox", "書き込みに成功しました");
								Log.i("lightbox", databaseReference.toString());

								databaseReference
									.addListenerForSingleValueEvent(new ValueEventListener() {
									@Override
									public void onDataChange(DataSnapshot dataSnapshot) {
										Log.i("lightbox",dataSnapshot.getValue().toString());
									}
									@Override
									public void onCancelled(DatabaseError databaseError) {

									}
								});

								databaseReference.getParent()
									.addListenerForSingleValueEvent(new ValueEventListener() {
									@Override
									public void onDataChange(DataSnapshot dataSnapshot) {
										Log.i("lightbox",dataSnapshot.getValue().toString());

										MyUser user = dataSnapshot.getValue(MyUser.class);
										Log.i("lightbox",String.format("%s",user.code));
										Log.i("lightbox",String.format("%d",user.getTeate()));

									}
									@Override
									public void onCancelled(DatabaseError databaseError) {

									}
								});

							}
							else {
								Log.i("lightbox", databaseError.toString());
								databaseError.toException().printStackTrace();
							}
						}
					});

			}
		});

		Button deleteButton1 = (Button) MainActivity.this.findViewById(R.id.deleteButton1);
		deleteButton1.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("lightbox","インデックスでエントリを削除");

				mDatabase.child("users").child("3").setValue(null);
				mDatabase.child("post").setValue(null);
				mDatabase.child("users").child("4/furi").setValue(null);

			}
		});

		Button saveButton2 = (Button) MainActivity.this.findViewById(R.id.saveButton2);
		saveButton2.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("lightbox","MyUserクラスによるデータ保存");

				MyUser user = new MyUser("0005","内高 友之","ウチタカ トモユキ",150000);
				mDatabase.child("users/4").setValue(user);

			}
		});

		Button saveButton3 = (Button) MainActivity.this.findViewById(R.id.saveButton3);
		saveButton3.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("lightbox","push and MyUser");

				DatabaseReference treeKey = mDatabase.child("post").push();
				MyUser user = new MyUser("0005","内高 友之","ウチタカ トモユキ",150000);
				treeKey.setValue(user);

			}
		});

		Button saveButton4 = (Button) MainActivity.this.findViewById(R.id.saveButton4);
		saveButton4.setAllCaps(false);
		saveButton4.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("lightbox","Hash Map");

				HashMap<String, Object> entry = new HashMap<String, Object> ();
				entry.put("code", "A001");
				entry.put("name", "山田 太郎");
				entry.put("kyuyo", 100000);

				DatabaseReference treeKey = mDatabase.child("post/entry").push();
				treeKey.updateChildren(entry);

			}
		});

		Button saveButton5 = (Button) MainActivity.this.findViewById(R.id.saveButton5);
		saveButton5.setAllCaps(false);
		saveButton5.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("lightbox","Array List");

				ArrayList<MyUser> userList = new ArrayList<MyUser>();
				DatabaseReference listTree = mDatabase.child("post/list");
				userList.add(new MyUser("0001","内高 001","ウチタカ 001",10000));
				userList.add(new MyUser("0002","内高 002","ウチタカ 002",20000));
				userList.add(new MyUser("0003","内高 003","ウチタカ 003",30000));
				listTree.setValue(userList);

			}
		});

	}
}



関連する記事

Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。

Firebase API + Android Studio : Database 処理の基本設定

Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出る場合の対処方法




posted by lightbox at 2016-09-20 17:12 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり