SQLの窓

2017年04月15日


Tools クラスを使って Livedoor の お天気Webサービスを呼び出して Google gson でリストビューに一括で投入するとこうなります

関連する記事

13行目の Tools クラスに関しては以下を参照して下さい

Android Studio のテストの時間を短縮する為のいくつかの static メソッドをまとめた Tools クラス

簡単に使える API

Livedoor の お天気Webサービスは、特別な制限無く使える API で、しかもリストビューのテストには都合のいい、各地域の名前とその地域の天気の情報を表示する URL の配列を JSON 文字列から手に入れる事ができます。

リストビューは、オブジェクトの配列を addAll するだけで表示可能な手順があるので、そのオブジェクトを JSON 文字列から Google Gson に自動的に作ってもらっています。( Google Gson にとって、クラスのコンストラクタは必要ありません。この実装では、Google Gson 以外から追加する事を想定しています )

Google Gson

ダウンロード(GitHub)
Gson Download and Maven => Gson Download => Browse Central For => gson-x.x.x.jar  

オンラインドキュメント

Google Gson 用のクラス定義

Google Gson は、fromJson メソッドで、文字列の JSON と一致するクラス定義を使ってそのクラスのインスタンスを作成してくれます。クラス定義は必要な部分だけでよく、他のものは省略してかまいません。ここでは、PinpointLocation というクラスを定義して、その配列を JSON 文字列が対応しています。

PinpointLocation で注意するのは、ListView で表示して欲しい内容を toString メソッドを Override して定義しておく事です。

表示する以外の内容は、ListView をクリックした時のイベントで取得可能です。(97 〜 100 行)
package app.lightbox.winofsql.jp.listviewa;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;

import com.google.gson.Gson;
import jp.android.work.Tools;

public class MainActivity extends Activity {

	// Livedoor の お天気Webサービス用 (配列データ用)
	class PinpointLocation {
		String link;
		String name;
		public PinpointLocation(String myLink, String myName) {
			name = myName;
			link = myLink;
		}

		@Override
		public String toString() {
			return name;
		}
	}
	// Livedoor の お天気Webサービス用 (JSON用)
	class Weather {
		PinpointLocation[] pinpointLocations;
	}

	ListView listView = null;
	ArrayAdapter<PinpointLocation> adapter = null;

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

		// リストビュー(PinpointLocation)用のアダプターを作成
		adapter =
			new ArrayAdapter<PinpointLocation>(
					MainActivity.this,
					android.R.layout.simple_list_item_1
			);

		// ボタンがクリックされたら読み込み
		Button button = (Button) this.findViewById(R.id.button);
		button.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				// 単純確認メッセージボックス
				Tools.messageBox(MainActivity.this, "API呼び出し", "実行しますか?", new Tools.OnMessageBoxListener() {
					@Override
					public void onMessageBoxYesListener() {

						// データをセット
						Tools.callHttpGet(
							"http://weather.livedoor.com/forecast/webservice/json/v1?city=270000",
							"utf-8",
							new Tools.OnAsyncTaskListener() {
								@Override
								public void onAsyncTaskListener(String s) {

									Gson gson = new Gson();
									Weather weatherData = gson.fromJson(s, Weather.class);
									adapter.clear();
									adapter.addAll(weatherData.pinpointLocations);
									// リストビューに適用
									listView.setAdapter(adapter);

								}
							}
						);
					}

					@Override
					public void onMessageBoxNoListener() {
						Log.i("lightbox","キャンセルしました");
					}
				});

			}
		});

		// リストビューのアイテムがクリックされた時の処理
		listView = (ListView) MainActivity.this.findViewById(R.id.listView);
		listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

				// クリックされたアイテムを取得
				PinpointLocation mydata = (PinpointLocation) parent.getItemAtPosition(position);
				// LogCatに表示
				Log.i("lightbox", mydata.name);
				Log.i("lightbox", mydata.link);

				// URL を開く
				Tools.callBrowser(MainActivity.this, mydata.link);

			}
		});
	}

}


関連する記事

Android の単純な ListView の ArrayAdapter による応用の効く 4バリエーション と複数項目に即対応できる SimpleAdapter による実装



posted by lightbox at 2017-04-15 01:37 | 1 Android Studio | このブログの読者になる | 更新情報をチェックする

2015年07月15日


Android の ListView で ArrayAdapter をカスタマイズして表示する時、リストビューのアイテム内にボタン等がある場合のイベント登録時の注意事項



ListView に自由なレイアウトの表示を行う場合、以下のような手順になると思います。

1) 自分が表示したいレイアウトを作成
2) そのレイアウトに対するデータを保存するクラスを作成
3) そのクラスを扱う専用アダプタを作成

