Firebase の環境とプロジェクトの作成方法 シンプル Android Data Binding : Android Studio 2.2 tools.jar画面定義
MainActivity 主な処理は、初期画面に表示する ListView の処理です。ListView 用の一覧データは、Firebase より取得します。API を使用して(orderByChild メソッド) でフリガナでソートしています。 また、初期画面には表示されていませんが、ViewSwitcher を使用しているので、次画面用の処理として NextPage クラスを用意して、ここで初期化しています。 特に、Spinner 用データ(性別・所属)も Firebase より取得し、KeyValue という汎用クラスを用いて処理を構築しています。(この参照用のデータの取得が成功してから、一覧データを取得しています) ListView 用の MyArrayAdapter は、Data Binding を使用しています
public class MainActivity extends AppCompatActivity { // ViewSwitcher public static int FIRST_PAGE = 0; public static int NEXT_PAGE = 1; // Data Binding private ActivityMainBinding binding; // Firebase private FirebaseDatabase database; private DatabaseReference mDatabase; // データフォーマット private JsonData json; // ローディング中のダイアログ private ProgressDialog progress; // 画面関連 private ViewSwitcher vs; private NextPage nextPage; private ListView listview; private MyArrayAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Data Binding を使用した画面表示 binding = DataBindingUtil.setContentView(this, R.layout.activity_main); // Firebase Database 用 database = FirebaseDatabase.getInstance(); mDatabase = database.getReference(); // ローディング中のダイアログ progress = new ProgressDialog(MainActivity.this); // ViewSwitcher で複数画面処理 vs = (ViewSwitcher) MainActivity.this.findViewById(R.id.viewSwitcher); // 次画面処理 nextPage = new NextPage(MainActivity.this); // 次画面の初期処理( イベント登録等 ) nextPage.initAction(); // リストビューの取得 listview = (ListView) MainActivity.this.findViewById(R.id.listView); // リストビューの行をタップした時の処理 listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // アダプターを取得( ここ専用 ) MyArrayAdapter adapter = (MyArrayAdapter)parent.getAdapter(); // 行データを取得 json = (JsonData)adapter.getItem(position); // この行データを Data Binding で画面にセット binding.setJdata( json ); // この行データを次画面で使用 nextPage.setData( json ); // 画面移動 vs.setDisplayedChild(MainActivity.NEXT_PAGE); } }); // ListView 用の アダブターを作成 adapter = new MyArrayAdapter(MainActivity.this,R.layout.list_item); // 最新の Firebase のデータを取得する loadData(); } // ****************************** // データロード用の public メソッド // ****************************** public void loadData() { // データロード前に表示 progress.setProgressStyle(ProgressDialog.STYLE_SPINNER); progress.setMessage("データをロードしています"); progress.show(); // Firebase の item ツリーを name でソートして取得 mDatabase.child("refdata") .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if ( dataSnapshot.exists() ) { // 性別コンボボックスの作成 DataSnapshot ref1 = dataSnapshot.child("sex"); GenericTypeIndicator<ArrayList<String>> t1 = new GenericTypeIndicator<ArrayList<String>>() {}; ArrayList<String> sexData = ref1.getValue(t1); ArrayAdapter adapter = new ArrayAdapter( MainActivity.this, android.R.layout.simple_spinner_item); Spinner spinner = (Spinner) MainActivity.this.findViewById(R.id.spinnerSex); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.addAll(sexData); spinner.setAdapter(adapter); // 所属コンボボックスの作成 DataSnapshot ref2 = dataSnapshot.child("syozoku"); Iterator<DataSnapshot> child = ref2.getChildren().iterator(); ArrayList<KeyValue> syozokuData = new ArrayList<KeyValue>(); while(child.hasNext()) { DataSnapshot next = child.next(); // Firebase API でJsonData に変換 KeyValue kv = new KeyValue(next.getKey(),next.getValue().toString()); // ArrayList に追加 syozokuData.add(kv); } ArrayAdapter adapter2 = new ArrayAdapter( MainActivity.this, android.R.layout.simple_spinner_item); Spinner spinner2 = (Spinner) MainActivity.this.findViewById(R.id.spinnerSyozoku); adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter2.addAll(syozokuData); spinner2.setAdapter(adapter2); loadDataList(); } else { Log.i("lightbox","コンボボックス用データを読み込めませんでした"); // ローディングダイアログを閉じる progress.dismiss(); } } @Override public void onCancelled(DatabaseError databaseError) { databaseError.toException().printStackTrace(); Log.i("lightbox","StackTrace(コンボボックス用データ) を出力しました"); // ローディングダイアログを閉じる progress.dismiss(); } }); } public void loadDataList() { // Firebase の class ツリーを furi でソートして取得 mDatabase.child("class").orderByChild("furi") .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if ( dataSnapshot.exists() ) { // 空の ArrayList ArrayList<JsonData> listData = new ArrayList<JsonData>(); // name でソートされたデータを dataSnapshot より取得 Iterator<DataSnapshot> child = dataSnapshot.getChildren().iterator(); while(child.hasNext()) { DataSnapshot next = child.next(); // Firebase API でJsonData に変換 json = next.getValue(JsonData.class); // ArrayList に追加 listData.add(json); } // アダプタをクリア adapter.clear(); // アダプタにデータセット ( listData は name でソートされた ArrayList ) adapter.addAll(listData); // リストビューにデータを表示 listview.setAdapter(adapter); } else { Log.i("lightbox","データを読み込めませんでした"); } // ローディングダイアログを閉じる progress.dismiss(); } @Override public void onCancelled(DatabaseError databaseError) { databaseError.toException().printStackTrace(); Log.i("lightbox","StackTrace を出力しました"); // ローディングダイアログを閉じる progress.dismiss(); } }); } }
NextPage クラス ViewSwitcher の中に include で用意した次画面の処理を行います。MainActivity の中での処理になりますが、別クラスで分離して管理するようにしています。 この中では、Firebase の API を使用して更新処理を行っています。Firebase の更新は、JsonData クラスに必要なデータをセットし、そのまま API へ渡すというとても簡単で解り易い仕様となっています。
public class NextPage { private MainActivity mainActivity; private ViewSwitcher vs; private JsonData json; private View include1; // Firebase private FirebaseDatabase database; private DatabaseReference mDatabase; // コンストラクタ public NextPage(MainActivity mainActivity) { this.mainActivity = mainActivity; } // 処理する行データが外部からセットされる public void setData( JsonData json ) { this.json = json; } // 初期処理 public void initAction(){ // ViewSwitcher( 複数画面処理 ) vs = (ViewSwitcher) mainActivity.findViewById(R.id.viewSwitcher); // activity_next.xml の 親 view を取得 include1 = mainActivity.findViewById(R.id.include1); // Firebase Database 用 database = FirebaseDatabase.getInstance(); mDatabase = database.getReference(); // ***************************************** // 戻るボタンの処理 ( include1 より取得 ) // ***************************************** Button backButton = (Button)include1.findViewById(R.id.backButton); backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 最初の画面へ移動 vs.setDisplayedChild(MainActivity.FIRST_PAGE); } }); // ***************************************** // 更新ボタンの処理 ( include1 より取得 ) // ***************************************** Button updateButton = (Button)include1.findViewById(R.id.updateButton); updateButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EditText et; et = (EditText) include1.findViewById(R.id.editName); json.setName(et.getText().toString()); et = (EditText) include1.findViewById(R.id.editFuri); json.setFuri(et.getText().toString()); et = (EditText) include1.findViewById(R.id.editKyuyo); json.setKyuyo(Integer.parseInt(et.getText().toString())); Spinner spinner; spinner = (Spinner) include1.findViewById(R.id.spinnerSex); json.setSex(String.format("%d",spinner.getSelectedItemPosition())); spinner = (Spinner) include1.findViewById(R.id.spinnerSyozoku); json.setSyozokuFromSpinner(spinner); DatePicker dp = (DatePicker) include1.findViewById(R.id.datePickerBirthday); String stringDate = String.format("%d/%02d/%02d", dp.getYear(),dp.getMonth()+1,dp.getDayOfMonth() ); json.setBirthday(stringDate); Tools.messageBox(mainActivity, "確認", "更新しますか?", new Tools.OnMessageBoxListener() { @Override public void onMessageBoxYesListener() { // 更新 mDatabase .child("class") .child(json.getCode()) .setValue(json) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { Log.i("lightbox", "書き込みに成功しました"); mainActivity.loadData(); // 最初の画面へ移動 vs.setDisplayedChild(MainActivity.FIRST_PAGE); } else { Log.i("lightbox", task.getException().toString()); task.getException().printStackTrace(); Toast.makeText(mainActivity,"更新に失敗しました",Toast.LENGTH_SHORT).show(); } } }); } @Override public void onMessageBoxNoListener() { } }); } }); } }
JsonData クラス データの表示時に Data Binding で使用され、データの取得と更新時には Firebase で使用される、とても重要なクラスです。 特に、テキスト以外の入力値が必要な画面コントロールに対して、Data Binding の @BindingAdapter を使用したカスタムセッターを、数値データ(画面へは文字列なので)、DatePicker、Spinner に合わせて作成してあります。
public class JsonData extends BaseObservable { private String code; private String name; private String furi; // 画面用のカスタムセッターと保存用の カスタムセッター が必要です private String birthday; private long kyuyo; private String sex; // コンボボックス private String syozoku; // コンボボックス // 未使用( 無いと Firebase のデータが消失するので ) public String teate; public String kanri; // ************************************** // Firebase で必要な空のコンストラクタ // ************************************** public JsonData(){} // キーなので setter はありません public String getCode() { return code; } // ************************************** // setter 内で通知するのに、@Bindable を getter に // ************************************** @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; notifyPropertyChanged(lightbox.july.listviewandnextactivity.BR.name); } // ************************************** // フリガナ // ************************************** @Bindable public String getFuri() { return furi; } public void setFuri(String furi) { this.furi = furi; notifyPropertyChanged(lightbox.july.listviewandnextactivity.BR.furi); } // ************************************** // 生年月日 // ************************************** @Bindable public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; notifyPropertyChanged(lightbox.july.listviewandnextactivity.BR.birthday); } @BindingAdapter("dateText") public static void setDateText(DatePicker datePicker, String text) { if ( text != null && !text.equals("")) { int year = Integer.parseInt(text.substring(0, 4)); int month = Integer.parseInt(text.substring(5, 7)) - 1; int day = Integer.parseInt(text.substring(8, 10)); datePicker.updateDate(year, month, day); } } // ************************************** // 給与 // ************************************** @Bindable public long getKyuyo() { return kyuyo; } public void setKyuyo(long kyuyo) { this.kyuyo = kyuyo; notifyPropertyChanged(lightbox.july.listviewandnextactivity.BR.kyuyo); } @BindingAdapter("longKyuyo") public static void setLongKyuyo(EditText editKyuyo, long kyuyo) { editKyuyo.setText(String.format("%d",kyuyo)); } // ************************************** // 性別 // ************************************** @Bindable public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; notifyPropertyChanged(lightbox.july.listviewandnextactivity.BR.sex); } @BindingAdapter("stringSex") public static void setStringSex(Spinner spinnerSex, String sex) { if ( sex != null && !sex.equals("")) { spinnerSex.setSelection(Integer.parseInt(sex)); } } // ************************************** // 所属 // ************************************** @Bindable public String getSyozoku() { return syozoku; } public void setSyozoku(String syozoku) { this.syozoku = syozoku; notifyPropertyChanged(lightbox.july.listviewandnextactivity.BR.syozoku); } // コントロールから、syozoku をセットする Setter // ※ setSyozoku という名称は使えません public void setSyozokuFromSpinner(Spinner spinnerSyozoku) { int position = spinnerSyozoku.getSelectedItemPosition(); ArrayAdapter adapter = (ArrayAdapter) spinnerSyozoku.getAdapter(); KeyValue kv = (KeyValue)adapter.getItem(position); this.setSyozoku(kv.getCode()); } @BindingAdapter("syozokuData") public static void setSyozokuData(Spinner spinnerSyozoku, String syozoku) { if ( syozoku != null && !syozoku.equals("")) { ArrayAdapter adapter = (ArrayAdapter) spinnerSyozoku.getAdapter(); int count = adapter.getCount(); for( int i = 0; i < count; i++ ) { KeyValue kv = (KeyValue) adapter.getItem(i); if ( kv.getCode().equals(syozoku)) { spinnerSyozoku.setSelection(i); break; } } } } @Override public String toString() { return this.name; } }
activity_next.xml 第二画面の定義です。Data Binding 用の記述として、app 名前空間で、カスタムセッターの名称を定義しています。
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="jdata" type="lightbox.july.listviewandnextactivity.JsonData"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/btn_back" android:id="@+id/backButton" android:layout_alignParentTop="true" android:layout_alignParentStart="true" android:layout_weight="1"/> <Button android:text="@string/btn_update" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/updateButton" android:layout_weight="1"/> </LinearLayout> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:text="@{jdata.code}" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:id="@+id/textCode"/> <EditText android:text="@{jdata.name}" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPersonName" android:ems="10" android:id="@+id/editName"/> <EditText android:text="@{jdata.furi}" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPersonName" android:ems="10" android:id="@+id/editFuri"/> <EditText app:longKyuyo="@{jdata.kyuyo}" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" android:ems="10" android:id="@+id/editKyuyo"/> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:layout_marginLeft="5dp"> <Spinner app:stringSex="@{jdata.sex}" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/spinnerSex" android:layout_weight="1" android:layout_marginRight="5dp"/> <Spinner app:syozokuData="@{jdata.syozoku}" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/spinnerSyozoku" android:layout_weight="1"/> </LinearLayout> <DatePicker android:layout_width="match_parent" android:layout_height="wrap_content" android:datePickerMode="spinner" android:calendarViewShown="false" android:id="@+id/datePickerBirthday" app:dateText="@{jdata.birthday}"/> </LinearLayout> </ScrollView> </LinearLayout> </layout>
ListView 用の画面定義( Data Binding 仕様 )
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="jdata" type="lightbox.july.listviewandnextactivity.JsonData"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"> <TextView android:text="@{jdata.name}" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:id="@+id/textItem1" /> <TextView android:text="@{jdata.furi}" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textItem2" android:layout_marginTop="5dp"/> </LinearLayout> </layout>
|
【2016 Android Studioの最新記事】
- Android Studio で Twitter4J で ListView に検索結果を表示する
- Android Studio で Twitter4J で画像付きツイート
- 内部ストレージを起点とした画像データの処理 / Android
- カメラを起点とした画像データの処理 / Android
- バグ : Android Studio 2.2.2 で、spinnerMode を dialog に設定すると app:spinnerMode となってしまいます
- Firebase storage に画像をアップロードする。1) ギャラリーから、2) 実行中の画面 / Android
- Android : 画像関連のテスト用カメラアプリ
- Firebase storage の画像を ファイルとしてダウンロードして ギャラリーに保存する( ImageView にも表示する ) / Android
- Firebase storage の画像の URL を取得して、通常と同様に Stream でダウンロードして ImageView に表示する / Android
- Firebase storage の画像をメモリに直接ダウンロードして ImageView に表示する / Android
- Android : Firebase の データを REST API の PUT コマンドで更新する
- Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。(orderByChild 使う場合は、getChildren ..
- Android : Data Binding + Firebase API で ListView にデータを表示する
- Firebase API + Android Studio : Database 処理の基本設定
- Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出..
- Firebase API + Android Studio : Database にデータを保存は単純で、DatabaseReference の setValue メソッドを使用します