SQLの窓

2017年11月18日


Android : WebView 経由のデータベースアプリケーション



HTTP で直接通信すると手っ取り早いですが、いかんせん汎用性に欠けます。WebView を使うと途中のデバッグそのものが、他の開発に転用できそうなのでいいと思います。とにかく、いろいろ手順が満載です。

1) Android で入力した値を引数としてページに渡す

これは一番簡単です。javascript:以降に関数名を記述して、引数を文字列として埋め込んで loadUrl するだけです。
EditText et = (EditText) MainActivity.this.findViewById(R.id.editText);
String scode =((EditText) MainActivity.this.findViewById(R.id.editText)).getText().toString();
String callString = String.format("javascript:getWebPageData(\"%s\")",scode);
wv.loadUrl(callString);
※ API level 19 から  evaluateJavascript が追加されています。こちらでは、JavaScript の戻り値を 非同期で UI スレッド上で得る事ができます

全体のソースコードはこちら

関連する記事

WebView で JavaScript にデータを渡したい時に注意する事

2) Webページでは、jQueryでサーバーから必要な値を取得
$.get("dbdata_json.php?scode="+scode,function( data ){
	if ( typeof androidObject !== 'undefined' ) {
		// サーバから受け取った application/json データ
		// を文字列に変換して Android に渡します
		androidObject.toAndroid(JSON.stringify(data));
	}
	else {
		// 通常のブラウザではこちらが実行されます
		console.log(JSON.stringify(data,null,"   "));
	}
})
全体のソースコードはこちら

3) サーバーのPHPは、DBのデータをJSONで返す
$_GET["scode"] = str_replace("'","''",$_GET["scode"]);
$result = $connect->query("select * from 社員マスタ where 社員コード = '{$_GET["scode"]}'"); 
if ( !$result ) {
	die('クエリーに誤りがあります : ' . $connect->error );
}

// 内容を書き込むファイルの準備
$log_file = "rowdata_002.json";
file_put_contents( $log_file,"" );

$check = false;
while ($row = $result->fetch_array($db_data_type)) {

	$check = true;
	print json_encode($row,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
	print "\n";

	// ファイルに追加出力
	file_put_contents( $log_file, print_r(json_encode($row,$json_type)."\n",true), FILE_APPEND );
}

全体のソースコードはこちら

file_put_contents は、デバッグ用です。処理には直接必要ありません

4) WEBページは JSON の文字列を Android に送る

さて、ここが重要な Android 側のインターフェイスの定義が必要なところです。専用のクラスを作成して、Activity 内の変数を使いやすいように、インターフェイスを定義して処理を外に出しています

JavaScriptAccess クラス
package sample.lightbox.webbrowser;

import android.util.Log;
import android.webkit.JavascriptInterface;

/**
 * Created by lightbox on 2015/09/24.
 */
public class JavaScriptAccess {
	// Webページからデータを取得するイベント用
	public interface OnGetWebDataListener {
		abstract public void onWebGetDataListener( String textData );
	}

	private OnGetWebDataListener ogwdl = null;

	public JavaScriptAccess( OnGetWebDataListener ogwdl ) {
		this.ogwdl = ogwdl;
	}

	// Webページ上の JavaScript から、Android Studio の logcat に表示します
	@JavascriptInterface
	public void logcat(String message) {
		Log.i("lightbox", message);
	}

	// コンストラクタで取得したインターフェイスのインスタンス内のメソッドを
	// 呼び出して、Webページから取得したデータを渡します
	@JavascriptInterface
	public void toAndroid(String message) {
		this.ogwdl.onWebGetDataListener(message);
	}


}

この定義を使用しているのは、WebView の addJavascriptInterface メソッドですが、これによって、WEBページから Andrpod のこのクラスの内部で定義されたメソッドを実行可能になります。

全体のソースコード

WEBページから呼ばれると、onWebGetDataListener 内が実行されます

5) JSON文字列を Gson で Android 内のオブジェクトに変換

Syain というクラスを定義しておいて、Google Gson で gson.fromJson(textData,Syain.class) を実行してインスタンを取得します。

▼ Syain クラス
public class Syain {
	String 社員コード;
	String 氏名;
	String フリガナ;
	String 所属;
	int 性別;
	String 作成日;
	String 更新日;
	int 給与;
	int 手当;
	String 管理者;
	String 生年月日;
}

日本語を使っているのは、テーブル定義が日本語なのでそのまま利用できるからです。(Google Gson を使用しますが、JSON 側の名前と一致したものがこちらにあれば良く、全てある必要はありませんし、JSON側に無いものがあってもかまいません)

※ compile 'com.google.code.gson:gson:x.x.x' を build.gradle に記述

6) UI スレッドへその値を送る

要するに画面に値をセットするだけですが、JavaScript のインターフェイスが別スレッドなので、runOnUiThread を使用します
try {
	syain = gson.fromJson(textData,Syain.class);

	// 別スレッドから UI スレッドへのアクセス
	MainActivity.this.runOnUiThread(new Runnable() {
		@Override
		public void run() {
			TextView tv = (TextView) MainActivity.this.findViewById(R.id.textView);
			tv.setText(syain.氏名);
		}
	});

} catch (Exception e) {
	e.printStackTrace();
}
全てのソースコード