この際、getView メソッドを Override する事になっています。その中で、convertView == null の場合は各行の初回の処理にはなりますが、画面に同時に表示される行以上を作成する事が無いので、getView 内で常にデータをセットする事になっています。という事は、実際に作成されるボタンのインスタンスは最大行数ぶんしか無いので、それぞれのボタンにイベントを設定しても、イベント数そのものが行数ぶんになってしまうので、ボタンが常に正しい行の処理ができるように、ボタンにとっての最新 position をボタン自身に setTag で登録しておきます。

MainActivity.java
package sample.lightbox.listview02;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;


public class MainActivity extends Activity {

	private static final String DEBUG_TAG = "ListView :";
	MyArrayAdapter adapter = null;

	// MyArratAdapter 用プライベートクラス
	private class MyLinkData {
		String myText;
		String myUrl;

		public MyLinkData(String myText, String myUrl) {
			this.myText = myText;
			this.myUrl = myUrl;
		}
	}

	// ボタンが3つあるカスタム行をを使った MyLinkData 専用 ArrayAdapter
	private class MyArrayAdapter extends ArrayAdapter<MyLinkData> {

		// プライベートなので、コンストラクタに渡す情報はありません
		public MyArrayAdapter() {
			// スーパークラスに必要なのは、アクティビティのインスタンスのみ
			super(MainActivity.this, 0);
		}

		// 一般的な getView 内のカスタマイズ
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View rowView = convertView;

			if (rowView == null) {
				LayoutInflater inflater = MainActivity.this.getLayoutInflater();
				// ボタンが3つある行
				rowView = inflater.inflate(R.layout.row, null);
			}

			// myText の表示
			// Adapter の position の位置のデータを取得して、行の画面にセット
			((TextView)rowView.findViewById(R.id.textView)).setText(adapter.getItem(position).myText);

			Button button = (Button) rowView.findViewById(R.id.button);
			Button button2 = (Button) rowView.findViewById(R.id.button2);
			Button button3 = (Button) rowView.findViewById(R.id.button3);
			// 初回のみイベント登録
			if ( button.getTag() == null ) {
				// ボタン A
				button.setOnClickListener(new View.OnClickListener() {
					@Override
					public void onClick(View v) {
						// 最新の position を取得
						int buttonPosition = (int) v.getTag();
						// その position から データを取得
						MyLinkData data = adapter.getItem(buttonPosition);
						Toast.makeText(MainActivity.this,data.myText,Toast.LENGTH_SHORT).show();
					}
				});
				// ボタン B
				button2.setOnClickListener(new View.OnClickListener() {
					@Override
					public void onClick(View v) {
						// 最新の position を取得
						int buttonPosition = (int) v.getTag();
						// その position から データを取得
						MyLinkData data = adapter.getItem(buttonPosition);
						Log.i(DEBUG_TAG, data.myText);
					}
				});
				// ボタン C
				button3.setOnClickListener(new View.OnClickListener() {
					@Override
					public void onClick(View v) {
						// 最新の position を取得
						int buttonPosition = (int) v.getTag();
						// その position から データを取得
						MyLinkData data = adapter.getItem(buttonPosition);
						Toast.makeText(MainActivity.this,data.myUrl,Toast.LENGTH_SHORT).show();
					}
				});
			}

			// getView が呼び出されるという事は、その position が最新の状態なのでボタンに保存
			// して、ボタンイベント内でその position を使用する
			button.setTag(position);
			button2.setTag(position);
			button3.setTag(position);

			return rowView;
		}
	}

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

		// リストビューに表示させる情報
		MyLinkData[] myLinks = {
			new MyLinkData( "SQLの窓", "http://winofsql.jp" ),
			new MyLinkData( "logical error", "http://logicalerror.seesaa.net/" ),
			new MyLinkData( "琴線に触れる", "http://heart.winofsql.jp/"),
			new MyLinkData( "GINPRO", "http://ginpro.winofsql.jp/"),
			new MyLinkData( "SQLの窓 2", "http://winofsql.jp" ),
			new MyLinkData( "logical error 2", "http://logicalerror.seesaa.net/" ),
			new MyLinkData( "琴線に触れる 2", "http://heart.winofsql.jp/"),
			new MyLinkData( "GINPRO 2", "http://ginpro.winofsql.jp/")
		};

		// リストビュー用のアダプターを作成
		adapter = new MyArrayAdapter();
		adapter.addAll(myLinks);

		// リストビューを取得
		ListView listView = (ListView) MainActivity.this.findViewById(R.id.listView);

		// リストビューにデータ( アダプター ) をセット
		listView.setAdapter(adapter);

		// リストビューのアイテムがクリックされた時の処理
		listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view,
									int position, long id) {

				MyLinkData item = adapter.getItem(position);
				// LogCatに表示
				Log.i(DEBUG_TAG, item.myText);
				Log.i(DEBUG_TAG, item.myUrl);
				Log.i(DEBUG_TAG, Integer.toString(position));

				// URL を開く
				startActivity( new Intent(Intent.ACTION_VIEW, Uri.parse(item.myUrl)) );

			}
		});
	}


}


