Android

下位ページ

Content

スピナーコントロールの設定

レイアウトの準備

<Spinner
  android:id="@+id/planets_spinner"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content" />

選択肢の設定

string.xmlでの設定

まずは、string.xmlに文字配列を作る
<string-array name="planets_array">
  <item>Mercury</item>
  <item>Venus</item>
  <item>Earth</item>
</string-array>

  • この文字配列をアダプタにして、スピナーコントロールにアダプタをする
    • リソースのアダプタ化には、ArrayApapter.createFromResource を使用できる。
      • simple_spinner_item はデフォルト外観を設定している。通常はこれで良し。
    • setDropDownViewResource(int) は選択時に一覧を表示するのに使う。なくても一応ドロップダウンは出てくるが、ちょっとしょぼい?

Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.planets_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);


プログラム側から値を選択する

Spinner.setSelection で位置を指定する。その位置を取得するにはAdapterを使う。
  • 使っているアダプタを取得する
    • objSpinner.getAdapter でアダプタを取得できる
  • objAdapter.getPosition("...") でセレクタの位置を取得
    • 値が見つからなかったら -1 が返る
  • objSpinner.setSelection に先程取得した位置を設定する

ArrayAdapter spinnerAdapter = (ArrayAdapter) objSpinner.getAdapter();
int i = spinnerAdapter.getPosition("value");
objSpinner.setSelection(i);



アクティビティ

アプリの閉じられ方で、挙動が異なる

onDestroyが呼ばれない限りは、Serviceを使わずとも、
↓にある通り、ホームボタンとバックボタンでアプリケーションから離れた場合で挙動が違う。
https://kokufu.blogspot.jp/2011/03/activity.html

説明として、
  • ホームボタン:ホームアプリケーションが起動している
  • バックボタン:Activityスタックからポップしている
と書いてあったが、気持ち悪いのは、□ボタンを押すとあたかもまだ生きているかのように、アプリケーションリストに表示されるから。画面上に残っているが実際には onDestroy で消えている。
このあたりが、「アプリケーションをスワイプして消しても消さなくてもメモリにはそれほど影響しない」ということなんだろうか。

アクションバーの代わりに、ツールバーを使う

今後の拡張性から、アクションバーよりツールバーを使ったほうが良い、という記述をちょこちょこ見かけるが、Android Studioでプロジェクトを作ると、基本はアクションバーが設定されている。これをツールバーに置き換える。


アクションバーを消す

res/values/styles.xmlで AppThemeのテーマを変更する
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

ツールバーをレイアウトに追加する

<android.support.v7.widget.Toolbar
  android:id="@+id/toolbar"
  android:layout_width="match_parent"
  android:layout_height="wrap_content" />


Activity内で、アクションバーの代わりに使う記述をする

/* ToolBarの設定 */
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
toolbar.setTitleTextColor(Color.WHITE); // 設定をしておく
setSupportActionBar(toolbar);   // アクションバーの代わり、という設定

これを書かないと、画面上では何も表示されない(空間だけはある)

スライドメニューを実装する

NavigationDrawer が正式名称?


ドロワーレイアウトを作成する

  • レイアウトxmlにて、DrawerLayout オブジェクトをレイアウトのルートビューとして指定する。
  • ルートの中にドロワービューとメインビューを設定する
    • 順序はメインビューを先にする
      • 高さはルートに合わせる(match_parent)
    • 次にドロワーのビューを指定する
      • layout_gravityを指定する(layout_gravity:どっちにくっつけるか、どちら方向から出てくるか?)
        • 右から左に出す場合にはstart
      • layout_heightは親ビューと同じ高さを指定する
      • layout_widthはすべての情報が見える幅を指定する

ドロワービューの中身を準備する

ListViewで作る

ListViewの中に
android:layout_gravity="..."
を入れないと、スライドで入ってくる設定にならず、重ねて見えている状態になる
android:background="#111"
背景がないと、中途半端にすけた状態で表示される。

別のXMLファイルで作る

NavigationViewで作った場合、ヘッダ部分とメニュー部分をそれぞれレイアウトとメニューで作成する
  • app:headerLayout="@layout/drawer_header"
  • app:menu="@menu/drawer"

ドロワーのオープン・クローズを実装する

DrawerLayout にリスナーをセットする。このリスナーは DrawerLayout.DrawerListener を実装して、使う。