dbdata_json.php は、データベースの部分なので、WEB上にも用意しました
(※ WEB上のソースコードはこちら)

実機でテストする場合必要なので、001.php も WEB上に用意しました

関連する記事

WebView で JavaScript にデータを渡したい時に注意する事

Android で WebView を使ってWEBにあるデータベースのデータを取得する為のクラス





posted by lightbox at 2017-11-18 14:46 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

2017年11月17日


Android で WebView を使ってWEBにあるデータベースのデータを取得する為のクラス

WebView は非表示で良く、HTTP の機能のみ必要です。その為、最低限必要な機能を WebView を継承して実装しています

※ compile 'com.google.code.gson:gson:2.8.2' を使用

DataWebView.java
import android.content.Context;
import android.util.AttributeSet;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class DataWebView extends WebView {

	public DataWebView(Context context) {
		super(context);
		init();
	}
	public DataWebView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	public DataWebView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	private void init(){
		// 編集モードの場合は処理を行わない
		if (isInEditMode()) {
			return ;
		}

		this.getSettings().setDomStorageEnabled(true);
		this.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
		this.getSettings().setJavaScriptEnabled(true);

		this.setWebViewClient(new WebViewClient() {

			@Override
			public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
				return false;
			}
		});

	}

}


Android と WebView 内の JavaScript とのインターフェイスです

JavaScriptAccess.java
import android.util.Log;
import android.webkit.JavascriptInterface;

public class JavaScriptAccess {

	// Webページからデータを取得するイベント用
	public interface OnGetWebDataListener {
		abstract public void onWebGetDataListener( String textData );
	}

	private OnGetWebDataListener ogwdl = null;

	public JavaScriptAccess( OnGetWebDataListener ogwdl ) {
		this.ogwdl = ogwdl;
	}

	@JavascriptInterface
	public void logcat(String message) {
		Log.i("lightbox", message);
	}

	@JavascriptInterface
	public void toAndroid(String message) {
		this.ogwdl.onWebGetDataListener(message);
	}

}


JavaScriptAccess によって(インターフェイス経由の onWebGetDataListener の呼び出し)、JavaScript から呼び出された時のイベントとして、こちら側で処理が可能になっています。

但し、非同期の処理の為、UI スレッドへは直接アクセスできないので、runOnUiThread を使用しています。

MainActivity での実装部分
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.google.gson.Gson;

public class MainActivity extends AppCompatActivity {

	private DataWebView dataWebView;
	private Gson gson;
	private Syain syain;

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

		gson = new Gson();
		dataWebView = (DataWebView) MainActivity.this.findViewById(R.id.webView);

		MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {

				// 呼び出し( 後は、JavaScriptAccess のイベントで待つ )
				String callString = String.format("getWebPageData(\"%s\")", "0001");
				dataWebView.evaluateJavascript(callString,null);

			}
		});

		// JavaScript からの戻り
		dataWebView.addJavascriptInterface(new JavaScriptAccess(new JavaScriptAccess.OnGetWebDataListener() {
			@Override
			public void onWebGetDataListener(String textData) {

				syain = gson.fromJson(textData, Syain.class);
				MainActivity.this.runOnUiThread(new Runnable() {
					@Override
					public void run() {

						TextView textView1 = (TextView) MainActivity.this.findViewById(R.id.textView1);
						textView1.setText(syain.scode);

						TextView textView2 = (TextView) MainActivity.this.findViewById(R.id.textView2);
						textView2.setText(syain.kj);

					}
				});

			}
		}), "androidObject");

		dataWebView.loadUrl("http://winofsql.jp/002.php");
	}
}


画面定義
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button"/>

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textSize="30sp"/>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:textSize="30sp"/>

    <com.example.lightbox.webviewtest.DataWebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"/>


</LinearLayout>


Syain クラス
public class Syain {

	public String scode;
	public String kj;
	public String furi;
	public String syozoku;
	public String seibetu;
	public String kyuyo;
	public String teate;
	public String kanri;
	public String birth;
	public String sname;

}


Web 側の定義( JavaScript / HTML )

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
// **************************************
// Android から呼ばれる場合
// console.log は Android 側で表示
// **************************************
if ( typeof androidObject !== 'undefined' ) {
	window.console.log = function(message){
		androidObject.logcat(message);
	}
}

