Androidプログラミング・メモ
by K.I
2014/05/12〜
Index
- Androidのアプリケーションプログラムに関する備忘録としてメモを残す
- OracleのサイトJavaから、Javaの開発キットJDKをダウンロード
- Java SE8u5のJDK(jdk-8u5-windows-x64.exe)をダウンロード、インストールする
- JDKのパス設定を行う
- マイコンピュータを右クリック、システムの詳細設定を選んで、環境変数のボタンを押す
- システム環境変数に、新規の変数:JAVA_HOMEを追加。変数値:C:\Program Files\Java\jdk1.8.0_05
- さらに、システム環境変数:Pathの一番先頭に、%JAVA_HOME%\bin;を追加
- 開発環境として、Eclipseをインストールする
- Pleiadesは、Eclipseを日本語化するプラグインらしい
- Eclipse 4.3 Keplerを選択、JavaのStandard Editionをダウンロード(JREを含まないもの)
- Eclipseはインストーラがないので、Zipファイルを解凍したら、
- Cドライブに、Androidというディレクトリを作成。展開されたpleiadesディレクトリをコピーする
- eclipse.exeを起動して、workspace(ワークディレクトリ)を設定しておく
- 自分の場合は、Dドライブに作成したワークを設定した
- Android SDKをインストールする
- ダウンロードサイトの、USE AN EXISTING IDE→Download the SDK Tools for Windows をクリック
- ライセンス条項に同意して、ダウンロード、インストーラを起動
- インストールディレクトリは、C:\Android\android-sdkに変更しておく
- あとは、デフォルトで進めると、Android SDK Managerが起動する
- Android4.4.2(API19)にチェックが入っているが、Android2.1(API7)以上のバージョン全部にチェックを入れる
- Install packages...のボタンを押して、Accept Licenseにチェックすると、以下のメッセージが出て、Installボタンが有効にならない
Package 'Google TV Addon, Android API 13, revision 1' depends on 'SDK Platform Android 3.2, API 13, revision 1'
- Android SDKの3.2は、これからインストールするつもりなんだけど?どうしろって言うんだろう?
- 一度Cancelして、Android 3.2(API13)のGoogle TV Addonのチェックを外してやり直すとInstallが有効になったので、とりあえずそうする。
- Eclipseで、ヘルプ→更新の確認を選択してみる
- ステータスバー上に、ソフトウェア・サイトへの接続中と表示され、20分ぐらい掛かって、更新が検出されませんでしたと表示された。。
- Android SDKのパス設定
- システム環境変数のPathの一番最後に、;C:\Android\android-sdk\tools;C:\Android\android-sdk\platform-toolsを追加
- Eclipseを起動して、ヘルプ→新規ソフトウェアのインストールで、追加のボタンをクリック
- 開発ツールのチェックボックスが表示されるので、チェックして次へ
- インストールされる項目が表示されるので、次へ
- ライセンス条項に同意して、完了
- 完了しても、インストール継続中なので、Eclipseの再起動を促すDialogが表示されるまで待つこと。
- 最初、待たずにExlipseを終了してしまい、やり直すことになった。。
[top]
- ファイル→新規→プロジェクトを選択
- Android→Androidアプリケーション・プロジェクトで次へ
- アプリケーション名に、例えばTestAppと入力すると、プロジェクト名とパッケージ名が自動的に設定される
- パッケージ名は、ドメイン名を逆にしたものになるのは慣習らしいが、IOSのプログラムと同じだ
- デフォルトで、最小必須SDKはAPI8、ターゲットSDKと次でコンパイルはAPI19に設定されている
- どうするべきか良く分からん。トラ技の例のようにAPI17を設定してみる
- それ以降もいろいろ設定あるけど、とりあえずデフォルトで、
- アクティビティーの作成で、Blank Activityになっているが、そのまま次へ進んで完成させる
- メインのソースファイル
- src/com.example.testapp/MainActivity.java を見てみる
package com.example.testapp;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) { //Activityの生成
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}
}
- ちょっと複雑な感じだ。Flagmentって何だろう。。。
- もう一度、プロジェクトを作り直してみた。
- 今度は、アクティビティの作成で、Empty Activityにして作成する
- 今度は明快だ。onCreate(アクティビティの起動)時の記述だけになっている
- デフォルトのonCreateをオーバーライドして、
- setContentViewで、画面レイアウト(R.layout.activity_main)のリソースを読み込んでいるだけ
- @Overrideは、オーバーライドメソッドであることを明記して、コンパイラにチェックしてもらう
- Rというのは、genフォルダ下にR.javaというファイルで、リソースIDの定義ファイルのようなものらしい
- WindowsのVisualCで言うと、resource.hと同じような感じなのかなぁ。。
- 単に、画面サイズを合わせてから、
- TextViewに、hello_worldというストリングを置いているだけのようだ
- 実際の文字列は、res/value/strings.xmlの中で定義されている
- このxmlファイルは、グラフィカルレイアウトタブで、GUIによる画面レイアウトも可能。
- GUIで編集すると、XMLにも反映されるようになっているので、簡単にレイアウトできる
- アクションバーの右側にオプションメニューがあることを示すアイコン(縦方向に…)が表示され
- クリックすると、メニューが表示されて選択することが出来るようになる
- 新規→その他...を選択、Android→Android XMLファイルで、次へ
- リソース・タイプをMenuに、ファイルをmainにして完了
- Menuリソースが出来るので、Menu Elementで追加ボタンを押して、
- で追加できると思うんだけど、これ以降はTEXTで記述した方が楽な気がする
- ということで、Menuリソース(res/menu/main.xml)を直接編集して追加する
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/menuitem1"
android:showAsAction="never"
android:title="Item1"/>
<item
android:id="@+id/menuitem2"
android:showAsAction="never"
android:title="Item2"/>
</menu>
- メインのActivityのコードは、例えば以下のようにする
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.menuitem1:
showMessage("Select Item1");
break;
case R.id.menuitem2:
showMessage("Select Item2");
break;
}
return true;
}
protected void showMessage(String msg){
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
- Menuリソース(res/menu/main.xml)を追加する
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menuitem1"
android:title="Item1"
android:showAsAction="ifRoom"
android:icon="@drawable/a"/>
<item
android:id="@+id/menuitem2"
android:title="Item2"
android:showAsAction="ifRoom"
android:icon="@drawable/b"/>
</menu>
- res/drawable/に、アイコンファイルを入れるのを忘れないように
- showAsAction属性で、メニューの表示方法を変えることが出来るらしい
showAsAction属性 | 表示方法 |
never | 常に表示しない |
ifRoom | 表示する場所があれば表示 |
always | 常に表示する |
withText | titleのテキストを表示 |
collapseActionView | actionViewLayoutの指定と関連付ける |
- ifRoom|withTextの様に、複数の属性を指定することも出来る
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.menuitem1:
showMessage("Select Item1");
return true;
case R.id.menuitem2:
showMessage("Select Item2");
return true;
}
return false;
}
protected void showMessage(String msg){
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
[top]
- 自分の場合は、Android端末として、ASUSのNexus7、LGのNexus5を接続してみた
- まず、設定→開発者向けオプションで、USBデバッグにチェックを入れておく必要がある
- Android4.2以降は、デフォルトで開発者向けオプションが表示されないらしい。
- 設定→タブレット情報→ビルド番号をタップする
- 何度かタップすると、「デベロッパーになるまであと○ステップです」と表示される
- 計7回タップすると、「これでデベロッパーになりました!」と表示される
- これで、開発者向けオプションが表示されるようになる
- 設定→開発者向けオプション→USBデバッグにチェックを入れれば良い
- Google USB Driverのインストール
- 開発者サイトにアクセスして、「Download Google USB Driver」ボタンを押す
- 規約が表示されるので、確認してダウンロードする
- ダウンロードしたZIPファイルを解凍しておく
- USBデバッグを有効にしたAndroid端末を接続する。
- デバイスマネージャで確認すると、Nexus7として認識されているが、!マークが付いている
- 右クリック→ドライバソフトウェアの更新で、コンピュータを参照してドライバソフトウェアを検索を選択
- あらかじめダウンロードしておいたUSBドライバの場所を指定して、インストール
- これで、Windowsのポータブルデバイスに、Nexus7として認識された!
- Nexus5の場合も、開発者向けオプション有効にして、Google USB Driverインストールすれば、
- adb接続は可能となり、EclipseでもAndroidデバイスとして認識されるようになるはずなんだけど。。
- adb接続出来ないし、EclipseでもAndroidデバイスとして認識されない。。
- また、WindowsではNexus5はストレージとして認識されていない。。。
- この場合、Android端末がMTP接続の設定になっている可能性がある。
- 設定→ストレージで、右上のオーバーフローメニュー(縦向きの…)から、「USBでパソコンに接続」を選択
- メディアデバイス(MTP)接続の場合は、このチェックを外すと、adb接続可能となりEclipseでAndroidデバイスとして認識される
- さらにカメラ(PTP)で接続するように設定すると、Windowsのポータブルデバイスとして認識されるようになる。
- 普通は、USBでパソコンに接続する場合、メディアデバイス(MTP)で接続するらしいが、
- adbのドライバをインストールした場合、MTPではダメでPTP接続しないと、認識されない様だ。
- Eclipseを起動して、実行→実行構成を選択すると実行構成のダイアログが表示される
- Androidアプリケーションをダブルクリックして、新規構成
- プロジェクトの参照で、作成しておいたTestAppを選択。上の名前も同じにしておく
- ターゲットタブを選択
- デプロイ・ターゲット選択モードで、「デバイスを選択するときに常にプロンプトを表示」を選択
- 実行ボタンを押すと、Androidデバイス選択のダイアログが表示され、
- 実行中のAndroidデバイスを選択するで、asus-nexus_7-xxxxxxxxと表示されるので選択してOKボタンを押す
- Android端末側でも、USBデバッグを許可するダイアログが表示されるので、許可しておく。
- TestAppが転送されて、緑色のDroidのアイコンのアプリが追加される
- PC側にも、なんか表示された
- とりあえず、Yesでerrorにしておく
- 以下のエラーが出て、アプリの転送が出来ないことがあった
Failed to install TestApp.apk on device 'xxxxxxxx': タイムアウト
起動はキャンセルされました!
USBケーブルを接続しなおして、USBデバッグを許可し直したら転送できるようになった。
- ウィンドウ→パースペクティブのカスタマイズで、
- コマンド・グループ可用性タブを選択、「Android SDK および AVDマネージャー」にチェックを入れておく
- ウィンドウ→Android 仮想デバイス・マネージャーを選択
- 新規...ボタンを押して、エミュレータの設定を行う
- AVD名: 適当な名前をつける。例えば、AVDemu
- 装置: Androidの機種を指定
- CPU/ABI: Android OSのバージョン。とりあえずAndroid4.0 API14にしておく
- キーボード: 使わないので、チェックを外す
- スキン: とりあえず No Skin
- フロントカメラ: 使わないので、None
- メモリオプション: あまり大きいとエミュレータが機動しないことがあるらしい。とりあえずRAM:256
- 内部ストレージ: よく分からないが、とりあえず100MiB
- SDカード: SDカードの容量ってなんだろう。とりあえず64MiB
- エミュレーション・オプション: わからないのでなにもチェックしない
- 設定が終わったら、OKボタンを押す
- 作成したエミュレータの設定を選択して、開始ボタンを押すと起動オプションのダイアログが表示される
- 実際のサイズに表示をスケールするにチェックを入れて、起動ボタンを押す
- プログレスバーが終了しても、起動画面が出るまでは待つこと。
- 最初、以下のエラーが出て、エミュレータが起動しなかった
Unfortunately, System UI has stopped.
[2014-05-21 20:30:44 - TestApp] New emulator found: emulator-5554
[2014-05-21 20:30:44 - TestApp] Waiting for HOME ('android.process.acore') to be launched...
[2014-05-21 20:31:46 - TestApp] HOME is up on device 'emulator-5554'
[2014-05-21 20:31:46 - TestApp] Uploading TestApp.apk onto device 'emulator-5554'
[2014-05-21 20:31:46 - TestApp] Installing TestApp.apk...
[2014-05-21 20:33:49 - TestApp] Failed to install TestApp.apk on device 'emulator-5554!
[2014-05-21 20:33:49 - TestApp] (null)
[2014-05-21 20:33:49 - TestApp] Failed to install TestApp.apk on device 'emulator-5554': 確立された接続がホスト コンピューターのソウトウェアによって中止されました。
[2014-05-21 20:33:49 - TestApp] com.android.ddmlib.InstallException: 確立された接続がホスト コンピューターのソウトウェアによって中止されました。
[2014-05-21 20:33:49 - TestApp] 起動はキャンセルされました!
- Androidとシリアルデバイスをケーブルで接続するような場合
- PCでプログラムを修正した時、ケーブルをいちいち差換えなければならない。
- また、LogCatも見れなくなるので、デバッグもやりにくい
- Android端末で、設定→タブレット情報→端末の状態→IPアドレスで、
- 端末のIPアドレスを確認しておく(例えば、192.168.1.99とする)
- PCとAndroid端末を、USBケーブルで接続して、
- USBケーブルを抜いて、Eclipseから実行を試すと、実行中のAndroidデバイスの選択で、
- asus-nexus_7-192.168.1.99:5555が選択できる様になっている
- 実行すると、リモートでアプリが起動する。素晴らしい!
- 元に戻すときは、USBケーブルを接続して、以下のコマンドを入力すれば良いらしい
> adb usb
- Wifiで接続でも使ったadbコマンドは、他にもいろいろ便利な機能がある
- 前述の方法でWifi接続してあれば、PCからリモートで操作可能
$ adb devices
$ adb shell screencap -p /sdcard/screen.png
$ adb shell screenrecord /sdcard/hoge.mp4
- ファイル転送(pull:端末→PC、push:PC→端末)
$ adb pull /sdcard/screen.png
$ adb push local.file /sdcard/
- adbシェル →rm,mv,cp等、基本的なunixのシェルコマンドが使える
$ adb shell rm /sdcard/screen.png
参考: ターミナルからIntentを投げる
- アプリケーションのデータディレクトリ /data/data/パッケージ名/をアクセスすると、
- run-asコマンドで パッケージ名 を指定すると、そのアプリケーションのユーザに切り替わって、
- 例えば、プリファレンスファイルとかをcatで確認可能になる
$ cat shared_prefs/xxxx.xxxx.xxxx.applname_prefences.xml
[top]
- とりあえず、Bluetoothのモジュールを動かしてみたい。
- まずはトラ技2014年3月号の記事に従って、サンプルプログラムを試してみる。
- 解凍すると、自動解凍の圧縮ファイルがいくつか入っている
- トラ技のARMライタと、Bluetoothモジュール、そして圧電サウンダを接続しただけ
- USBケーブルを接続すれば、電源の+3.3Vはボードから供給される
- まず、LPC11U35_sample.exeを解凍すると、デフォルトでC:\workspaceに展開される
- C:\workspace\LPC11U35_MyElecPiano\Release\LPC11U35_MyElecPiano.binを書き込む
- ISPボタンを押しながら、トラ技ARMライタをPCに接続すると、
- トラ技ARMライタがPCに接続済みだった場合は、
- RESETボタンとISPボタンを同時に押して、
- まずRESETボタンを離してから、ISPボタンを離す
- firmware.binファイルが入っているので、削除してから、
- LPC11U35_MyElecPiano.binを書き込む
- 次に、Android_sample.exeを解凍すると、デフォルトでC:\Android\pleiades\workspaceに展開されるていうことなんだけど、
- 何故か、解凍したフォルダ以下に展開されるので、Dドライブの自分のWorkディレクトリにプロジェクトをコピーする。
- Eclipseを起動して、パッケージ・エクスプローラで右クリック、インポートを選択
- 一般→既存プロジェクトをワークスペースへを選択して、次へ
- ルートディレクトリの選択で参照ボタンを押して、プロジェクトをコピーしたWorkディレクトリを指定、
- 完了ボタンを押すと、プロジェクトが読み込まれる
- MyElecPianoプロジェクトの、res→layout→main.xmlをダブルクリックすると、
- まず、上部中央のボタンで、横長の画面に設定する
- この画面で、自由にボタン等を配置できるらしいが、もう出来てるので、そのまま特に弄らない
- でもPropertiesで、かなり自由に設定できるので、思った通りの画面が作れそうだ
- ソースプログラムは、src→com.example.bluetooth.elecpiano→ActivityElecPiano.java
package com.example.bluetooth.elecpiano;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;
public class ActivityElecPiano extends Activity {
// クラス定数宣言定義
public static final int CONNECTDEVICE = 1;
public static final int ENABLEBLUETOOTH = 2;
// Bluetoothインスタンス定数
private BluetoothAdapter mBluetoothAdapter;
private BluetoothClient BTclient;
// バッファ定義
private byte[] ReceivePacket = new byte[64]; // 受信バッファ
private byte[] TransmitPacket = new byte[64]; // 送信バッファ
//一般変数定義
private static TextView text0;
Context context = this;
//最初に実行されるメソッド
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// タイトル表示
setContentView(R.layout.main);
setTitle("MY スマホ鍵盤");
setTitleColor(Color.BLACK);
text0=(TextView) findViewById(R.id.text0);
// スイッチイベント組み込み
findViewById(R.id.select).setOnClickListener((OnClickListener) new SelectExe());
// Bluetooth搭載スマホか確認
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //Bluetooth搭載情報の取得
if (mBluetoothAdapter == null) { //nullならBluetoothが未搭載
text0.setTextColor(Color.YELLOW); //文字色 黄色設定
text0.setText("使用不可"); //Bluetoothの無効表示
}
// 鍵盤のボタン操作
findViewById(R.id.Button1).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
TransmitPacket[0] = 'A';
BTclient.write(TransmitPacket);
}
});
findViewById(R.id.Button2).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
TransmitPacket[0] = 'B';
BTclient.write(TransmitPacket);
}
});
:
中略(全ボタンの数だけ繰り返し)
:
findViewById(R.id.Button17).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
TransmitPacket[0] = 'Q';
BTclient.write(TransmitPacket);
}
});
}
// アクティビティ開始時(ストップからの復帰時)
@Override
public void onStart() {
super.onStart();
if (mBluetoothAdapter.isEnabled() == false) { // Bluetoorh無効時
Intent BTenable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); // ダイアログ画面にて有効化
startActivityForResult(BTenable, ENABLEBLUETOOTH); // ENABLEパラメータ発行
}
else {
if (BTclient == null) { // Bluetoorh有効時
BTclient = new BluetoothClient(this, handler); // クライアントクラスを生成し
} // ハンドラを生成
}
}
// アクティビティ再開時(ポーズからの復帰時)
@Override
public synchronized void onResume() {
super.onResume(); // 特に処理なし
}
// アクティビティ破棄時
@Override
public void onDestroy() {
super.onDestroy();
if (BTclient != null) {
BTclient.stop(); //Bluetoothクライアント停止
}
}
// 遷移ダイアログからの戻り処理
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CONNECTDEVICE: // 端末選択ダイアログからの戻り処理
if (resultCode == Activity.RESULT_OK) { // 端末が選択された場合
String address = data.getExtras().getString(DeviceListActivity.DEVICEADDRESS);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // 端末に接続要求
BTclient.connect(device); // 端末へ接続
}
break;
case ENABLEBLUETOOTH: // 有効化ダイアログからの戻り処理
if (resultCode == Activity.RESULT_OK) { // Bluetooth有効化の場合
BTclient = new BluetoothClient(this, handler); // クライアントクラスを生成し
} // ハンドラを生成
else { // 無効化の場合メッセージ表示
Toast.makeText(this, "Bluetooth使用不可", Toast.LENGTH_SHORT).show();
finish();
}
}
}
// 接続ボタンイベントクラス
class SelectExe implements OnClickListener{
public void onClick(View v){ // デバイス検索と選択ダイアログへ移行
Intent Intent = new Intent(ActivityElecPiano.this, DeviceListActivity.class);
startActivityForResult(Intent, CONNECTDEVICE); // 端末選択したら接続要求
}
}
// Bluetooth端末の接続処理のハンドラ
private final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) { // ハンドルメッセージごとの処理
switch (msg.what) { // 戻り値メッセージごとに処理を実行
case BluetoothClient.MESSAGE_STATECHANGE:
switch (msg.arg1) {
case BluetoothClient.STATE_CONNECTED: //接続完了
text0.setTextColor(Color.GREEN); //文字色 緑色設定
text0.setText("接続完了"); //接続完了のテキスト表示
break;
case BluetoothClient.STATE_CONNECTING: //接続中
text0.setTextColor(Color.WHITE); //文字色 白色設定
text0.setText("接続中..."); //接続中のテキスト表示
break;
case BluetoothClient.STATE_NONE: //接続なし
text0.setTextColor(Color.RED); //文字色 赤色設定
text0.setText("接続失敗"); //接続失敗のテキスト表示
break;
}
break;
case BluetoothClient.MESSAGE_READ: // Bluetooth受信処理
ReceivePacket = (byte[])msg.obj; // データの受信
break; // 受信処理
}
}
};
}
- アプリの書込みについては、前章でやったことと同じ
- まずタブレットを接続して、デバイスマネージャで認識されていることを確認。
- Eclipseを起動して、実行→実行構成を選択すると実行構成のダイアログが表示される
- Androidアプリケーションをダブルクリックして、新規構成
- プロジェクトの参照で、MyElecPianoを選択。上の名前も同じにしておく
- ターゲットタブを選択
- デプロイ・ターゲット選択モードで、「デバイスを選択するときに常にプロンプトを表示」を選択
- 実行ボタンを押すと、Androidデバイス選択のダイアログが表示され、
- 実行中のAndroidデバイスを選択するで、asus-nexus_7-xxxxxxxxと表示されるので選択してOKボタンを押す
- Android端末側でも、USBデバッグを許可するダイアログが表示されるので、許可しておく。
- 「Bluettooth My Elec Piano」が転送されて、赤い枠のMyピアノというアイコンのアプリが追加される
- トラ技ARMライタに、USBケーブルで電源を接続する
- Android端末で、書き込んだアプリ「Bluetooth My Elec Piano」を起動する
- 画面上の接続ボタンをクリックすると、Bluetoothモジュールのシリアル番号が表示されるので選択
- 接続に成功すると、「接続完了」と表示される。「接続失敗」の場合は、もう一度接続ボタンを押してみる
- Android端末の画面上の鍵盤をクリックすると、
[top]
- こちらが詳しく書いてあったので、参考にさせてもらいました
- Git for Windowsとか、Githubのアカウント登録とか、以前、やってあったのは 省略1
- eclipseを起動、ヘルプ→新規ソフトウェアのインストールで、以下のURL入力して、Enterを押す
- Eclipse Gitチーム・プロバイダとJGitを選択して、
- 使用条件の条項に同意
- 完了しても、インストールは時間が掛かるので待つ。。
- 署名なしソフトをインストールしていいか聞いてくるので、OKとする
- Eclipse再起動を聞いてくるので、OKする
- ウィンドウ→ビューの表示→その他...で、Git関連のウィンドウが開けるようになる
- Eclipseのウィンドウ→設定で、チーム→Gitの複製リポジトリが、設定されていること、
- 構成で、ユーザ名とメールアドレスが設定されていることを確認しておく
- Githubで、保存用のリポジトリを作成しておく。
- アカウントは、以前作成済みなので、右上のSign inボタンを押して、UsernameとPasswordを入力
- +New Repositoryボタンで、Repository nameとDescriptionを記入、Public2
- 作成したリポジトリのURLが表示されるので、メモしておく
- パッケージエクスプローラでプロジェクト名を右クリック、
- チーム→プロジェクトの共用で、Gitを選択して次へ
- Gitリポジトリの構成で、プロジェクトの親フォルダー内のリポジトリを使用または作成をチェックしてから、
- リポジトリの作成ボタンを押して、ローカルリポジトリを作成する
- コミットする前に、binフォルダと、genフォルダについては、生成可能なので、対象外としておく
- 右クリック→チーム→無視とすると、.gitignoreファイルに記述され、コミット対象外となる
- 改めて、パッケージエクスプローラで、プロジェクト名を右クリック、
- チーム→コミットで、コミットメッセージを指定(簡単で良いので、あとでわかりやすいもの)
- コミットするファイルを選択して、コミットボタンを押す
- パッケージエクスプローラで、プロジェクト名を右クリック、
- チーム→リモート→プッシュで、メモしておいた GithubのURLを設定
- ホスト名とリポジトリ・パスは、自動的に設定される。プロトコルはhttps
- Github認証用の、ユーザ名とパスワードを設定して、次へ
- ソース参照で、master[ブランチ]を選択して、+Add Specボタンを押す
- Specifications for プッシュに、表示されたのを確認して、完了ボタンを押す
- これで、 Githubの、自分のリポジトリに登録されているはずなので、確認してみる
- code.google.comのインポートが出来るかもと思って、
- Google Plugin for Eclipseをインストールしてみた
- eclipseを起動、ヘルプ→新規ソフトウェアのインストールで、以下のURL入力して、Enterを押す
- 使用条件の条項に同意
- 完了しても、インストールは時間が掛かるので待つ。。
- 署名なしソフトをインストールしていいか聞いてくるので、OKとする
- Eclipse再起動を聞いてくるので、OKする
- Eclipseが再起動して、Googleメニュー(○にgのアイコン)が追加されている
- でも、Googleホストプロジェクトのインポートをしても、
- 何も表示されず、キャンセルしかできない
- 使い方が分からないので、保留
- 結局、code.google.comからのインポートは
- このアドレスを、インポート→Git→Gitからプロジェクトで、次へボタン
- Clone URI、次へボタンで、上記のURIを指定すれば、インポートできる
- プロジェクトをインポートに使用するウィザードを選択 では、
- これで、パッケージエクスプローラでは、インポートしたプロジェクトにエラーマークが付くが、
1でも、この設定以外にもいろいろやったかもしれない、やはり前述の記事を参考にした方が良いと思う。
2公開指定。この場合無料で使用可能。
3一般的なプロジェクトとしてインポートを選ぶと、プロジェクトとして認識されない様な気がする。
4どうして、エラーマークが消えるのか良く分からない。ダメな場合もあるかもしれない。
[top]
- サンプルプログラムを見ながら、Androidのプログラムを勉強してみる
- Androidのプログラムのフローは以下のようになっているらしい
- onCreate() →Activityの生成時に実行される
- onStart() →Activityが表示される前に実行される
- onResume() →Activity前面に来た時に実行(Activateイベント)
- Activityの実行中
- onPause() →別のActivitiの開始前に呼び出される(データの保存等行うべき)
- onResumeに戻って、別のActivityが表示される
- onStop() →元々のActivityは停止状態になる
- 停止状態のActivityを再表示する場合、onRestart()を実行後、onStart()に戻る
- 他のアプリがメモリを要求している場合は、停止状態のActivityを強制終了してから最初に戻る
- onDestroy() →Activityの終了
- Androidのリソースは、基本的にresフォルダ下のフォルダ名とXMLファイル名で指定されるが、
- アイコンの様にPNGファイル名だったり、ストリングのようにXMLファイル中の定義名を指定する例外もある
フォルダ/ファイル | 定義内容 | XMLで参照 | Javaで参照 |
res/layout/xxx.xml | レイアウト | @layout/xxx | R.layout.xxx |
res/drawable/xxx.png | アイコン | @drawable/xxx | R.drawable.xxx |
res/menu/xxx.xml | メニュー | @menu/xxx | R.menu.xxx |
res/values/strings.xml | ストリング(文字列) | @string/xxx | R.string.xxx |
- ストリングリソースについては、strings.xmlの中で、以下のように設定する
<string name="xxx">Hello World!</string>
リソースのID
- リソースのIDは、例えば「@+id/resourcename」という様に記述できる5
@[パッケージ:][+]リソース型/リソース名
- パッケージは省略可能
- リソースのXMLファイルの先頭には、以下の宣言が必要
<?xml version="1.0" encoding="utf-8"?>
参考: リソースの定義と指定
- 1つのOnClickで、ボタンのID毎に処理を振り分ける方法はすぐに思い付くけど、
- これはボタン毎に、onClickListenerを用意して、その中でOnClickを定義している
参考: 美しいOnClickListenerの実装方法 →何故こんな書き方をしてるのか良く分かった(ような気がする)
- LogCatは、EclipseでAndroid開発用のLog表示を行うプラグイン
- 最初で、クラスをImportしておく
import android.util.Log;
- Logへの出力は、以下の様に記述するだけ
Log.d("タグ","メッセージ");
LogCatウィンドウは小さいので、横長に引き伸ばさないと、メッセージが見れないので注意
- LagCatウィンドウ自体が無い場合は、ウィンドウ→ビューの表示→その他で、Android→LogCatを選択すれば良い
- Log.dメソッドはデバッグ用で、他にも用途別に以下が用意されている
用途 | メソッド |
デバッグ(debug) | Log.d |
エラー(error) | Log.e |
情報(info) | Log.i |
詳細(verbose) | Log.v |
警告(warm) | Log.w |
参考: デバッグログを表示する
- で、実際使ってみると、表示が多すぎて使い物にならない。。
- と思ったら、フィルタできるらしい。というか、フィルタ使わないと使えない
- 左側のフィルタで、+ボタンを押して、フィルタを登録する
- 例えば、by Log tagに、タグ文字列を入れると、そのタグの表示しか出ないようになる
- 正規表現も使えるらしいので、必要な情報のみ出すことが出来るだろう
- widget.Toastは画面に簡単なメッセージを表示して、すぐ消えるという機能
import android.widget.Toast;
:
:
protected void showMessage(String msg){
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
これでメッセージを表示できる
showMessage("Hello World!");
- 文字色を変えるのはちょっと面倒だ
- Viewに置いた部品からTextViewを探して、色を変えているらしい
public static void warning(String msg) {
Toast toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
View v = toast.getView();
v.setBackgroundColor(Color.YELLOW);
if (v instanceof ViewGroup) {
ViewGroup g = (ViewGroup)v;
for (int i = 0; i < g.getChildCount(); i++) {
View c = g.getChildAt(i);
if (c instanceof TextView) {
((TextView) c).setTextColor(Color.BLACK);
}
}
}
toast.show();
}
- Toastはすぐに消えてしまうので、ボタンを押すまで表示されるAlertDialogの方が良いこともある
new AlertDialog.Builder(this)
.setTitle("Title")
.setMessage("Message")
.setPositiveButton("OK", null)
.show();
- Androidエミュレータは動いていたんだけど、
- OKして、起動すると、以下の表示が出て起動しない。
Unfortunately, Launcher has stopped.
- Android SDK Toolsの、Android SDK Managerを起動
- Intel x86 Emulator Acceleratorをチェックして、インストール
- 続いて、AVD(Android Virtual Device) Managerを起動
- Createで、DeviceをNexus7で、Use Host GPUにしたものを作成
- なんか、ちゃんと動く様になった。エミュレータの画面が全然違うけど。
- でも、何が悪かったのか、どの設定が効果があったのか不明。。
- Android SDKのアップデートをしたら、Ecripse起動後に、以下のダイアログが表示されるようになった
This Android SDK requires Android Developer Toolkit version 23.0.0 or above.
Current version si 22.6.3.v201404151837-1123206.
Please update ADT to the latest version.
- 更新の確認ボタンを押しても、更新が検出されませんでしたとなる。
- この状態では、起動も全く出来なくなってしまった。
参考:Android SDKアップデート後のエラー対応
- ヘルプ→新規ソフトウェアのインストール...を選択、
- 作業対象のプルダウンメニューから、Android Pluginを選択して、
- 表示された、開発ツールにチェックを入れて、次へボタンを押す
- インストールされて、ライセンス許諾にチェックを入れて完了
- さらに、Eclipse上でインストールされるので、少し待っていると、再起動の確認ダイアログが出るので再起動
- Intentの意味を調べると、意図とか目的ということ
- システムに対して、意図とか目的を指示して、処理をしてもらう仕組みらしい
- 実行する処理(Action)、その補足情報(Category)、対象となるデータ(Data)等のうち、必要な情報を指定してIntentをシステムに投げる
- アプリケーション側は、受付可能なIntentの条件を、intent-filterで指定する
- Androidで、例えばブラウザが、JPGを表示する場合、
- ブラウザは、Intentを作成(アクション:データを画面に表示、データ:xxx.jpg)
- システムは、Intentを受け取ると、画像表示アプリをユーザに選択させて、選択したアプリにIntentを渡す
- アプリは、Intentを受け取って、JPGファイルを表示する
- Intentによって、アプリ間でデータ連携が簡単に出来るらしい。
- アプリ内でも、同じようにデータ連携で利用されるらしい
- サンプルでは、例えばメインのアクティビティから、デバイス選択のアクティビティへの画面遷移に使われている
// 接続ボタンイベントクラス
class SelectExe implements OnClickListener{
public void onClick(View v){
Intent Intent = new Intent(ActivityElecPiano.this, DeviceListActivity.class); // デバイス検索と選択ダイアログへ移行
startActivityForResult(Intent, CONNECTDEVICE); // 端末選択したら接続要求
}
}
- イメージ的には、WindowsのSendMessageに近い感じがするんだけど、どうなんだろ?
- 現在のActivityのインスタンスと、呼び出すサブActivityのクラスを指定して、Intentのインスタンスを作成
- サブActivityから値を戻さない時は、startActivityで、Intentを起動する
startActivity(intent);
- サブActivityから値を戻すときは、startActivityForResultで、Intentを起動する
- サブActivity側では、getIntentでIntentを取得して、
- 値を戻す時は、やはりputExtraメソッドでキーと値を指定してデータをメインActivityに戻す
- サブActivityから戻ってきた時は、onActivityResultメソッドが呼ばれる
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
String result;
if (requestCode == SUBACTIVITY) {
if (resultCode == RESULT_OK) {
Bundle extras = intent.getExtras();
if (extras != null) result = extras.getString("RESULT_STRING");
}
}
}
- 戻す時にも、Intentを使うのか。。
- 使い方は良いとして、Intentって、なんかよく分からない概念の機能だなぁ。。。
- AndroidのUIは、基本的にシングルタスクでしか動かすことが出来ないらしい。
- 基本的に、1つのタスクからしかUIは操作できないということか。
- Handlerというのは、このHandlerのインスタンスを作成したタスクが、
- サンプルでは、Handlerを生成した後のBlockにメッセージ処理を記述するようになっている
- ボタンのイベント処理もこんな書き方をしていたけど、Javaではこういう書き方が一般的なのかな。
- あぁ、なんかいろいろな仕組みや用語が多くてメンドイなぁ。。
- 追記:タスク毎に、処理をキューで順番に実行する Looper という仕組みがあって、
- それに処理を登録するのが Handler というものらしい
- postDelayedで、1000m秒後に呼出されるようにする
wake_handler.postDelayed(wake_task, 1000);
- Android用のアプリケーション・アイコンの作り方
- プロジェクトで右クリック、新規→その他で、ウィザードを開く
- Android→Android アイコン・セットを選択して、次へ
- Lancher Iconsを選択して、次へ
- とりあえずなら、テキストで適当な文字を設定して、完了を押す
- 予め、大きめのイメージファイルを用意しておけば、それを元に自動生成することも出来るようだ。
- GooglePlay用のLancherは512x512らしいので、その大きさで元ファイルを作るのが良いのかもしれない。
- これで、以下の4種類の大きさのアイコンがそれぞれのディレクトリに生成される
- mdpi 160DPI(48x48) →/res/drawable-mdpi
- hdpi 240DPI(72x72) →/res/drawable-hdpi
- xhdpi 320DPI(96x96) →/res/drawable-xdpi
- xxhdpi 480DPI(144x144) →/res/drawable-xxdpi
- Android アイコン・セットを使わずに、、/res/drawable下に、ic_launcher.pngという名前で、イメージファイルを入れるだけでも良い。
参考: アイコンのデザインガイド
- 例えば、文字列リソースは、res/values/string.xmlに定義されているが、
- res/values-ja/string.xmlを作成して、同じNameで文字列を定義する
- そうすると言語設定が、日本語ならvalues-jaフォルダ、それ以外はvaluesフォルダのXMLを使用するようになるらしい
参考: Androidアプリの多国語対応の方法 →ここは、他にもいろいろ参考になりそうです
- ListViewは、リストを表示して選択させるインターフェース
- まず1行分の表示用に、TextViewの設定をしたXMLファイルを用意(layout/list.xml)
- それから、通常のActivity用のXMLファイルを用意(layout/main.xml)
- あとは以下のように、配列データを用意して、1行分のレイアウトを指定して、Adapterにセット
- リストのアイテムクリックのイベントリスナを定義する
private ListView list;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String[] ldata = {"AAA","BBB","CCC","DDD","EEE","FFF"};
list = (ListView)this.findViewById(R.id.listView1);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list, ldata);
list.setAdapter(adapter);
list.setSelection(1);
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?>adapter, View view, int position, long id) {
TextView tview = (TextView)view;
Toast.makeText(HelloListView.this, tview.getText() +" が選択されました", Toast.LENGTH_LONG).show();
}
});
}
- EditBoxの右に▼が付いて、ドロップダウンリストから選択するインターフェース
private Spinner m_spinner;
public static ArrayList<String> spinnerlist;
@Override
public void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
m_spinner = (Spinner)findViewById(R.id.spinner1);
spinnerlist = new ArrayList<String>();
spinnerlist.add("Alpha");
spinnerlist.add("Beta");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, spinnerlist);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
m_spinner.setAdapter(adapter);
m_spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
//アイテム選択時
public void onItemSelected(AdapterView<?> adapter, View view, int pos, long id) {
String item = (String) adapter.getSelectedItem();
}
//アイテム非選択時
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
- この例では、Spinnerの選択項目を動的に変更できるようにArrayListで定義している。
- Spinnerのレイアウトは、システムで用意されている以下のXMLファイルを参照している
- android.R.layout.simple_spinner_item
- android.R.layout.simple_spinner_dropdown_item
- 前項で示したSpinnerのレイアウトファイルを、カスタマイズしたものを作成すれば、文字サイズを変更できるが、
- その中でStyle名が定義されているので、Styleを定義してThemeをカスタマイズする方法がある。
- 例えば、/res/values/styles.xmlファイルを作成して、Spinnerの文字サイズを指定してみる
- このThemeを使うには、AndroidManifest.xmlで指定すれば良い
android:theme="@style/AppTheme"
- ActivityにLayoutを配置は、通常以下のようにする
setContentView(R.layout.main);
View view = this.getLayoutInflater().inflate(R.layout.main, null);
setContentView(view);
public View inflate(int resource, ViewGroup root, [boolean attachToRoot])
- resource: R.rootで始まるレイアウトID
- root: 生成するViewの親となるView(必要ない場合はnull)
- attachToRoot: 親Viewにaddするかどうかのフラグ
- addしない場合でも、親の情報を必要とする場合は、親Viewを指定しなければならないらしい
- 例えば、親Viewの幅に合わせる属性を持っている場合とか
- まず、部品の幅と高さを指定する
- android:layout_width
- android:layout_height
- 直接サイズを指定(通常はdp単位)する以外に
- match_parent は、置いた場所に合わせて最大の大きさになる
- wrap_content は、部品の中身に合わせて大きさを決める
- サイズを指定した場合、wrap_contentでサイズを決めた場合には、余った分が空白になる。
- android:layout_weightで、余った分を各部品で分配することが出来る
- 例えば、2:1で分配する場合、layout_weight=2,layout_weight=1とすればよい。
- EditTextやButton等は高さを固定して、ListViewの部分だけ画面サイズに合わせて大きさを変える場合は、
- 高さを固定する部品はlayout_weight=0として、大きさを変える部品、例えばListViewはlayout_weight=1とすると、
- 余った場所を、ListViewだけがうまく使ってくれるようになる
- layout_waitは、部品サイズを引いて余った場所を分配する7ので、配置がwaitの比率ににならなかったりするが、
- 部品のサイズに関係なく均等に分けたい場合は、部品の大きさを0dpに設定すると分かり易い。
- dp(dip):160dpiの画面で1pxとなる大きさ→つまり320dpiでは2pxになる
- onDrawの、getMeasuredWidth(), getMeasuredHeightで、部品の幅と高さを得られる様だ
- タップした時に文字色を変えたい場合、Selectorを使う
- LayoutのXMLで、以下のようにtextColor指定する
android:textColor="@drawable/text_color"
- タップした時の背景色を変える場合は、文字色とはSelectorの記述方法が異なる9ので注意
- LayoutのXMLで、background指定する
android:background="@drawable/text_bcolor"
- /res/drawableにXMLでShapeを定義する
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#00000000" />
<stroke android:width="1dp" android:color="#ffffff" />
<padding android:left="5dp" android:top="5dp" android:right="5dp" android:bottom="5dp" />
<corners android:radius="6dp" />
</shape>
- LayoutのXMLで、background指定すれば良い
- Activity.onCreateDialogを使う場合(現在は非推奨)
public class MainActivity extends Activity {
:
:
private void showAlert() {
showDialog(0);
}
@Override
protected Dialog onCreateDialog(int id) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Title")
.setMessage("Message");
return builder.create();
}
}
public class MainActivity extends FragmentActivity {
:
:
private void showAlert() {
FragmentManager fm = getSupportFragmentManager();
AlertFragment af = new AlertFragment();
af.show(fm, "alert_dialog");
}
}
public class AlertFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Title")
.setMessage("Message");
return builder.create();
}
}
- FragmentManagerをImportしても、以下のエラー
- 型の不一致: android.support.v4.app.FragmentManager から android.app.FragmentManager には変換できません
final EditText editView = new EditText(FilelistSaveActivity.this);
new AlertDialog.Builder(FilelistSaveActivity.this)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle("Dialog title")
.setView(editView)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// OKボタン処理
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Cancelボタン処理
}
})
.show();
<resources>
<integer name="intData">123</integer>
<string name="stringData">ABC</string>
<array name="intArray">
<item>1</item>
<item>2</item>
<item>3</item>
</array>
<array name="stringArray">
<item>ABC</item>
<item>DEF</item>
<item>GHI</item>
</array>
</resources>
それを、プログラムから使う方法
// 整数値
int[] intData = getResources().getInteger(R.array.intData);
// 文字列
String stringData = getResources().getString(R.array.stringData);
// 整数値配列
int[] intArray = getResources().getIntArray(R.array.intArray);
// 文字列配列
String[] stringArray = getResources().getStringArray(R.array.stringArray);
- 特定のクラスで使う定数テーブルを、リソースに保存しておいて、読込もうとしたんだけど、、
- 普通のクラスからは、getResources出来ないようだ。
public synchronized boolean wait_ms(long msec) {
try {
wait(msec);
} catch(InterruptedException e) {
e.printStackTrace();
return false;
}
return true;
}
- 短い音を鳴らす場合、SoundPoolを使う
- 効果音のファイル、例えばpi.wavを/res/rawに入れておく
SoundPool soundPool;
int sound1;
int stream1;
// リソース読込み
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
sound1 = soundPool.load(context, R.raw.pi, 1);
// 効果音を鳴らす
stream1 = soundPool.play(sound1, 1.0f, 1.0f, 0, 0, 1.0f);
// リソース開放
soundPool.stop(stream1);
soundPool.unload(sound1);
soundPool.release();
- SoundPool(maxStreams,streamType,srcQuality)
- SoundPool#load(context,resId,priority)
- SoundPool#play(soundID,leftVolume,rightVolume,priority,loop,rate)
- API21以降は、SoundPool.Builderを使うべきらしい。
- 呼出し方も全然違うみたいだけど、自分の環境だとちょっと確認できないので、そのうち試そう
private MediaActionSound mShutterSound;
// リソース読込み
mShutterSound = new MediaActionSound();
mShutterSound.load(MediaActionSound.SHUTTER_CLICK);
// シャッター音を鳴らす
mShutterSound.play(MediaActionSound.SHUTTER_CLICK);
// リソース開放
mShutterSound.release();
mShutterSound = null;
- リソース読込みは予めonCreateとかでやって、開放はonDestroyとかでやる
- 或いは、onResumeとonPauseでやるべきかも。
- Backキーを押すと、Activityが終了してしまう。
- 何回もビルドしていると、いつ改定したものか分からなくなってしまう。
- この方法は、Eclipseではうまくいったんだけど、Android Studioにしたら出来なくなった。
- Apkファイルを展開すると、ちゃんとMANIFEST.MFはあるのに、何故か、1979/11/30 24:00.0010になる。
- パッケージファイルから、インストール日付を取得できる
- firstInstallTime で、最初のインストール
- lastUpdateTime で、最後にインストールした日付が分かる
PackageInfo packageInfo = null;
try {
packageInfo = getPackageManager().getPackageInfo("zzz.yyy.xxx.appName", PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Date dateLastUpdateTime = new Date(packageInfo.lastUpdateTime);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd kk:mm.ss");
String installDate = sdf.format(dateLastUpdateTime));
- これで、ビルド日付を取得出来れば良いのに。。
- Androidのバージョンで、処理を切り分ける場合、コンパイラエラーになるので、
コードネーム | バージョン |
| 1.0 |
| 1.1 |
Cupcake | 1.5 |
Donut | 1.6 |
Eclair | 2.0 |
Froyo | 2.2 |
Gingerbread | 2.3 |
Honeycomb | 3.0 |
Ice Cream Sandwich | 4.0 |
Jelly Bean | 4.1 |
KitKat | 4.4 |
Lollipop | 5.0 |
Marshmallow | 6.0 |
Nougat | 7.0 |
Oreo | 8.0 |
- クラスの継承の階層を調べる
- クラスを選択して、右クリック→型階層を開く(F4)
- クラスを選択して、ctrl+T(クイック型階層)
- メソッドの定義を見る
- メソッドを選択して、右クリック→宣言を開く(F3)
- クラスやメソッドの構造を見る(クイックアウトライン)
- インデントを揃える
- 選択して、右クリック→ソース→インデントの訂正
- 選択して、ctrl+I
- 複数行をコメントアウトする
- 選択して、ctrl+/
- 選択して、ctrl+shift+/ → /* 〜 */でコメントアウトされる
- Importを追加する
- メソッドを選択して、右クリック→ソース→インポートの追加
- Importを整理 →ワイルドカード指定を必要なクラスに整理
5+を付けると、新しくIDを生成して、Rクラスに追加するらしい。ID以外にも使えるのかな?
6じゃない場合もある様だ。よくわからん。。
7サイズ考えないと、waitとは逆の大きさになっちゃたりする。なんで、こんな分かりづらい仕様にしたんだろう。
8pressed以外に、selected,focused,checkedとか、いろいろあるらしい。
9AndroidのXMLって、わけわからん仕様が多い気がする。
10この日付は、なんか意味のあるものなんだろうか。
[top]
- Eclipseで、Androidのアプリケーションをプログラムしている時に起こったエラーの備忘録
- Menuリソースを追加しようとしたら、コンソールにエラーが出た。
W/ResourceType( 9160): ResXMLTree_node size 0 is smaller than header size 0x45.
D:\work\eclipse\TestApp\res\menu\main.xml:4: エラー: エラー: No resource found that matches the given name (at 'icon' with value '@drawable/a').
- なんだか分からなかったが、単にアイコンのデータを用意するのを忘れていただけだった。
参考: XMLのエラーは分かりにくい
- プログラムのリソースを参照している箇所にエラーマークが付いて、
- カーソルを持っていくと、「Rを変数に解決できません」と表示される
- Rを参照できなくなっている様だ。
- 確認してみると、genフォルダ下にあるはずの、R.javaが無くなっている
- これは、リソースファイルに何らかのエラーがあって、R.javaが生成出来なかったということらしい。
- たとえば、前項のエラーのようにアイコンのファイルを忘れただけでも、このエラーが出る
- R.javaが生成されていて、変数も定義されている場合は、
- AndroidManifest.xmlで定義されているpackage名が合っているか確認11する
- 他のパッケージからリソースを使うなら、'R'をインポートする
- リソースを追加したのに、R.javaに登録されない
- Cleanしてみたがダメだった。
- ちょっと悩んだが、単にリソース追加後に保存するだけで直った。
- リソースの追加後の保存は自動的には行われないらしい。
- パッケージ名が違っていると、やっぱりダメなので、これもチェックしておく。
- でも、R.javaにちゃんと登録されているのに、このエラーが出ることがある。
- その場合は、以下の行が無いかチェックしてみる
import android.R;
- この行を削除すると、大概はエラーが解消される
- Eclipseから、アプリケーションを起動しようとした時に、コンソールにエラーが出る
Failed to install TestApp.apk on device '07f3c25f': タイムアウト
起動はキャンセルされました!
- タイムアウトの時間は、ウィンドウ→設定→Android→DDMSの、ADB接続タイムアウトで設定できるが、
- サンプルプログラムをImportしたら、R.javaにエラーマークが付いている
- 通常はgenフォルダ下にあるはずのR.javaが、srcフォルダ下に入っている
- これは古い環境の仕様らしいので、srcフォルダ下のR.javaは削除する。
- それから、default.propertiesというファイルを追加して、
- 以下のように対象のAndroidのバージョンに合わせてターゲットを設定しておく必要があるらしい
target=android-10
参考: Androidのバージョン違いによるサンプルの動作について
- AndroidManifest.xmlに、xxxxxxxxという名前のActivityが定義されていない。
- 使用するActivityは、全てAndroidManifest.xmlに定義しておく必要がある。
- サンプルプログラムをImportしたら、ソースコードに大量のエラーマークが表示される。例えば、
- この行に複数マーカーがあります
- xxxxxを型に解決できません
- 最初の、packageの行からエラーになっているので、どうしようもない。。
- 途方にくれてしまうが、これはサンプルプロジェクトのJavaのバージョン設定が古い可能性がある
- Eclipseで、プロジェクト→プロパティを選択、Androidの設定を確認、
- ターゲット名で古いバージョンのAndroidが指定されていたら、新しいバージョンに設定してみる
参考: Android初心者がよくやる失敗
- Eclipseで、こんな風にデータファイルを読み込もうとしたら、
InputStream inStream = new FileInputStream("src/filename.txt");
- 基本的には、Eclipseのプロジェクトファイルを基準にしたパスで書けば良いみたいだ。
- classファイルと同じpackageの中に入れてしまっていたのが問題だった。
- src下に入れなおしたら、問題なしだった。まぁ、考えればあたりまえなんだけど、
- Eclipseのパッケージ・エクスプローラ上で、ついpackageの中に入れてしまった。。
- package文に記述されたパスが、
- そのファイルの置いてあるパスと一致しない場合に出るエラーだと思う
- それをチェックすれば、良いと思うが、
- hm.orz.bluefish.testと纏めて記述することが、出来るらしい
- また、package文のパスの記述が、自動的に書き換わったりするみたいだ
- いまいち、正しい設定の仕方が分からなかったりする場合がある
- 実行構成で、プロジェクト名を指定しようとしても、参照でプロジェクト名がリストされない
- プロジェクト名を、直接記述してみると、このエラーが出た
- 一般的なプロジェクトとしてインポートすると、プロジェクトとしてうまく認識されないのか?
- 既存プロジェクトのインポートとして、やり直すと、エラーマークが出るんだけど、
- プロジェクト→クリーンで、エラーマークが消える
- これに関しては、何故そうなるのか、さっぱり分からない。。
- StrageDirにファイルを保存しようとすると、FileNotFoundExceptionが出る
- 保存するのに、何故FileNotFound? ディレクトリは存在するのに? かなり悩まされたんだけど。。
- 結局、AndroidManifestに、パーミッションの設定を加えないとStrageDirには保存出来ないらしい
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- Permission Deniedとか言ってくれれば、すぐ分かったのに。。
- onDestroyをOverrideした時に、super.onDestroyを呼ばなかったら、これが出た。
- コンソールにはエラーメッセージが出ないので、LogCatを見る
- Tagが AndroidRuntimeで、テキストが java.lang.RuntimeException: で始まる行を探す
- 例えば、XMLファイルで、自作のViewのパスが間違っていた場合は、コンパイル時のエラーが出ない
- SDcardにファイルを書き込んでも、それだけでは、他のアプリケーションが認識出来ない。
- AndroidのOSを再起動すれば、SDcardがスキャンされるので、認識されるようになる。
- 以下のように、MediaScannerConnectionで、指定したファイルを登録することが出来る
MediaScannerConnection.scanFile(
context,
new String[] { Environment.getExternalStorageDirectory() + "/" + fileName },
new String[] { "text/plain" },
null);
- LogCatのWindowが表示されない
- ウィンドウ→ビューの表示→その他で、LogCatを選択してもダメ
- DDMSのモードにすれば表示されるんだけど、Javaでは表示されない
- 結局、これはLogクラスがインポートされていないと表示されないらしい
import android.util.Log;
- 実行時、Androidデバイスの選択で、targetがunknownになってしまい実行出来ない。
- 接続しなおしてもダメなので、Windows7を再起動してみたら直った。
- EditTextの内容をIntentで戻そうとしたら、
public void onClick( View v ) {
final int iTag = (Integer)v.getTag();
switch( iTag ) {
case BUTTON_OK:
Intent intent = new Intent();
intent.putExtra( "file", m_EditText.getText().toString());
setResult( Activity.RESULT_OK, intent );
finish();
break;
}
}
beginBatchEdit on inactive InputConnection
endBatchEdit on inactive InputConnection
- ソフトキーボードを消してから実行すれば出なかったので、プログラムで消してから返したらOKだった。
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- よく分からないが、キーボードが出てる間は入力中ってことなのかな?
- AsyncTaskで、Toastで出力しようとしたらエラーになった
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
- UIスレッド以外で、GUIを弄っちゃダメってことか。
- LayoutのXMLファイルで、部品の順番を変えたら出た。
- リソースファイルを変更しても、R.javaファイルが更新されない場合があるようだ。
- というか、リソースを変更したら、クリーンしないとダメなのかも。
- ToastもUIを弄るので、UIスレッド以外から呼出すと、エラーになる
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
- MainのLooperにHandlerで直接投げる手があるらしい
- 今まで動いていたのに、MainのActivityのSetContentViewでInflateExceptionで落ちるようになった。
- Contentに含まれる自作のViewのonCreateで、popupWindowの初期化処理を追加したのを忘れていた。
- その中で、getLayoutInflaterを実行していた。
- 多分、親のActivityが生成される前だったのがマズイんじゃないかと思う。
- 別件で、クラスにいろいろなインターフェースをimplementを試しているときに、
- うっかりabstructに設定してしまい、やはりInflateExceptionで落ちるようになったが、
- しばらく気がつかなくて、けっこう悩んでしまった。
- 代入したい場合は、グローバル変数使ってるけど、あんまり良いやり方じゃないか。。
- AlartDialog上のEditTextをタップすると、
- Dialogが上に移動して、下にキーボードが表示されるが、すぐに閉じてしまう。
- LogCatで以下のWarning表示
beginBatchEdit on inactive InputConnection
endBatchEdit on inactive InputConnection
- 画面が横向きの場合は、画面全体がキーボードだけの表示になるが、ちゃんと編集可能
- でも縦向きに戻すと、キーボードは消えてDialogだけの表示になる。例のWarningも表示されている。
- キーボード表示中に、AlartDialogの再表示が行われることで、なにか問題が起こっている。のかな?
- カスタムView上に、Dialogを表示しているんだけど、それが問題なのかも
- 結局、OnDrawの中でテスト的に無条件でDialogを表示していたので、
- キーボードが表示されたあとに、onDrawが発生、Dialogが初期状態に戻っていただけだった。
- OKボタンも効かないことがあったので、やっと気がついた。
- 分かってみるとくだらない理由だったけど、かなり時間を浪費したので、自戒のため記録しておく。
11別のパッケージのActivityを使う場合は、package名を付けることを忘れないように。
[top]
- とりあえず、メモしているので、ちゃんと見ていないものも有り
- トラ技の2014年3月にスマホ電子工作の特集があったので、バックナンバーを買ってきて参考にした
[top]
[プログラムの部屋に戻る]