Activity にアクションバーがセットされている場合は ActionBarDrawerToggle が DrawerLayout.DrawerListener を実装する。
DrawerLayout mDrawerLayout = ...;
ActionBarDrawerToggle mDrawerToggle;

mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
  public void onDrawerClosed(View view) {...} 
  public void onDrawerOpened(View drawerView) {...}
};

// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);


バックグラウンド処理(サービス)


流れ
  1. Serviceのサブクラスを作成する
  2. AndroidManifest.xmlにサービスを登録
  3. サブクラスで、必要なクラスをオーバーライドする。次のあたり。
    • onCreate()
    • onStartCommand()
    • onDestroy()
  4. アクティビティからサービスを起動する
  5. (きちっと止まるように設計しておく)

閉じられても動作するサービスを動かす


バックグラウンドで動作させるためにはServiceを用いる。

Serviceクラスの作成

Activityのように、作成・開始などのイベントで動くが、おもに3つ。
  • onCreate
  • onStartCommand
  • onDestroy

Activityから、作成したサービスを動かす

startServiceで起動、stopService(stopSelf)で停止。忘れずにServiceを止めないと、いつまでも動き続ける。
startService、stopServiceなどには、インテントを準備して、サービスにそれをなげる形をとっている。
startService - Context | Android Developers
stopService - Context | Android Developers
stopSelf - Service | Android Developers

加速度センサの情報を受ける


回転角の情報を受け取る

センサーは加速度まではそのまま読み取れるが、回転角は加速度情報、地磁気情報から計算する必要がある。まず getRotationMatrix で回転行列を求め、getOrientation で回転行列を回転角に変換する(計算する)


引数に取った2つの配列には、傾斜行列、回転行列(の情報)が計算されて入ってくる。情報が不要ならnullでよい。

回転角の解釈

正位置として
  1. Zは天を指す
  2. Yは磁北を指す
  3. Xは Y,Z の外積を指す


画面の回転を抑制する

AndroidManifest.xmlで抑制する

回転させないActivityに
android:screenOrientation="portrait"
を追加すると、縦向き固定になる


動的に(プラグラム内で)で抑制する



インテントにオブジェクトの情報を乗っける


bundleで多くの情報をわたすような方法として、putParcelableArrayList くらいしか見当たらないので、これを使う。そのためには、Parcelable をimplements したようなクラスを作る必要がある。
Bundle | Android Developers

parcelable をインプリメントしたクラスをつくる

Parcelable実装にはParcelable.Createorというstatic fieldが必要。そのフィールドの初期化にて、Parcelに保存したデータを復元するためのコンストラクタを呼ぶ。
Parcelable | Android Developers

Parcelable.Creater フィールドの実装

  • createFromParcel(Parcel source)
    • Parcelable.writeToParcel() で書き出されたParcelデータをインスタンス化する → コンストラクタを作っておく
  • newArray(int size)
    • ParcelableクラスのArrayを作る

BundleやIntentに情報を乗せる

IntentならputParcelableArrayListExtra、BundleならputParcelableArrayList で情報を登録
putParcelableArrayListExtra - Intent | Android Developers
getParcelableArrayList - Bundle | Android Developers

Activity側で受ける

IntentならgetParcelableで受けられる。受けたときにすでにParcelableをimplementしたオブジェクトで受けられる。
getParcelableArrayListExtra - Intent | Android Developers
getParcelableArrayList - Bundle | Android Developers


複数の情報をリストにして表示する

バイブレーションを一定時間、作動させる

Vibratorインスタンスからvibrate()を実行する。バイブレーションの実施にはAndroidManifest.xmlにパーミッションの追加が必要。

パーミッションの追加


Vibratorオブジェクトを生成する

getSystemServiceでVibratorオブジェクトを生成する
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);

vibrateを実行する

幾つかパターンはあるが、かんたんなところで、これ。
vibrator.vibrate(500);

通知バーにバックグラウンド起動中の表示を出す


裏返したときの方向で、記録を分ける


メニューのバーを設定する

メニューリソースを準備し、表示させる。そのうえで、メニューのタップ動作に対する反応を記述する
メニュー | Android Developers

メニューリソースを準備する


フォルダの作成

デフォルトではメニュー用のフォルダが無い(かもしれない)ので、res/menuを追加し、ここに入れておく。
  1. resフォルダ右クリック
  2. [New]>[Android resource directory]を選択
  3. ダイアログで、「Resource type:」から「menu」を選択し、OK

リソースファイルの作成

  1. menuフォルダを右クリック
  2. [New]>[Menu resource file]
  3. ファイル名を入力し、OK