function getWebPageData(scode) {

	$("#param").val(scode);
	// ***************************************
	// Android WebView の中のこのページ
	// より、サーバへアクセスします
	// ***************************************
	$.get("dbdata2_json.php?scode="+scode,function( data ){
		$("#result").val(JSON.stringify(data));
		if ( typeof androidObject !== 'undefined' ) {
			// サーバから受け取った application/json データ
			// を文字列に変換して Android に渡します
			androidObject.toAndroid(JSON.stringify(data));
		}
		else {
			// 通常のブラウザではこちらが実行されます
			console.log(JSON.stringify(data,null,"   "));
		}
	})
}
function setWebPageData(sdata) {

	$("#param").val(sdata);
	// ***************************************
	// Android WebView の中のこのページ
	// より、サーバへアクセスします
	// ***************************************
	$.get("dbdata_update_json.php?sdata="+encodeURIComponent(sdata),function( data ){
		$("#result").val(JSON.stringify(data));
		if ( typeof androidObject !== 'undefined' ) {
			// サーバから受け取った application/json データ
			// を文字列に変換して Android に渡します
			androidObject.toAndroid(JSON.stringify(data));
		}
		else {
			// 通常のブラウザではこちらが実行されます
			console.log(JSON.stringify(data,null,"   "));
		}
	})
}
</script>
</head>
<body>
<pre>
<input type="button" value="logcat test" onclick="androidObject.logcat('OK')">

<input type="button" value="toAndroid test" onclick="getWebPageData('0001')">

<input type="button" value="toAndroid update" onclick='setWebPageData(&#39;{"birth":"2000/10/1","furi":"ウラオカ トモヤ","kj":"浦岡 友也","kyuyo":"270000","scode":"0001","seibetu":"0","sname":"営業部第三","syozoku":"0003","teate":"9000"}&#39;)'>

<a href="dbdata2_json.php?scode=0001">リンク</a>

<textarea id="param" style="width:100%;height:100px;"></textarea>
<textarea id="result" style="width:100%;height:100px;"></textarea>

</pre>
</body>
</html>


関連する記事

WebView で JavaScript にデータを渡したい時に注意する事




posted by lightbox at 2017-11-17 21:48 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

WebView で JavaScript にデータを渡したい時に注意する事

いろいろ注意事項はありますが、Android の技術情報は年月で変化して行くので、まずそのへんをしっかり押さえておく必要があります。

年月で変化

1) WebView の JavaScript のアクセスに loadUrl を使ってはいけない
( 厳密に言うと使ってはいけないわけでは無いと思いますが、ブックマークレットのような使い方は後々の為に避けたほうがいいし、evaluateJavascript なら非同期で戻り値を得られるわけですから使う意味もありません。戻り値がいらないなら callback を null にすればいいですし )

Android公式ドキュメント Migrating to WebView in Android 4.4 の翻訳ページ
代わりに、新しいメソッドとして evaluateJavascript を JavaScript を非同期で実行させるために使用してください。
(Android 4.4 : API level 19 : KitKat で追加)
実際、JavaScript の結果を "文字列" としてイベントで取得できるので、使いやすいです。但し、帰って来た文字列が "(ダブルクォート) で挟まれているので Android 側で取り去る必要があります。 2) WebViewClient の shouldOverrideUrlLoading(WebView view, String url) が非推奨になった (Android 7.0 : API level 24 : Nougat から) 代わりに、shouldOverrideUrlLoading(WebView view, WebResourceRequest request) を使用します (Android 7.0 : API level 24 : Nougat で追加) 一般 WEB では使えない これらが目新しい変化ですが、そもそも WebView では一般の WEB ページを表示させる事を想定していないようで、無闇に使用すると良く解らないトラブルが発生します。 1) opener が使用できない いろいろ調べましたが、良く解りません。どうやら、WebChromeClient を使って自分で代替処理を作る必要があるようです。( 参考 : WebChromeClientで使える関数のまとめ / onCreateWindow ) 2) localStorage を使っているページに注意 setDomStorageEnabled(true) を実行せずに、そのページで localStorage が処理されると、JavaScript 側のメモリがぶっ壊れて、変数がおかしくなりました。 これは、動作しないとかでは無くぶっ壊れるのでバグの部類です。という事は、他のオプションでも何があるか解らないので一般の WEB ページのように自分ではコントロールできないものを表示すべきでは無いと言う事です。ちなにみに、Android の Chrome では正常に動作しています。ただ、キャッシュの操作や履歴の操作等、いずれにしても問題は多くあります。 JavaScript から Android の UI データを取得に注意 JavaScript から Android とのやり取りは、@JavascriptInterface で定義される public なメソッドですが、JavaScript から 呼び出されたそれらのメソッドは、UI スレッドでは無いところが重要です。 特に問題の無い一方通行 JavaScript => Android JavaScript からデータを JSON 文字列で渡せば、たいていの情報を簡単に渡す事ができ、受け取った Android のメソッドでは Google Gson でデシリアライズすれば、runOnUiThread でそのまま画面に対して有効利用できるはすです。 非同期の為、Android で 画面データを return できない しかし、JavaScript の呼び出しで Android が値を返す場合は、UI スレッドへのアクセスが終わる前に戻り地を返す必要が出てきます。結局一度では無理があるので、通常の Android のように リクエストコードを使用して呼び出してもらい、画面データを用意してから Android から JavaScript のメソッドを呼び出すだけにします。 そして、その Android から呼び出された JavaScript 側のメソッド内から、再度 JavascriptInterface を持ったメソッドを呼び出すようにするのがいいでしょう。 実行画面 JAVASCRIPT からデータを取得 (Android 側 : 行28〜行56) JAVASCRIPT からデータを取得ボタンをクリックした結果です。取得するのは、一番下にある文字列で、WebView 内の テキストフィールドです。これは最も単純で、evaluateJavascript を使用して jQuery の文字列を直接渡してフィールドの結果を取得し、イベントで Android 内に戻って来ます。この文字列は ダブルクォート で挟まれているので、元の表示とダブルクォートを取り去った表示を同時に行っています。 JAVASCRIPT へデータを送る 単純に考えてしまうと、JavaScript の引数に文字列を指定すればいいですが、とても煩雑で問題が出そうです。ですから、データを用意した後、いったん『getAndroidUIData』を "request-02" のリクエストで呼び出して、『getAndroidUIData』 内から Android を呼び出す(getRequestData) 事によって、必要な文字列を JavaScript のメソッドの戻り値で取得するようにしています。 Android 側
public class MainActivity extends AppCompatActivity {