row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:descendantFocusability="blocksDescendants"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A"
        android:id="@+id/button"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B"
        android:id="@+id/button2"
        android:layout_below="@+id/button"
        android:layout_alignParentStart="true"
        android:layout_marginTop="38dp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="C"
        android:id="@+id/button3"
        android:layout_alignBottom="@+id/button2"
        android:layout_alignParentEnd="true"/>

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="New Text"
        android:id="@+id/textView"
        android:layout_below="@+id/button"
        android:layout_alignParentStart="true"
        android:textSize="25dp"
        android:layout_marginTop="3dp"/>
</RelativeLayout>
あまり必要性を感じませんが、ListView の行そのものをタップした場合も処理を実行できるように、android:descendantFocusability="blocksDescendants" を行の root の要素に設定しています。



posted by lightbox at 2015-07-15 21:50 | 1 Android Studio | このブログの読者になる | 更新情報をチェックする

2015年07月14日


できる限り不必要な記述は省いて simple_list_item_2 を使った 自前クラスを扱う専用 ArrayAdapter(private) でリストビューの表示



android.R.layout にあるものを適当に使えるのですが、とりあえず simple_list_item_2 を使って実装しました。

一般的な ListView のカスタマイズですが、できる限り不必要な記述は省いて作成しています。( 正確には、『不必要な記述は省く』では無く『書かなくても動作する部分は省く』です。 )

MyArrayAdapter はプライベートクラスなので、getView で必要なものは直接参照するようにして、コンストラクタの引数は無くしました。スーパークラスのコンストラクタは呼んでおかないと、内部の List のインスタンスが作成されないので呼んでいますが、MainActivity の インスタンスにしても、直接参照できるので必要無いのですが、渡さないとスーパークラスの初期処理でエラーとなるのでセットしています。
package sample.lightbox.listview02;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;


public class MainActivity extends Activity {

	private static final String DEBUG_TAG = "ListView :";
	MyArrayAdapter adapter = null;

	// MyArratAdapter 用プライベートクラス
	private class MyLinkData {
		String myText;
		String myUrl;

		public MyLinkData(String myText, String myUrl) {
			this.myText = myText;
			this.myUrl = myUrl;
		}
	}

	// simple_list_item_2 を使った MyLinkData 専用 ArrayAdapter
	private class MyArrayAdapter extends ArrayAdapter<MyLinkData> {

		// プライベートなので、コンストラクタに渡す情報はありません
		public MyArrayAdapter() {
			// スーパークラスに必要なのは、アクティビティのインスタンスのみ
			super(MainActivity.this, 0);
		}

		// 一般的な getView 内のカスタマイズ
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View rowView = convertView;

			if (rowView == null) {
				LayoutInflater inflater = MainActivity.this.getLayoutInflater();
				rowView = inflater.inflate(android.R.layout.simple_list_item_2, null);
			}

			MyLinkData myLinkData = MyArrayAdapter.this.getItem(position);
			TextView textView1 = (TextView) rowView.findViewById(android.R.id.text1);
			textView1.setText(myLinkData.myText);
			TextView textView2 = (TextView) rowView.findViewById(android.R.id.text2);
			textView2.setText(myLinkData.myUrl);

			return rowView;
		}
	}

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

		// リストビューに表示させる情報
		MyLinkData[] myLinks = {
			new MyLinkData( "SQLの窓", "http://winofsql.jp" ),
			new MyLinkData( "logical error", "http://logicalerror.seesaa.net/" ),
			new MyLinkData( "琴線に触れる", "http://heart.winofsql.jp/"),
			new MyLinkData( "GINPRO", "http://ginpro.winofsql.jp/")
		};

		// リストビュー用のアダプターを作成
		adapter = new MyArrayAdapter();
		adapter.addAll(myLinks);

		// リストビューを取得
		ListView listView = (ListView) MainActivity.this.findViewById(R.id.listView);

		// リストビューにデータ( アダプター ) をセット
		listView.setAdapter(adapter);

		// リストビューのアイテムがクリックされた時の処理
		listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view,
									int position, long id) {

				MyLinkData item = adapter.getItem(position);
				// LogCatに表示
				Log.i(DEBUG_TAG, item.myText);
				Log.i(DEBUG_TAG, item.myUrl);
				Log.i(DEBUG_TAG, Integer.toString(position));

				// URL を開く
				startActivity( new Intent(Intent.ACTION_VIEW, Uri.parse(item.myUrl)) );

			}
		});
	}


}

関連する記事

できるだけ難しい事をせずに、Android のリストビューでタイトルをクリックしたらそのページを表示する(1)
できるだけ難しい事をせずに、Android のリストビューでタイトルをクリックしたらそのページを表示する(2)

画面定義
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin"
                tools:context=".MainActivity">

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/listView"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"/>
</RelativeLayout>

R.layout は、ユーザー定義で、android.R.layout は システム定義です



posted by lightbox at 2015-07-14 20:25 | 1 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 ドロップシャドウの参考デモ
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり