忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2024/03/29 13:57 |
Android2.3 静的IPアドレス設定を読む
WiFiの設定画面でMENUボタン→詳細設定を押すと静的IPアドレスの設定ができる、というのは比較的有名です。
でもそこをアプリ側からどうにかしたいといったときの情報が何故か全く出てきません。

WiFi設定画面はACTION_WIFI_SETTINGSで呼び出せます。
	startActivity(new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS));
同じく静的IPアドレスの設定画面はACTION_WIFI_IP_SETTINGSです。
	startActivity(new Intent(android.provider.Settings.ACTION_WIFI_IP_SETTINGS));
びっくりするほど日本語情報がありませんでした。

またWifi情報はWifiConfigurationやWifiInfoあたりでどうこうというのは出てきますが、静的IPアドレス部分の情報はこれまた全く出てきません。
どうなってるんだ。
	import android.provider.Settings.System;

	ContentResolver contentResolver = getApplicationContext().getContentResolver();
	int WIFI_USE_STATIC_IP = System.getInt(contentResolver, System.WIFI_USE_STATIC_IP, 0);
	String WIFI_STATIC_IP = System.getString(contentResolver, System.WIFI_STATIC_IP);
	String WIFI_STATIC_GATEWAY = System.getString(contentResolver, System.WIFI_STATIC_GATEWAY);
	String WIFI_STATIC_NETMASK = System.getString(contentResolver, System.WIFI_STATIC_NETMASK);
	String WIFI_STATIC_DNS1 = System.getString(contentResolver, System.WIFI_STATIC_DNS1);
	String WIFI_STATIC_DNS2 = System.getString(contentResolver, System.WIFI_STATIC_DNS2);
ということでこれが答えです。
最初からこれらの単語でググれば答えは出てくるのですが、それがわからないから"静的IPアドレス"といったキーワードから調べようとした場合、これらの結果に全く辿り着けないんですよね。


あ、なんかACTION_WIFI_IP_SETTINGSはAndroid4とかではエラーになるとかなんとか。
持ってないからわかりませんが。
PR


2013/01/25 21:44 | Comments(0) | Android
Android2.3 ScanResultとWifiConfigurationの関係
任意のアクセスポイントに接続を行いたいとします。
他所のサイトを見ると、WiFiのアクセスポイント一覧を見るには
	WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
	List<WifiConfiguration> wifiConfigurationList = wifiManager.getConfiguredNetworks();
ってすればいいよ、とか書いてあることが多いのですが、これは正確ではありません。

何が問題って、既に圏外になってるアクセスポイントもびしばし入ってくるんだよね。
そして逆に、存在するけど一度も接続したことのないポイントは出てきません。

つまりこのWifiConfiguration、本体のWiFi設定一覧画面で出てくる「接続履歴あり」っていうアクセスポイントの一覧ということなわけだ。
単純にgetConfiguredNetworks()だけ使って接続しようとすると、電波の届かないアクセスポイントに向かって接続試行するということになりかねません。

同じようにWiFi機器を取得するメソッドとして
	List<ScanResult> wifiManager.ScanResult();
ってのがありますが、こちらは現在電波が入っているアクセスポイントの一覧を持ってきます。
本体のWiFi設定一覧画面で「圏外」になっていないアクセスポイントのリストということです。

つまりWiFiの接続先を変更するといった用途に使用するには、基本ScanResultを使った方がいいということです。
しかしここで問題があって、WiFiの接続変更にはNetworkIdが必要なのですが、それがWifiConfigurationにしか入ってないんですよね。

さらにScanResultから直接WifiConfigurationを作成するとかそういう手段がありません。
そのため、これまで繋げたことのないアクセスポイントに接続するには、以下のようなわりかし面倒な手順が必要です。
	// WifiManager
	WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
	
	// 現在電波の入っているアクセスポイント一覧
	List<ScanResult> listScanResult = wifiManager.ScanResult();

	// 接続したいScanResultを選択する。今回は最初に出てきたの
	ScanResult scanResult = listScanResult[0];
	
	// WifiConfigurationを作る
	WifiConfiguration wifiConfiguration = new WifiConfiguration();
	wifiConfiguration.SSID = "\"" + scanResult.SSID + "\"" //何故か\がつく
	/* 略 */
	
	// 作ったWifiConfigurationをWifiManagerに登録
	wifiManager.addNetwork(wifiConfiguration);
	wifiManager.saveConfiguration();
	
	// 接続変更を実行
	wifiManager.updateNetwork(wifiConfiguration);
	wifiManager.enableNetwork(wifiConfiguration.networkId, true);
なんで
	WifiConfiguration wifiConfiguration = scanResult.getWifiConfiguration();
的なメソッドが無いのでしょうか。


2012/11/16 23:29 | Comments(0) | Android
Android2.2 ローカルファイルに保存
前回SharedPreferencesでテキストを保存というのをやりました。

SharedPreferencesはあくまで小規模なテキストなどの保存用で、画像などの大きなファイルの保存には向いていません。
大きなファイルの保存にはストリームを使います。
http://android.roof-balcony.com/shori/strage/localfile-2/

問題点は、ストリーム経由なのでめんどいのと、全部読み込みメソッドが何故か無いこと。
PHPで言うとfread()はあるのにfile_get_contents()が無い。
まあとりあえずやってみましょう。
	//画像を取得
	Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
 
	//画像をバイト列に
	ByteArrayOutputStream output = new ByteArrayOutputStream();
	bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
	byte[] byteArray = output.toByteArray();
 
	//書き込むファイル
	String directory =  "/data/data/" + this.getPackageName();
	String filename  = "fileName";
	File file = new File(directory, filename);
 
	//ファイルをストリームに
	FileOutputStream outputStream = new FileOutputStream(file);
 
	//書き込みの実行
	outputStream.write(byteArray);
 
 
	//読み込むファイル
	FileInputStream inputStream = new FileInputStream(file);
 
	//ストリームから画像に
	Bitmap bitmapFactory = BitmapFactory.decodeStream(inputStream);
 
	//ここからはImageViewに画像を突っ込んでるだけ
	View view = findViewById(R.id.imageView1);
	ImageView imageView = (ImageView)view;
	imageView.setImageBitmap(bitmapFactory);
いやあ、これ絶対どこか間違ってるよ。
pngファイルをビットマップとして開いてpngに変換してさらにバイト列にして保存とかがっかりにも程があるだろう。

なお、directory =  "/data/data/" + this.getPackageName()はアプリのローカルディレクトリです。
ファイルエクスプローラーなどで確認できます。
特にパーミッションは指定していないのですが600だったので他のアプリから読まれる心配はない、のかなあ?
そこらへんよくわかりません。

さて、ファイルを保存する度にこんな面倒なことやってらんねえよ、ということでもう少しだけ簡単なメソッドが用意されています。
	//画像を取得
	Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
	ByteArrayOutputStream output = new ByteArrayOutputStream();
	bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
	byte[] byteArray = output.toByteArray();
 
	//ファイル名
	String filename =" fileName ";
 
	//書き込むストリーム
	OutputStream outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
 
	//書き込み実行
	outputStream.write(byteArray);
 
 
	//読み込み
	InputStream inputStream = openFileInput(filename);
 
	//ストリームから画像に
	Bitmap bitmapFactory = BitmapFactory.decodeStream(inputStream);
 
	//ここからはviewに画像を突っ込んでるだけ
	View view = findViewById(R.id.imageView1);
	ImageView imageView = (ImageView)view;
	imageView.setImageBitmap(bitmapFactory);
openFileOutput()とopenFileInput()がそれなのですが……たいしてかわらないな。
ファイルをストリームにする手間が省けただけで、画像をバイト列に変換する部分の野暮ったさはそのままです。

なお、書き込み先のディレクトリは"/data/data/" + this.getPackageName() + "/files/"で固定になり、サブディレクトリなどの指定はできません。
融通が利かない分、指定の必要もないため多少操作は楽になります。