	private WebView webview;
	private JsonDataList jsonDataList = null;
	private Gson gson;

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

		gson = new Gson();
		jsonDataList = gson.fromJson("{\"item\": [\n" +
				"        {" +
				"            \"text\": \"\"," +
				"            \"subject\": \"\"," +
				"            \"name\": \"\"," +
				"            \"datetime\": \"\"" +
				"        }]}",JsonDataList.class);

		// *****************************
		// JavaScript からデータを取得
		// *****************************
		MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				EditText et;
				et = (EditText) MainActivity.this.findViewById(R.id.editSubject);
				jsonDataList.item[0].subject = et.getText().toString();
				et = (EditText) MainActivity.this.findViewById(R.id.editText);
				jsonDataList.item[0].text = et.getText().toString();

				// jQuery でそのまま実行
				String script = "$('#android_data').val();";

				webview.evaluateJavascript(script, new ValueCallback<String>() {
					@Override
					public void onReceiveValue(String s) {

						EditText et;

						// そのまま表示
						et = (EditText) MainActivity.this.findViewById(R.id.editSubject);
						et.setText(s);

						// ダブルクォート削除
						et = (EditText) MainActivity.this.findViewById(R.id.editText);
						if (s != null ) {
							String wk = s;
							wk = wk.substring(1, wk.length() - 1);
							et.setText(wk);
						}

					}
				});

			}
		});

		// *****************************
		// JavaScript へデータを送る
		// *****************************
		MainActivity.this.findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				EditText et;
				et = (EditText) MainActivity.this.findViewById(R.id.editSubject);
				jsonDataList.item[0].subject = et.getText().toString();
				et = (EditText) MainActivity.this.findViewById(R.id.editText);
				jsonDataList.item[0].text = et.getText().toString();

				String script = "getAndroidUIData(\"request-02\");";

				Log.i("lightbox", script);

				webview.evaluateJavascript(script,null);

			}
		});

		webview = (WebView) MainActivity.this.findViewById(R.id.webView);
		webview.getSettings().setDomStorageEnabled(true);
		webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
		// 必ず必要な JavaScript を有効にする設定
		webview.getSettings().setJavaScriptEnabled(true);

		JavaScriptAccess jsa = new JavaScriptAccess();
		// **********************************
		// 第二引数の文字列が、WebView の中のページの
		// JavaScript より使用可能になります
		// **********************************
		webview.addJavascriptInterface(jsa,"myAndroidObject");
		// 必ず必要な設定
		webview.setWebViewClient(new WebViewClient(){

			// 必ず必要な設定 : 常に WebView 内でページを表示する為
			@Override
			public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
				return false;
			}

		});

		// 目的のページを表示する
		webview.loadUrl("https://lightbox.sakura.ne.jp/homepage/demo/data/csvtype/android.html");

	}

	// **********************************
	// JavaScript 用クラス
	// **********************************
	private class JavaScriptAccess {

		@JavascriptInterface
		public void log(String message) {

			Log.i("lightbox",message);

		}

		@JavascriptInterface
		public void clear() {

			webview.clearHistory();
			webview.clearCache(true);

		}

		// **************************************
		// JavaScript から Android へデータを送る
		// **************************************
		@JavascriptInterface
		public void setAndroid(String json) {

			Log.i("lightbox","setAndroid");

			jsonDataList = gson.fromJson(json,JsonDataList.class);

			runOnUiThread(new Runnable() {
				@Override
				public void run() {

					EditText et;
					et = (EditText) MainActivity.this.findViewById(R.id.editSubject);
					et.setText(jsonDataList.item[0].subject);
					et = (EditText) MainActivity.this.findViewById(R.id.editText);
					et.setText(jsonDataList.item[0].text);

				}
			});

		}

		// **************************************
		//  Android 内の データを JavaScript へ戻す
		// **************************************
		@JavascriptInterface
		public String getAndroid() {

			Log.i("lightbox","getAndroid");

			String result = gson.toJson(jsonDataList.item[0],JsonData.class);

			return result;
		}

		// **************************************
		//  UI データを JavaScript へ戻す
		// **************************************
		@JavascriptInterface
		public String getRequestData(String requestCode) {

			Log.i("lightbox","getRequestData");

			String result = "";

			if ( requestCode.equals("request-01")  ) {

				result = gson.toJson(jsonDataList.item[0],JsonData.class);

			}
			if ( requestCode.equals("request-02")  ) {

				result = gson.toJson(jsonDataList.item[0],JsonData.class);

			}

			return result;

		}

		// **************************************
		// JavaScript から UI データのリクエスト
		// **************************************
		@JavascriptInterface
		public void requestAndroid(String requestCode) {

			Log.i("lightbox","requestAndroid");

			if ( requestCode.equals("request-01")  ) {
				runOnUiThread(new Runnable() {
					@Override
					public void run() {

						EditText et;
						et = (EditText) MainActivity.this.findViewById(R.id.editSubject);
						jsonDataList.item[0].subject = et.getText().toString();
						et = (EditText) MainActivity.this.findViewById(R.id.editText);
						jsonDataList.item[0].text = et.getText().toString();

						String script = "getAndroidUIData(\"request-01\");";

						Log.i("lightbox",script);

						// JavaScript からの戻りを必要としない
						webview.evaluateJavascript(script, null);

					}
				});

			}

		}

	}

	private class JsonData  {

		String text;
		String subject;
		String name;
		String datetime;

	}

	private class JsonDataList {
		JsonData[] item;
	}
}


