vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

【Android】和歌山トイレマップで遊んでみる 3(環境構築・BroadcastReceiver)

はじめに

前回の続きです。

今回はまずPCを新しく買って、環境構築しようとしたらつまづいたのでその対処法と、コンテンツ使用時にインターネットに接続されているかを確認する処理を扱います。
あと、前回はKotlinを使っていましたが、一旦JAVAに戻しました。

Kotlinが良い・悪いの前に私のAndroid力が低すぎて、ただでさえ期待通り動くかわからないコードがKotlinへの変換でよりわからなくなる、というツラみが感じられたためです。
なのでしばらく経ったらまた懲りずに手を出してみようかなとは思っています。

環境構築

ということで新しいPC買いました。Bluetooth4.0やUSB3.0も搭載しているので、Windows環境でも色々試していきたいところです。

…は良いのですが、環境構築でところどころつまづいたので(2015/12/20時点での)対処法をメモっておきます。

インストール

とりあえずこの辺りをインストールします。

Android Studioのフォント設定

購入したPCが、13.3インチで解像度2560×1440ということで、フォントの種類はともかく文字が非常に小さくて見づらいという問題が発生。

フォントの設定はFile > Settings > Editor > Colors & Fonts > Font で行うことができます。
が、何故か画面下部のAndroid Monitorなどに反映されず。

ここには反映されないのかな~とTwitterでぼんやりつぶやいてみたところ、神のお告げ(メンション)が。

File > Settings > Editor > Colors & Fonts > Console Font からConsoleに対するフォントの設定ができるようです。

ありがたや( ̄人 ̄)

AndroidのUSBドライバのインストール

Windows環境の場合、ただAndroid端末を接続するだけではDebugボタンを押しても実機でアプリを動作させることができないため、 USBドライバをインストールする必要があります。

  1. Android SDK Manager > Extras > Google USB Driverをインストールします
  2. PCにAndroid端末を接続します
  3. デバイスマネージャーでStep2の端末を探して、「ドライバーソフトウェアの更新」をクリックします
  4. 「コンピューターを参照してドライバーソフトウェアを検索します」をクリックし、 C:\Users\ユーザー名\AppData\Local\Android\sdk\extras\google\usb_driver を選択します

フィンガープリント

keytool

Google Map APIのキーは、PC(フィンガープリント)に紐付いているため、開発するPCを変更した場合はAPIキーも変更が必要になるようです。

フィンガープリントを確認するコマンドは以下(C:\Users\ユーザー名 で実行した場合)ですが、環境変数を設定していないとkeytoolが見つからないと怒られたりします。

keytool -v -list -keystore .android/debug.keystore

このkeytoolはjdkの中にあるので、「C:\Program Files\Java\jdk1.8.0_66\bin\keytool ~」とパスを指定することでも実行可能になります。

debug.keystoreが無い場合

インストールしたAndroidStudioのバージョンによるかもしれませんが、C:\Users\ユーザー名.android に「debug.keystore」が自動で作成されない場合があります。
この場合は手動で作成してやる必要があります。

keytool -genkey -v -keystore ~/.android/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"

なおパスワードは「android」です。

ネットワーク接続を確認する

さて、ここからはプログラミングの話です。

このアプリではCSVから住所を取得して、そこから緯度・経度を取得します。
この緯度・経度を取得するためにはネットワーク(モバイル回線 or Wifi)への接続が必要となります。

というわけで、まずAndroid端末がネットワークに接続しているかを確認します。

public boolean checkIsNetworkConnected(){
    NetworkInfo networkInfo = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE)
            .getActiveNetworkInfo();
    if(networkInfo != null && networkInfo.isConnected())
    {
        return true;
    }
    // ネットワークにつながっていなければToast表示.
    Toast.makeText(this, "ネットワークにつながっていません", Toast.LENGTH_SHORT).show();
    return false;
}

ネットワーク接続の監視

起動時にネットワークに接続されているかが分からないということを考えれば、CSVからデータを取得するのは最初にネットワークに接続された時点、とした方が良さそうです。
そのため、BroadcastReceiverを使ってネットワークに接続されたかを監視することにします。

1. BroadcastReceiverを継承したクラスの作成

BroadcastReceiverからの通知を受け取るためのクラスを作成します。
また、ネットワーク接続状況の変化は、onReceive(Context context, Intent intent)で受け取ることができます。

NetworkAccesser.java

package jp.searchwakayamatoilet;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkInfo;
import android.util.Log;

public class NetworkAccesser extends BroadcastReceiver {
~省略~
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("NWA", "ネットワーク接続状況が変化しました");
    }
}

2. AndroidManifest.xmlへの登録

AndroidManifest.xmlに以下を追加することで、ネットワーク接続状況が変化すれば通知されるようになります。 なお、「android:name」はStep1のBroadcastReceiverを継承したクラス名です。

< receiver android:name=".NetworkAccesser" >
    < intent-filter >
        < action android:name="android.net.conn.CONNECTIVITY_CHANGE" / >
    < /intent-filter >
< /receiver >

通知を止める(失敗)

このアプリでは、バックグラウンドやアプリをストップした状態では動作させないため、そのような状態ではBroadcastReceiverの通知を止めます。

MainActivity.java

~省略~
private NetworkAccesser mNetworkAccesser;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    mNetworkAccesser = new NetworkAccesser();
    ~省略~
}
~省略~
public void onPause(Activity activeActivity){
    // ネットワーク状態の監視をストップ.
    activeActivity.unregisterReceiver(mNetworkAccesser);
}
public void onResume(Activity activeActivity) {
    // ネットワーク状態の監視を再開.
    activeActivity.registerReceiver(mNetworkAccesser, new IntentFilter(
            "android.net.conn.CONNECTIVITY_CHANGE"));
}
~省略~

問題

上記のコードで通知はストップするはずだったのですが、実際にはバックグラウンドにしても、タスク一覧からアプリを閉じても通知は止まりませんでした。

通知を止める(原因)

AndroidManifest.xmlへの登録時、以下のように記述していたのが原因でした。

AndroidManifest.xml

< activity
    android:name=".MainActivity"
    android:label="@string/app_name" >
    < intent-filter >
        < action android:name="android.intent.action.MAIN" / >

        < category android:name="android.intent.category.LAUNCHER" / >
    < /intent-filter >
< /activity >
< receiver android:name=".NetworkAccesser" >
    < intent-filter >
        < action android:name="android.net.conn.CONNECTIVITY_CHANGE" / >
    < /intent-filter >
< /receiver >

Activityの中にReceiverがないため、unregisterReceiverが動作しない、ということのようです。

以下のようにすることで、正しく通知がストップするようになりました。

AndroidManifest.xml

< activity
    android:name=".MainActivity"
    android:label="@string/app_name" >
    < intent-filter >
        < action android:name="android.intent.action.MAIN" / >

        < category android:name="android.intent.category.LAUNCHER" / >
    < /intent-filter >
    < receiver android:name=".NetworkAccesser" >
        < intent-filter >
            < action android:name="android.net.conn.CONNECTIVITY_CHANGE" / >
        < /intent-filter >
    < /receiver >
< /activity >

次はLocationについて、のハズです。

参考

Google USB Driver

keytool

ネットワーク