でもね、本当にほしかったのはfilePutContents(String fileName, Bitmap bitmap)なんだよな。
いやまあ、メソッド作ればいいだけなのですが。


2011/11/14 21:42 | Comments(0) | TrackBack() | Android
Android2.2 WebViewを複数設置したらどうなるの

どのViewも基本的に中身がはみ出たら画面外に出てしまって見えなくなります。
が、一部例外があってScrollViewとWebViewは自動的にスクロールしてくれます。

WebViewは一画面にふたつ以上作るなってのをどこかで見た気がするんだがどこだったっけ。
実際のところ複数設置しても問題なく動作します。

レイアウト
	<WebView android:id="@+id/webViewTest1"
		android:layout_height="wrap_content" android:layout_width="fill_parent"
		android:scrollbars="vertical" />
	<WebView android:id="@+id/webViewTest2"
		android:layout_height="wrap_content" android:layout_width="fill_parent"
		android:scrollbars="vertical" />
	<WebView android:id="@+id/webViewTest3"
		android:layout_height="wrap_content" android:layout_width="fill_parent"
		android:scrollbars="vertical" />
アクティビティ
	WebView webViewTest1 = (WebView) findViewById(R.id.webViewTest1);
	String url1 = "http://www.google.co.jp/";
	webViewTest1.loadUrl(url1);
	WebView webViewTest2 = (WebView) findViewById(R.id.webViewTest2);
	String url2 = "http://www.yahoo.co.jp/";
	webViewTest2.loadUrl(url2);
	WebView webViewTest3 = (WebView) findViewById(R.id.webViewTest3);
	String url3 = "http://www.bing.co.jp/";
	webViewTest3.loadUrl(url3);

普通に動作しますが、上のほうのWebViewが画面幅を使い切ると、それ以降のWebViewは画面外に追いやられてしまい閲覧できません。
また、どれかのWebViewでリダイレクトがかかるとブラウザに処理が渡ってそちらに移動してしまいます。
どうせWebViewを使うなら、一画面で全てを表示するのがよいのではないかと思われます。

ってかさー、RelativeLayoutとかのXMLによるレイアウトって超使いにくいよねー。
だいたいいつも手っ取り早くWebViewで実装してしまう。


2011/11/07 21:17 | Comments(0) | TrackBack() | Android
Android2.2 クリックリスナーでキャンセル扱いにする
うっかり間違ったボタンを押した場合、指を範囲外にドラッグしてから離すと、HTMLのフォームのようにキャンセルした扱いにするアプリは数多くあります。
どうやって実装しているのでしょう。

前回OnTouchListenerを実装しました。
ACTION_UPとACTION_CANCELがあるので、「画像上で指を離したときがACTION_UPで、画像の範囲外に指をドラッグして離したときがACTION_CANCELなの?」と思ってみれば違います。
ACTION_CANCELは「押してるときに戻るボタンを押した」とかの本気でキャンセルされた場合にしか呼ばれず、それ以外は大抵ACTION_UPになります。
ですのでACTION_UPに進むボタンを実装してしまうと、うっかり間違って押した場合にキャンセルができなくなってしまいます。

解決策としては、OnTouchListenerとOnClickListenerを併用。
view.setOnTouchListener(new OnTouchListener(){
	public boolean onTouch(View view, MotionEvent motionevent) {
		switch(motionevent.getAction()){
			//押した
			case MotionEvent.ACTION_DOWN:
				Log.v("OnTouchListener", "ACTION_DOWN");
				break;
			//離した
			case MotionEvent.ACTION_UP:
				Log.v("OnTouchListener", "ACTION_UP");
				break;
			//キャンセルした
			case MotionEvent.ACTION_CANCEL:
				Log.v("OnTouchListener", "ACTION_CANCEL");
				break;
		}
		return false;
	}
});
view.setOnClickListener(new OnClickListener(){
	@Override
	public void onClick(View view) {
		Log.v("OnClickListener: ", "onClick");
	}
});
OnClickListenerは、名前に反して指を離したときに発動します。
また、範囲外に指を移動してから離した場合は反応しません。
よって画面遷移などの契機とするのに最適なリスナーとなっています。