JavaScript 側
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
* {
	font-size:18px;
}
div {
	white-space: pre-wrap;
	word-wrap: break-word;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
// **************************************
// Android から呼ばれる場合
// console.log は Android 側で表示
// **************************************
if ( typeof myAndroidObject !== 'undefined' ) {
	window.console.log = function(message){
		myAndroidObject.log(message);
	}
}

// **************************************
// Android から呼ばれる関数
// **************************************
function getAndroidUIData( requestCode ) {

	console.log("JavaScript:getAndroidUIData:" + requestCode)

	var result;

	if ( requestCode == "request-01" ) {

		result = myAndroidObject.getRequestData( requestCode )

		console.log("JavaScript:getAndroidUIData:result:" + result);

		var json = JSON.parse(result);
		
		$("#android_data").val( json.subject );


	}

	if ( requestCode == "request-02" ) {

		result = myAndroidObject.getRequestData( requestCode )

		console.log("JavaScript:getAndroidUIData:result:" + result);

		$("#json").text( result );


	}

	return requestCode;

}

$( function(){

	// **************************************
	// Android へデータを送る
	// **************************************
	$("#set_android").on("click",function(){

		$.get("json.php",function( data ){
			if ( typeof myAndroidObject !== 'undefined' ) {
				// サーバから受け取った application/json データ
				// を文字列に変換して Android に渡します
				myAndroidObject.setAndroid(JSON.stringify(data));
			}
			else {
				// 通常のブラウザではこちらが実行されます
				console.log(JSON.stringify(data,null,"   "));
			}
		})

	});

	// **************************************
	// Android から画面データを取得する
	// **************************************
	$("#get_android").on("click",function(){

		if ( typeof myAndroidObject !== 'undefined' ) {
			// サーバから受け取った application/json データ
			// を文字列に変換して Android に渡します
			myAndroidObject.requestAndroid("request-01");
		}
		else {
			// 通常のブラウザではこちらが実行されます
			console.log("なにも実行しません");
		}
		

	});


} );
</script>
</head>
<body>
<input type="button" id="set_android" value="Android へデータを送る">
<br>
<input type="button" id="get_android" value="Android から画面データを取得する">
<br>
<input type="text" id="android_data">
<br>
<div id="json">
</div>
</body>
</html>



画面定義
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.lightbox.webviewjavascript.MainActivity">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/scrollView">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="JavaScript からデータを取得"
                android:id="@+id/button"/>

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="JavaScript へデータを送る"
                android:id="@+id/button2"/>

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/editSubject"/>

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/editText"/>

            <WebView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/webView"/>
        </LinearLayout>
    </ScrollView>

</LinearLayout>


関連する記事

Android で WebView を使ってWEBにあるデータベースのデータを取得する為のクラス

JavaScript から Android へアクセス

Android : WebView 経由のデータベースアプリケーション






posted by lightbox at 2017-11-17 15:58 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

2016年10月21日


シンプル Android Data Binding : Android Studio 2.2 / 古い定義との違いと、以前のプロジェクトでエラーが出る場合の対処

▼ 記事内のソースコードへ移動
@BindingAdapter でカスタムセッター
Syain クラスへ直接セットして表示
Google Gson と tools.jar を使用した REST API 経由の読み込み
Firebase API を使用した読込み


プロジェクトの Gradle に classpath "com.android.databinding:dataBinder:1.0-rc1" は必要ありません
Module(app) の Gradle に
    dataBinding {
        enabled = true
    }
があれば動作します
去年より地味に進化していました。build.gradle(Module: app) の簡単な設定で利用可能になります build.gradle(Module: app)
apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "23.0.3"

    dataBinding {
        enabled = true
    }

    defaultConfig {
        applicationId "lightbox.june.bindingbasic"
        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'
}

バインド用のクラスには、後々 Google Gson 使うので 超単純にしています。

※ @BindingAdapter はテキストを直接使えないコントロール用のカスタムセッターです

Syain.java

@{user.birthday} が app:dateText にセットされるよう画面で定義されているので、birthday が setDateText の引数として渡されます。
public class Syain {

	public String code;
	public String name;
	public String birthday;

	@BindingAdapter("dateText")
	public static void setDateText(DatePicker datePicker, String text) {

		if ( text != null && !text.equals("")) {
			Log.i("lightbox",text);

			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);
		}

	}
}