ファイル内に
<menu>
  <item />
  <item />
</menu>
を記述(実際はidやタイトルを設定する必要あり)
Menu Resource | Android Developers

設定したメニューファイルを、Activityのメニューバーに評させる

onCreateOptionMenuをオーバーライドして、この中でリソースの指定などを行う。XMLのメニューを実際?のメニューオブジェクトに変換するのに、inflatorを使用できる。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
  MenuInflater inflater = getMenuInflater();  //(1)
  inflater.inflate(R.menu.menu_options_menu_list, menu);  //(2)
  return super.onCreateOptionsMenu(menu);  //(3)
}


メニューの選択を受け取る処理を作る

オプションメニューを作っていれば、その受取はonOptionsItemSelectedをオーバーライドして処理できる。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    return super.onOptionsItemSelected(item);
}

このとき、itemにクリックされた情報が入っているので、これを紐解いて、どのメニューがクリックされたか判断し、switchなどで処理する。
int itemId = item.getItemId();

Android 3.0(APIレベル11)以降では メニューリソースXMLのitemに、android:onClick を記述しておくことで、動作を定義させることもできる。

チェックボックスを動作させる


設定画面を設定する/設定情報をローカルストレージに残す



記録内容をGoogleスプレッドシートに記録する


記録内容をGoogleカレンダーに記録する

多分、クライアント用のライブラリが作られていて、簡単に認証処理をしたり、データを取得したりできるようになっていると思われるが、別サイトでも転用が聞くように、地道な方法を取ってみる。というか、専用のライブラリの使い方をよくわかっていない。

流れは
  • OAuth2.0で認証
    • Google API にプロジェクトと登録(キーの発行)
    • 認証コードを発行 & 受け取り
    • コードを access token と交換
  • access token も使って、リクエスト送信

こまごまと引っかかった場所が多数。
  • AndroidManifest.xmlにパーミッションの設定が必要


ブラウザでURLを開く


ブラウザを開くURIとして、認証ページを指定する


リダイレクトを受け取る

大概の(google 以外でも)場合は、認証後に指定したリダイレクト先に飛ばしてくれる。そのスキーム名に応じて、Android側でどのアプリで開くのかを考えてくれる。Android に「このスキームがきたら、俺のアプリで開いて」と指示するためには、AndroidManifest.xml に記述する必要がある。
<scheme>://<host>:<port>/<path>

intent-filter内で、action, category, data を指定する。上記のリダイレクト先に対応する内容を書くのは data で、scheme は
<data android:scheme="com.example.testproject" />
のようになる。

Intent の 定数として ACTION_VIEW などが定義されているが、実体は文字列で、それが android.intent.action.VIEW などになる(ので、どれを設定するかはIntent を参照)。ブラウザでどんなスキームがきたらヨソになげるのか、どんな action として投げるのか、説明されている場所がわからないが、ひとまず
action : ACTION_VIEW 
category : CATEGORY_BROWSABLR
scheme : ここは各自で
で開けた。redirect_uri で <scheme>://~ が指定できない(:/だけ)なので、hostは存在せず、pathだけ。


受け取ったリダイレクトをデータに紐解く

一旦受け取れれば、中身は getIntent() を経由して、中身を見られる(Intent.getAction(), Intent.getCategories() など)。OAuth では、path のなかに code を入れて返してくるので、Dataのなかを探せばある
Intent intent = getIntent();
String data = intent.getDataString();
とすると、googleの認証で指定した redirect_uri のあとに code がくっついて返ってきている。以下、サンプル
com.example.####.####:/oauth2callback?code=4/8abcdefg#

上記の場合、oauth2callback を uri.getPath() で、4/8abcdefg# を getQueryParameter("code") で受け取れる。


codeを送って、tokenを受け取る

コードと必要情報を POST することで、access token との交換をする。この処理は、UIスレッドだとエラーになるので、AsyncTaskで実行する必要がある。

また、交換がうまく行かなかったときは、HttpURLConnection の getInputStream ではなく、 getErrorStream に情報が流れるため、プログラムの確認作業では注意。(この辺をよくわかっていなくて、エラー原因を探すのに苦労した。)

redirect_uri はスキームもパスもコード発行依頼時と同じものを使う。


tokenを保存する


終了時間と開始時間から、時間の計算をする



リストビューで独自レイアウトを設定する


USBデバッグ

リリースビルド

最終更新:2017年05月07日 22:50