なお、今度はonTouchの返り値がfalseになっていることに注意です。
こうしないとOnClickListenerに処理が渡りません。
そしてOnClickListenerを実装するとreturn falseでもACTION_UPやACTION_CANCELが反応するようになります。
意味がわからん。


実際他のアプリがどうやって実装してるのかは知らないのですが、これが一番簡単な作り方なのですかね。


2011/11/04 21:45 | Comments(0) | TrackBack() | Android
Android2.2 アプリ内でデータを共有
AndroidにはSQLiteが入っており、アプリからデータを保存したい場合は自由に使用することができます。
が、そんな大げさなものじゃなくて単に数十文字のちょっとした文字列なんかを保存したい、という場合にデータベースはいかにも大げさです。

そんなときのためにSharedPreferencesというものが用意されています。
とりあえず使ってみます。
	//保存
	android.content.SharedPreferences sp = getSharedPreferences("fileName", MODE_PRIVATE);
	sp.edit().putString("hoge", "fuga");
	sp.edit().putInt("integer", 100).commit();

	//取得
	String hoge = sp.getString("hoge", null);

	//削除
	sp.edit().remove("integer").commit();
超簡単。

getSharedPreferencesでリソースを取得し、putで設定、getで取得、commitで保存、removeで削除と簡単にデータの永続化ができます。
第二引数のMODE_PRIVATEは他アプリからは読み書き禁止ということです。
かわりにMODE_WORLD_READABLEMODE_WORLD_WRITEABLEで他アプリとデータを共有なんてこともできるみたい。


2011/10/31 21:37 | Comments(0) | TrackBack() | Android
Android2.2 OnTouchListenerで手を離したのを感知する
XMLにandroid:onClickと書くと簡単にView.OnClickListenerを実装できるという話をしました。

さて、イベントリスナーにはOnClickListener以外にも長押しを感知するOnLongClickListener、キーボードなどの押下を感知するOnKeyListenerなどがあります。
そこらへんはXMLでは指定できないみたいなので、Javaからリスナーをセットする必要があります。
とりあえずOnTouchListenerを実装してみます。
ImageView view = (ImageView) findViewById(R.id.imageView);
view.setOnTouchListener(new OnTouchListener(){
	@Override
	public boolean onTouch(View view, MotionEvent motionevent) {
		switch(motionevent.getAction()){
			//押した
			case MotionEvent.ACTION_DOWN:
				Log.v("OnTouchListener", "ACTION_DOWN");
				break;
			//離した
			case MotionEvent.ACTION_UP:
				Log.v("OnTouchListener", "ACTION_UP");
				break;
			//キャンセルした
			case MotionEvent.ACTION_CANCEL:
				Log.v("OnTouchListener", "ACTION_CANCEL");
				break;
		}
		return false;
	}
});
一見できているように見えますが、何故かACTION_DOWNは感知するのにACTION_UPACTION_CANCELも反応しません。
何故だ。

http://developer.android.com/reference/android/view/View.OnTouchListener.html
> Returns True if the listener has consumed the event, false otherwise.

よくわからんが、このリスナーで処理を続けるならtrueにしろってことか?
return trueにしたら無事動作するようになりました。
たったこれだけのことに数時間引っかかったことは秘密だ。


で、解決したあとになってそのまんまの記事が見つかるのもよくあること。


2011/10/28 22:13 | Comments(0) | TrackBack() | Android
Android2.2 画面中央に置いたViewの下にViewを置けない?
<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" >

	<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
		android:text="だみー" android:id="@+id/dummyTextView"
		android:layout_centerVertical="true" android:layout_centerHorizontal="true" ></TextView>

	<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
		android:id="@+id/dummyImageView" android:src="@drawable/dummyImage"
		android:layout_below="@+id/dummyTextView" android:layout_centerHorizontal="true" ></ImageView>

</RelativeLayout>
ってやったら、android:layout_belowがまったく効かない。
何故?