画面も、layout 要素の記述がスリムになりました。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="user" type="lightbox.june.bindingbasic.Syain"/>
    </data>

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="16dp">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/textView"
                android:textSize="40dp"
                android:text="@{user.code}"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/textView2"
                android:layout_marginTop="20dp"
                android:textSize="40dp"
                android:text="@{user.name}"/>

            <DatePicker
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/datePicker"
                android:layout_below="@+id/textView2"
                android:datePickerMode="spinner"
                android:calendarViewShown="false"
                app:dateText="@{user.birthday}"/>

        </LinearLayout>

</layout>

さて、MainActivity ですが、Android の公式ページがいまだに誤記しているのがタマに傷です。R.layout.main_activity では無く、R.layout.activity_main です。当たり前ですけれど。コピペするとえらい目にあいます。

MainActivity.java

最も単純なバインドのサンプルです。Syain クラスはコンストラクタも無く、JSON のプロパティは、public の同名の変数にセットされます。コメント部分は、JSON 文字列から Syain のインスタンスを作成して使用するパターンです( Google Gson は コンストラクタを使用しません )
package lightbox.june.bindingbasic;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import lightbox.june.bindingbasic.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

	private ActivityMainBinding binding;

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

		binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

//		String json = "{\"code\": \"0001\",\"name\": \"やまだ たろう\",\"birthday\": \"1959/10/10\"}";
//		Gson gson = new Gson();
//		Syain user = gson.fromJson(json,Syain.class);

		Syain user = new Syain();
		user.code = "0001";
		user.name = "やまだ たろう";
		user.birthday = "1959/10/10";

		binding.setUser(user);

	}
}

これで動くはずですが、良く解らないエラーが出る場合は以下の二つを試すといいはずです。画面に関しては以前からある問題点で、さらに動くまでは画面定義に日本語は直接書かないほうがいいと思います。

エラー時の対処 : パターン1
1) 画面定義の data 要素部分を削除してすぐ戻す
2) エラーが出るソースを開くと DataBindingUtil 部分のエラーがなくなる
3) binding.メソッドのエラーが残るので、プロジェクトをいったん閉じて開く
エラー時の対処 : パターン2
1) 画面定義の activity_main.xml を activity_main2.xml に変更して すぐに activity_main に戻す
2) ファイルメニューの Invalidate Caches / Restart を実行
Data Binding Android - Type parameter T has incompatible upper bounds : ViewDataBinding and MainActivity DataBindingUtil.setContentView - Type parameter T has incompatible upper bounds Google Gson と tools.jar を使用した読み込み ※ URL は、Firebase のログインの必要無いデータを使用しています
public class MainActivity extends AppCompatActivity {

	private ActivityMainBinding binding;

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

		// Data Binding 仕様の画面表示
		binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

		// アクセスする URL 
		String url = "https://freebase-44e8b.firebaseio.com/class/0001.json?print=pretty";
		// URL から読み込み
		Tools.callHttpGet(url, "utf-8", new Tools.OnAsyncTaskListener() {
			@Override
			public void onAsyncTaskListener(String s) {
				Log.i("lightbox", s);
				Gson gson = new Gson();
				// JSON 文字列を Syain クラスのインスタンスに変換
				Syain user = gson.fromJson(s,Syain.class);
				// Data Binding で画面にデータをセット
				binding.setUser(user);
			}
		});

	}
}
Firebase Database REST API のドキュメント
Google Gson のダウンロード
tools.jar のダウンロード


Firebase API を使用した読込み
public class MainActivity extends AppCompatActivity {

	private ActivityMainBinding binding;
	private FirebaseDatabase database;
	private DatabaseReference mDatabase;

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

		// Data Binding 仕様の画面表示
		binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

		// Firebase database 参照用
		database = FirebaseDatabase.getInstance();
		mDatabase = database.getReference();

		// データの参照
		mDatabase.child("class/0001").addListenerForSingleValueEvent(new ValueEventListener() {
			@Override
			public void onDataChange(DataSnapshot dataSnapshot) {
				// 取得したデータを Syain クラスのインスタンスとして取得
				Syain user = dataSnapshot.getValue(Syain.class);
				// Data Binding で画面にデータをセット
				binding.setUser(user);

			}

			@Override
			public void onCancelled(DatabaseError databaseError) {
				// Firebase database の参照に失敗した時の処理
				// ※ 参照権限がない場合等
			}
		});

	}
}

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







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

2016年10月10日


Android Studio で、ListView アプリケーションを作成するテンプレート

全てのソースコード



仕様の概略
1) MainActivity には ListView コントロールのみ
2) ListView 内に TextView は縦に2項目
3) NextActvity には、元へ戻るボタンと TextView が一つ
※ MyArrayAdapter を private で 一つのソースに記述しています。インターネットから JSON データを取得して ListView に表示します (https://lightbox.sakura.ne.jp/homepage/demo/data/csvtype/json.php) ➡ インターネットへのアクセスは、tools.jarTools.callHttpGet を使用します。 ➡ 読み出した JSON 文字列を Google Gson でデシリアライズして、JsonDataList にセットします。( リンク先には クラス定義があります ) このオブジェクトを ArrayAdapter<JsonData> を継承した MyArrayAdapter にセットし、ListView に MyArrayAdapter をセットして ListView を表示します。 ListView には、setOnItemClickListener で行をクリックしたイベントを定義し、その中で 行データを Intent にセットして次画面へ移動します。 次画面では、受け取った行データより、本文を取得して画面の TextView へ表示します。 MainActivity
public class MainActivity extends AppCompatActivity {

	private final int MY_REQUEST_CODE = 1000;
	private ListView listview;

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

		// リストビューの取得
		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();
				// 行データを取得
				JsonData json = (JsonData)adapter.getItem(position);

				// 引渡しデータを作成
				Intent intent = new Intent(MainActivity.this,NextActivity.class);
				intent.putExtra("DATA","こんにちは");
				// Serializable インターフェイスなのでまとめて渡す
				intent.putExtra("OBJECT",json);

				// 画面移動
				MainActivity.this.startActivityForResult(intent,MY_REQUEST_CODE);
			}
		});

		// JSON データの URL
		String json_url = "https://lightbox.sakura.ne.jp/homepage/demo/data/csvtype/json.php";
		// tools.jar の static メソッド
		Tools.callHttpGet(json_url, "utf-8", new Tools.OnAsyncTaskListener() {
			@Override
			public void onAsyncTaskListener(String s) {

				// JSON データをデシリアライズ
				Gson gson = new Gson();
				JsonDataList jdl = gson.fromJson(s, JsonDataList.class);

				// アダプタを作成して、データをセット
				MyArrayAdapter adapter
					= new MyArrayAdapter(MainActivity.this,R.layout.list_item);
				// jdl.item は配列
				adapter.addAll(jdl.item);

				// リストビューにデータを表示
				listview.setAdapter(adapter);

			}
		});
	}


	// ******************************
	// 次画面から戻って来た時の処理
	// ******************************
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		if ( requestCode == MY_REQUEST_CODE ) {
			// NextActivity の 戻るボタン以外で戻ると 0
			Log.i("lightbox",String.format("NextActivity からの戻り値 : %d", resultCode));
			if ( data != null ) {
				String message = data.getStringExtra("DATA");
				Log.i("lightbox",String.format("NextActivity からのメッセージ : %s", message));
			}
		}

	}

	// ******************************
	// JsonData を格納する、この処理専用の
	// ArrayAdapter のカスタマイズ
	// ******************************
	private class MyArrayAdapter extends ArrayAdapter<JsonData> {

		// コンストラクタで渡された画面の保存
		private int mResource;

		public MyArrayAdapter(Context context, int resource) {
			super(context, resource);
			// ArrayAdapter でも、このようにして保存して利用してます
			mResource = resource;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			if (convertView == null) {
				// 現在の View の取得
				LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService
					(Context.LAYOUT_INFLATER_SERVICE);
				convertView = inflater.inflate(mResource, null);
			}

			// アダプターより行データを取得
			JsonData json = MyArrayAdapter.this.getItem(position);

			// 画面にデータをセット
			TextView tv;

			// Subject
			tv	= (TextView) convertView.findViewById(R.id.textItem1);
			tv.setText(json.getSubject());

			// Name
			tv = (TextView) convertView.findViewById(R.id.textItem2);
			tv.setText(json.getName());

			// 行の画面をシステムに返す
			return convertView;
		}

	}

}

MainActivity での特記事項onItemClick 内での 行データの参照は、parent.getAdapter() によって、使用しているアダプターを取得します。
JsonData は、そのまま Intent にセットする為に Serializable インターフェイスを実装しています
JsonData へのデータのセットは、Google Gson 経由を想定しているので、setter および コンストラクタは定義していません
JsonData の getText 以外のメソッドはここでは使用しませんが、仕様の拡張を想定した最低限必要と判断したものです。特に、toString は、システムが用意した一つの項目しかない行を定義した画面で使う為に必要です(ここでは必要ありません)。
MyArrayAdapter で画面 id を内部保存しているのは、ArrayAdapter のソースコードに準じたものです


tools.jar は、ソースコードを簡略化する為のテスト用のライブラリです。本番には相応のコードを用意します。

NextActivity