あと、
<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" >

	<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
		android:text="だみー\nだみー\nだみー\nだみー\nだみー" android:id="@+id/dummyTextView" ></TextView>

	<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
		android:text="下寄せ" android:id="@+id/dummyTextView2"
		android:layout_alignRight="@+id/dummyTextView" android:gravity="bottom"
		></ImageView>

</RelativeLayout>
みたいに、親レイアウトに下寄せでビューを設置したいときはどうすればいいんですかね。


2011/10/25 00:04 | Comments(0) | TrackBack() | Android
Android2.2 setContentViewにStringの指す値を割り当てたい
表示するテンプレートをlayout/hoge.xmlに設定する場合、通常は以下のようにファイル名を表すリソースを与えます。
	setContentView(R.layout.hoge);
で、動きのない静的ページを沢山作りたいが毎回アクティビティ作るのもめんどくさいから全部同じアクティビティで処理してしまおうと考えました。
	String layoutStr = getIntent().getExtras().getString("layoutStr");
	setContentView(R.layout.{layoutStr});
PHPじゃないんだから勿論動きません。

で、こんなときどうすればいいんだと調べてみたものの、こういうことを書いてるところがどうも見あたらないんですよね。
結局呼び出し側でレイアウトIDを指定することしかできませんでした。
	//呼び出し側
		Intent intent = new Intent(this, Static.class);
		intent.putExtra("layoutID", R.layout.static_hoge);
		startActivity(intent);
	
	//呼び出され側
		int layoutId = getIntent().getExtras().getInt("layoutID");
		setContentView(layoutId);
探すと一応invokeとかリフレクションを使ってどうのというのが出てくるのですが、いまいち意味がわかりませんでした。
http://www.syboos.jp/java/doc/get-set-field-value-by-method-invoke.html
http://www.ibm.com/developerworks/jp/java/library/j-dyn0603/


2011/10/21 22:07 | Comments(0) | TrackBack() | Android
Android2.2 EclipseにUMLプラグインを導入
これまでクラス図作成にVisioとかを使っていたわけですが、どうやらEclipseにはソースからクラス図を作成できるプラグインがあるみたい。
あるみたいというか古いのは10年くらい前からあったりするわけですが、とりあえずこのAmaterasUMLというのを試してみます。

まずsourceforgeから「AmaterasUML」を選択してダウンロード。
執筆時点での最新版は1.3.3でした。

解凍したらEclipseのプラグインフォルダにコピペでインストールは終了みたい。
C:\eclipse\pluginsとかそこらへんにあると思います。

で、なんかそれとは別にGEFってプラグインが必要みたい。
ここらへんで詳しく解説されていたからそのままやってみます。

ヘルプ→新規ソフトウェアのインストール、
作業対象に「http://download.eclipse.org/tools/gef/updates/releases/」を設定…したらなんか「ロケーションの重複」とか言われました。
何故か最初から入っていたみたい。
「使用可能なソフトウェア・サイト」を探したら見つかったのでチェックボックスにチェックを入れ有効にした。
そうしたら作業対象が有効化され、リストにGEFが出てきました。

バージョンはよくわからないので最新のGEF SDK 3.7.1を選択。
適当に進んでたらインストールできたみたいです。
なんかさっぱりわからないまま進んだんですが大丈夫なんですかね。
しばらく待ち、インストールが終了したらクリーン再起動

以上でAmaterasUMLが使えるようになったはず。

ファイル→新規→その他→AmaterasUML→クラス図を選択。

なんかファイルが立ち上がるので、そこに適当なJavaクラスをドラッグしたらなんか一瞬でクラス図ができあがった。
逆にクラス図を作ってJavaにスケルトン作るとかもできるみたい。
便利すぎるだろこれ。

欠点としては拡張子cldという独自形式っぽいので別アプリで使い回せない点。
画像として出力はできますが、XMLかせめてテーブルタグとかでエクスポートできればもっと便利だったろうに惜しい。


2011/10/04 21:53 | Comments(0) | TrackBack() | Android

| HOME | 次のページ>>
忍者ブログ[PR]