public class NextActivity extends AppCompatActivity {

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

		// 引き渡された Intent を取得
		Intent intent = NextActivity.this.getIntent();
		// 文字列のデータを取り出す
		String message = intent.getStringExtra("DATA");
		Log.i("lightbox",String.format("MainActivity からのメッセージ : %s", message));
		// Serializable オブジェクトを取り出す
		JsonData json = (JsonData) intent.getSerializableExtra("OBJECT");

		// 画面へデータをセット
		TextView tv = (TextView) NextActivity.this.findViewById(R.id.textView);
		// text データ上の 改行文字列を実際の改行に変換する
		String text = json.getText();
		text = text.replace("\\n", "\n");
		tv.setText(text);

		// MainActivity へ戻る為のボタン
		Button button = (Button) NextActivity.this.findViewById(R.id.backButton);
		button.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {

				// 戻る時にも Intent を引き渡す
				Intent intent = new Intent();
				intent.putExtra("DATA", "今戻りました");
				// MainActivity で受け取る int データをセットする
				NextActivity.this.setResult(NextActivity.RESULT_OK,intent);
				// この画面を終了して MainActivity へ戻る
				NextActivity.this.finish();

			}
		});

	}
}

NextActivity での特記事項

Android Studio では、New => Activity で作成しており、AndroidManifest への定義は自動的に追加されます。


全てのソースコード


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

2016年09月27日


Android : Data Binding で ListView へのデータ表示を凄く簡単にする

2016/09/27 : Data Binding の最新の仕様に合わせて内容を調整しました
( Gradle の変更は Module(app)用の gradle のみです )
2015/10/5 時点で、バグと思われる注意事項があります。XML のレイアウト定義内に日本語があると、バインドする為の解析処理が失敗するようです。文字列リソースに日本語を定義して参照するのなら問題ありません。 また、何か(ビルド上の不可解な)問題が出た場合、以下のような処理で復帰できると思います。
1) 画面定義の data 要素部分を削除してすぐ戻す
2) エラーが出るソースを開くと DataBindingUtil 部分のエラーがなくなる
3) binding.メソッドのエラーが残るので、プロジェクトをいったん閉じて開く
バインド用のクラスは自動作成されますが、画面定義したレイアウトファイル名から作成されます。 activity_main なら、ActivityMainBinding となります MainActivity.java
package sample.lightbox.myapplication;

import android.app.Activity;
import android.content.Context;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import sample.lightbox.myapplication.databinding.ActivityMainBinding;
import sample.lightbox.myapplication.databinding.MyitemBinding;


public class MainActivity extends Activity {

	TestArrayAdapter<Item> adapter = null;

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


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

		final Item[] items = {
				new Item("あ","0001"),new Item("い","0002"),new Item("う","0003"),
				new Item("え","0004"),new Item("お","0005"),new Item("か","0006"),
				new Item("き","0007"),new Item("く","0008"),new Item("け","0009"),
				new Item("こ","0010")
		};

		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);
						}
						myitem.setItem(items[position]);

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

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

		// ボタンを押して、オブジェクトの変更のみで反映されます
		MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				user.setFirstName("鈴木");
				user.setLastName("ジロウ");
				items[0].setText("getView での記述が簡単になりました");
				items[9].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(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);
		}
	}

}

TestArrayAdapter は、getView をカスタマイズしやすくする為のクラスです。

activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">

	<data>
		<variable name="user" type="sample.lightbox.myapplication.MainActivity.User"/>
	</data>
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="10dp">

		<TextView android:layout_width="match_parent"
				  android:layout_height="wrap_content"
				  android:textSize="26dp"
				  android:text="@{user.firstName}"
				  android:id="@+id/textView"/>
		<TextView android:layout_width="match_parent"
				  android:layout_height="wrap_content"
				  android:textSize="26dp"
				  android:text="@{user.lastName}"/>

		<Button
			android:layout_width="match_parent"
			android:layout_height="wrap_content"
			android:text="@string/button_1"
			android:id="@+id/button"/>

		<ListView
			android:layout_width="match_parent"
			android:layout_height="match_parent"
			android:id="@+id/listView"
			android:layout_below="@+id/button"/>

        </LinearLayout>

</layout>

myitem.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="item" type="sample.lightbox.myapplication.MainActivity.Item"/>
    </data>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp">

        <TextView
            android:text="@{item.title}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView3"/>

        <TextView
            android:text="@{item.text}"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/text1"
        />
    </LinearLayout>
</layout>

Module(app)用の gradle
android {
    compileSdkVersion 22
    buildToolsVersion "22.0.0"
    dataBinding {
        enabled = true
    }
    defaultConfig {
        applicationId "sample.lightbox.myapplication"
        minSdkVersion 19
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
    }
}
モジュール用の build.gradle には、apply plugin: 'com.android.databinding' を追加します

データ部分は、Google Gson を使ってバインド用クラスに直接セットするようにするとさらに簡単になると思います。

自動作成されたクラス

Android デベロッパーの情報





posted by lightbox at 2016-09-27 20:27 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする
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 終わり