Android アプリ開発「MATRIX」

Androidアプリの開発に役立つサンプル集


ブロードキャストレシーバーの基本的な使い方(その1)

ブロードキャストレシーバーの使い方(その1)

ブロードキャストレシーバーは端末が送信している様々なメッセージや情報を受信するクラスです。これを利用すると、時間やタイムゾーンの変化、バッテリーの残量や充電状態など、細かな端末の状態を知ることができます。また、自分で情報を発信してそれを受信することも可能です。

今回は自分で情報(インテント)を発信(ブロードキャスト)して、それをブロードキャストレシーバーで受信する方法の説明です。

サンプルコード①(MainActivity.java

詳しい説明はコード内のコメントで記述してあります。

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//レイアウトファイルをViewにセット
setContentView(R.layout.activity_main);

//レイアウトファイルのボタンに直にクリックイベントリスナーを設定
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

//ブロードキャストレシーバーに自作インテントを送信する
Intent intent1 = new Intent(); //空のインテントを生成
intent1.setAction("MY_INTENT"); //インテントのアクション名を設定
sendBroadcast(intent1); //インテントを送信
}
});
}
}

サンプルコード②(mBroadcastReceiver.java

詳しい説明はコード内のコメントで記述してあります。

public class mBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

//送信されたブロードキャストを受信してトーストで表示
Toast.makeText(context, "受信しました…", Toast.LENGTH_SHORT).show();
}
}

サンプルコード③(AndroidManifest.xml

マニフェストファイルにブロードキャストレシーバーを登録します。以下の <receiver> タグを追記してください。追記する場所は <activity> タグと同じ並びです。

<!-- ブロードキャストレシーバーと受け取るアクション名「MY_INTENT」を登録 -->
<receiver android:name=".mBroadcastReceiver">
<intent-filter>
<action android:name="MY_INTENT"></action>
</intent-filter>
</receiver>

サンプルコード④(activity_main.xml

画面構成は中央に以下のボタンを配置しただけの簡単なものです。

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

実行結果

① 起動すると画面の中央にボタンが表示されるのでそれをクリックして自作のインテントを発信(ブロードキャスト)します。

アンドロイド開発「ブロードキャストレシーバー」①

② 送信されたインテントをブロードキャストレシーバーが受信してトーストで「受信しました…」というメッセージを表示します。

アンドロイド開発「ブロードキャストレシーバー」②

備考・その他

ブロードキャストレシーバーの使い方は特に難しいものではありませんが、ついうっかりマニフェストファイルに登録するのを忘れて「あれ、動かないぞ・・・」となることがよくあるので、それには注意してください。次回は、自作のインテントではなく端末の状態などの情報をブロードキャストレシーバーで受信する方法を説明する予定です。

END

画面をタッチしたまま指を動かす「ムーブイベント」を検出する方法

「ムーブイベント」を検出する

スマートフォンタブレットの画面をタッチしたまま指を動かす「ムーブイベント」を検出するには View クラスの「onTouchEvent」メソッドの中で「MotionEvent.ACTION_MOVE」アクションを取得します。

サンプルコード①(MainActivity.java

詳しい説明はコード内のコメントに記述してあります。 

public class MainActivity extends AppCompatActivity {

//アプリを動かすと必ず最初に実行される
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//オリジナルのView(画面)をセット
setContentView(new TouchView(this));
}

//オリジナルのView(画面)
public class TouchView extends View {

//XY座標用の変数を準備
private float x_zahyou;
private float y_zahyou;
private String mess;
private final static String def_mess = "ムーブしてください";

public TouchView(Context context) {
super(context);

//変数の初期化
x_zahyou = 0;
y_zahyou = 0;
mess = def_mess;
}

//描画するところ
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//文字の表示スタイルを設定
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(50);
paint.setStrokeWidth(30);

//画面に文字列などを表示する
canvas.drawText(mess,50,100, paint);
canvas.drawText("X座標:" + x_zahyou + " Y座標:" + y_zahyou,50,160, paint);
canvas.drawPoint(x_zahyou, y_zahyou, paint);
}

//画面(View)が操作されると呼び出される
@Override
public boolean onTouchEvent(MotionEvent event) {

//画面(View)が押されたかを判定
if(event.getAction() == MotionEvent.ACTION_MOVE) {

mess = "ムーブ中・・・"; //
x_zahyou = event.getX(); //X座標を変数にセット
y_zahyou = event.getY(); //Y座標を変数にセット

} else if(event.getAction() == MotionEvent.ACTION_UP) {

//メッセージを元に戻す
mess = def_mess;
}

//Viewの更新(onDrawの呼び出し)
invalidate();
return true;
}
}
}

サンプルコード②(activity_main.xml

今回は、オリジナルの「View」を作って表示しているので、レイアウトXMLファイル「activity_main.xml」は使用していません。

実行結果

アプリを起動すると「ムーブしてください」というメッセージと、現在マーカー「■」がある座標(X:0、Y:0)が表示されます。

アンドロイド開発「ムーブイベントを検出する」①

画面(スクリーン)内の適当なところをタッチしてそのまま指を移動すると、表示が「ムーブ中・・・」に変わり、X座標とY座標の値が連続で変わります。

アンドロイド開発「ムーブイベントを検出する」②

画面(スクリーン)から指を離すと、表示が「ムーブしてください」に戻ります。

アンドロイド開発「ムーブイベントを検出する」③

備考・その他

アプリだけでなくゲームなどにも活用できるのでムーブイベントを検出する方法を知っておくととても便利ですね。

END

画面がタッチされた時にX座標とY座標を取得する方法

画面がタッチされた時にX座標とY座標を取得する

スマートフォンタブレットの画面がタッチされた時にX座標とY座標を取得するには「View」クラスの「onTouchEvent」メソッドを使用します。

サンプルコード①(MainActivity.java

詳しい説明はコード内のコメントに記述してあります。 

public class MainActivity extends AppCompatActivity {

//アプリを動かすと必ず最初に実行される
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//オリジナルのViewをセット
setContentView(new TouchView(this));
}

//オリジナルのView
public class TouchView extends View {

//XY座標用の変数を準備
private float x_zahyou;
private float y_zahyou;

public TouchView(Context context) {
super(context);

//XY座標の初期化
x_zahyou = 0;
y_zahyou = 0;
}

//描画するところ
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//文字の表示スタイルを設定
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(50);
paint.setStrokeWidth(30);

//画面に文字列などを表示する
canvas.drawText("タッチしてください",50,100, paint);
canvas.drawText("X座標:" + x_zahyou + " Y座標:" + y_zahyou,50,160, paint);
canvas.drawPoint(x_zahyou, y_zahyou, paint);
}

//画面(View)が操作されると呼び出される
@Override
public boolean onTouchEvent(MotionEvent event) {

//画面(View)が押されたのかを判定
if(event.getAction() == MotionEvent.ACTION_DOWN) {

x_zahyou = event.getX(); //X座標を変数にセット
y_zahyou = event.getY(); //Y座標を変数にセット
}

//画面の更新(onDrawの呼び出し)
invalidate();

return true;
}
}
}

サンプルコード②(activity_main.xml

今回は、オリジナルの「View」を作って表示しているので、レイアウトXMLファイル「activity_main.xml」は使用しません。

実行結果

起動すると「タッチしてください」というメッセージと、現在マーカーがある座標(X:0、Y:0)が表示されます。

アンドロイド開発「タッチ座標を取得する」①

スクリーン内の適当なところをタッチします。

アンドロイド開発「タッチ座標を取得する」②

タッチした位置にマーク「■」が表示され、XとY座標の位置が表示されます。

アンドロイド開発「タッチ座標を取得する」③

備考・その他

「onTouchEvent」の中でキャッチするイベントを「MotionEvent.ACTION_MOVE」にすると連続して座標を取得することが可能です。

END

 

押されたキーの「キーコード」を取得する方法

押されたキーの「キーコード」を取得する

スマートフォンタブレットの物理的な「キー」が押された時に、そのキーコードを取得するには「View」クラスの「onKeyDown」イベントを利用します。この「onKeyDown」イベントはソフトウェアキーボードのコードも取得できる場合がありますが、確実ではありませんのでおすすめすることはできません。

サンプルコード①(MainActivity.java

アプリの詳しい説明はコード内のコメントに記述してあります。 

public class MainActivity extends AppCompatActivity {

//オブジェクト・変数を準備
private TextView textView;
private String str;
private String default_message = "キーを押してください";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//オリジナルViewMyView)をセット
setContentView(new MyView(this));
//デフォルトメッセージをセット
str = default_message;
}

//オリジナルViewMyView
public class MyView extends View {

public MyView(Context context) {
super(context);

//このViewにフォーカスさせる
setFocusable(true);
setFocusableInTouchMode(true);
}

//キーが押された時に呼び出される
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

//キーコードの取得と表示する文字列の作成
str = "コード「" + String.valueOf(KeyCode) + "」のキーが押されました";
//表示の更新(onDrawの自動呼び出し)
invalidate();

return super.onKeyDown(keyCode, event);
}

//キーが離された時に呼び出される
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {

//デフォルトメッセージをセット
str = default_message;
//表示の更新(onDrawの自動呼出し)
invalidate();

return super.onKeyUp(keyCode, event);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//ペイントの生成とパラメーターのセット
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(50);
paint.setColor(Color.RED);
//テキストを画面に描画
canvas.drawText(str,20,100,paint);
}
}
}

サンプルコード②(activity_main.xml

レイアウトは、画面の中央にスピードを表示するテキストビューがあるだけのシンプルな構造です。 

<TextView
android:id="@+id/keyevent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

実行結果

実行するとアプリは入力待ち状態になります。

f:id:vw-dsg:20181229001113j:plain

ボリュームキー(アップ、またはダウン)を押すと、押されたキーのキーコードが表示されました。

アンドロイド開発「キーコードを取得する」2

押したボリュームキーを離すとまた入力待ちの状態に戻ります。

f:id:vw-dsg:20181229001113j:plain

備考・その他

。 

END

Google Play Instant Development SDK(1.6.0)のアップデートがエラーで失敗する場合の対処方法

Google Play Instant Development SDK のアップデートエラー

Android StudioSDKマネージャーで「Google Play Instant Development SDK」のリビジョンを「1.5.0」→「1.6.0」にアップデートしようとすると、原因不明のエラーが発生してアップデートできない場合がありますが、確認したところ、このトラブルは前回の「1.4.0」→「1.5.0」にアップデートしようとした時のエラーと同じ方法で対処できることが分かりましたので、お困りの方は下記の対処方法を参考にしてください。

Google Play Instant Development SDK(revision 1.5.0)のアップデートがエラーで失敗する場合の対処方法

アップデートのエラー画面

Android Studio エラーメッセージ

備考・その他

次回「1.7.0」へのアップデートでも同じようなエラーが発生するかもしれませんので、その場合は再度この対処方法を試してみてください。

END

音楽を再生するアプリを作ってみよう ~ メディアプレイヤーの基本的な使い方 ~

音楽を再生するアプリの作り方

今回はメディアプレイヤーを使って音楽を再生するアプリを作ってみます。音楽を再生するアプリと聞くといろいろと難しいのでは・・・と考えてしまいがちですが、一つの曲を単純に再生するだけならとくに難しい技術は必要ありません。

下準備(プロジェクトに音楽ファイルを追加する)

プログラムを作成するまえにプロジェクトの「res」フォルダ内に「raw」フォルダを新規に追加作成して、その中に再生したい音楽ファイル(mp3,wav,mpeg4,ogg形式など)を追加します。

手順①

「res」フォルダを右クリックして「New」→「Android Resource Directory」を選択します。

f:id:vw-dsg:20181031192054p:plain

手順②

「New Resource Directory」という画面が表示されたら「Resource Type」を「raw」に変更し「OK」ボタンを押します。すると「res」フォルダの中に「raw」フォルダが作成されます。

f:id:vw-dsg:20181031192254p:plain

手順③

好きな音楽ファイル上で右クリック。表示されたメニューから「コピー」を選択しクリップボードにコピーします。

f:id:vw-dsg:20181031192608p:plain

手順④

「raw」フォルダ上で右クリックして表示されたメニューから「Paste」を選択。クリップボードにコピーしておいた音楽ファイルをペーストします。

f:id:vw-dsg:20181031191906p:plain

手順⑤

「raw」フォルダ内に音楽ファイルが追加されました。これでアプリから利用できるようになります。

f:id:vw-dsg:20181031190410p:plain

サンプルコード① MainActivity.java

プログラムは「メイン処理」「音楽を再生する処理」「音楽を停止する処理」の3つに分かれていますが、処理内容はとてもシンプルです。なお、詳しい内容についてはコード中のコメントを参照してください。 

public class MainActivity extends AppCompatActivity {

private MediaPlayer mediaPlayer1; //メディアプレイヤー用オブジェクト
private Button button_play; //プレイボタン用オブジェクト

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//レイアウトファイル(activity_main.xml)をビューにセット
setContentView(R.layout.activity_main);

//レイアウトファイル中のボタンを取得する
button_play = (Button)findViewById(R.id.play_button);

//上で取得したボタンにクリックイベントの監視を設定
button_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

//メディアプレイヤーが未生成、または、メディアプレイヤーが未再生だったら
if(mediaPlayer1 == null || !mediaPlayer1.isPlaying()) {
//音楽を再生する処理を実行
music_start();
} else { //メディアプレイヤーが再生中だったら
//音楽を停止する処理を実行
music_stop();
}
}
});
}

//アプリがユーザーから見えなくなった時
@Override
protected void onStop() {
super.onStop();

//音楽を停止する処理を実行
music_stop();
}

//音楽の再生する処理
private void music_start() {

//メディアプレイヤーを生成
mediaPlayer1 = MediaPlayer.create(getBaseContext(), R.raw.music);
//曲の先頭から再生するように設定
mediaPlayer1.seekTo(0);
//再生開始
mediaPlayer1.start();
//ボタンの表示を「STOP」に変更
button_play.setText("STOP");
}

//音楽を停止する処理
private void music_stop() {

//メディアプレイヤーが生成されていない場合は何もせずメソッドを抜ける
if(mediaPlayer1 == null) return;
//音楽の再生をストップ
mediaPlayer1.stop();
//メディアプレイヤーを解放
mediaPlayer1.release();
//メディアプレイヤーにNULLをセット
mediaPlayer1 = null;
//ボタンの表示を「PLAY」に変更
button_play.setText("PLAY");
}
}

サンプルコード② activity_main.xml

画面に「PLAY」と「STOP」が切り替わるボタンがひとつ配置されているだけの単純な構成です。

<Button
android:id="@+id/play_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PLAY" />

結果画面

起動すると「PLAY」と書かれたボタンが表示されます。

f:id:vw-dsg:20181031185326j:plain

「PLAY」ボタンを押すとあらかじめセットしておいた音楽が再生され、ボタンのラベル表示が「STOP」に変わります。

f:id:vw-dsg:20181031185339j:plain

「STOP」ボタンを押すと音楽の再生が停止して、ボタンのラベル表示が再び「PLAY」に変わります。

f:id:vw-dsg:20181031185326j:plain

備考・その他

今回はひとつの音楽ファイルを再生するだけのアプリでしたが、音楽ファイルを複数読み込んで次から次へと連続で再生するようにできれば「音楽プレイヤー」のようなアプリが作れると思いますので、ぜひチャレンジしてみてください。

END

Google Play Instant Development SDK(revision 1.5.0)のアップデートがエラーで失敗する場合の対処方法

Google Play Instant Development SDK のアップデートエラー

Android Studio で Google Play Instant Development SDK のリビジョンを「1.4.0」から「1.5.0」にアップデートしようとするとエラーが発生してアップデートできない場合があります。

f:id:vw-dsg:20181025224057p:plain
Android Studio の右下に表示されるアップデート案内をクリックし、表示された選択画面で「Update Now」を選択する。

f:id:vw-dsg:20181025224133p:plain
アップデートが開始されダウンロードが始まる・・・しかし・・・

f:id:vw-dsg:20181025224112p:plain
原因不明のエラーが発生して「Google Play Instant Development SDK」のリビジョンアップが停止してしまう・・・。何度試しても失敗してしまうのでお手上げ状態に・・・

エラーの対処方法

海外の掲示板に「古いリビジョンのファイルが邪魔をしているので SDK のインストール先にある instantapps というフォルダを削除して再度アップデートすれば解決する…」とう書き込みがあったので、それを試してみたのですが何度トライしても結局ダメ・・・。

一時は途方に暮れてしまったのですが、しばらくしてから少し方法を変えてトライしてみたところ、なぜか無事にアップデートを完了することができました。

f:id:vw-dsg:20181025224341p:plain
① まず、SDK マネージャーを表示し「SDK Tools」タブをクリックして「Google Play Instant Development SDK」のチェックを外します。

f:id:vw-dsg:20181025224505p:plain
② 次に、SDK がインストールされているフォルダを開いて、その中にある「instantapps 」というフォルダを削除する。※削除してしまうと失敗した時に元に戻すのが面倒になるので「instantapps」を「instantapps_backup」などにリネームしても良いですね。

f:id:vw-dsg:20181025224133p:plain
Android Studio を再起動して再びアップデートを試みます。

f:id:vw-dsg:20181025224203p:plain
④ 今度は Google Play Instant Development SDK のリビジョン「1.5.0」のインストールが成功しました。

f:id:vw-dsg:20181025224247p:plain
⑤ 最後にSDKマネージャーを表示して「Google Play Instant Development SDK」にチェックを入れて完了です。

備考・その他

もしこの方法で失敗する場合は、⑤のSDKマネージャーの「Google Play Instant Development SDK」にチェックを入れるタイミングを少し変えてみてください。

END

サービスの基本的な使い方を知っておこう

基本的なサービスの使い方

今回は「サービス」の基本的な使い方です。「サービス」というのは長時間バックグラウンドで動きインターフェース画面を持たないアプリケーションです。基本的な作り方は意外に簡単で、サービスを継承したクラスを作った後、それを他から呼び出して実行させるだけです。

「サービス」を利用すれば画面を閉じても動き続ける必要がある「タイマー」アプリや「音楽プレイヤー」アプリなどが作れるようになりますね。

サンプルコード①(MainActivity.java

MainActivity クラスの中に「Service」を継承した「TestService」が入っていますが、コード増えると長くなってしまうので、その場合はそれぞれ別々のファイルに分けた方が良いですね。

public class MainActivity extends AppCompatActivity {

private Button button, button2;
private Intent intent;
private static TextView textView;

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

//サービス用のインテントを生成
intent = new Intent(getBaseContext(), TestService.class);
//レイアウトから表示用のテキストビューを取得
textView = (TextView)findViewById(R.id.infom);

//レイアウトからボタンを取得してクリックイベントを設定
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startService(intent);
}
});

//レイアウトからボタン2を取得してクリックイベントを設定
button2 = (Button)findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
stopService(intent);
}
});
}

@Override
protected void onDestroy() {
super.onDestroy();
// アプリを終了したらサービス停止
stopService(intent);
}

//サービス本体
public static class TestService extends Service {

// サービスが作られると呼び出される
@Override
public void onCreate() {
super.onCreate();
}

// サービスが停止すると呼び出される
@Override
public void onDestroy() {
super.onDestroy();
// 画面に「サービス停止中」と表示
textView.setText("サービス停止中");
}

// バインドされると呼び出される(※内容がなくても省略不可能)
@Override
public IBinder onBind(Intent intent) {
// バインドしていないので内容はなし
return null;
}

// サービスが開始されると呼び出される
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 画面に「サービス実行中」と表示
textView.setText("サービス実行中");
// 強制終了したら再起動させる戻り値
return START_REDELIVER_INTENT;
}
}
}

サンプルコード②(AndroidManifest.xml

「サービス」を継承したクラスを作ったら必ずマニフェストファイルにその存在を登録する必要があります。※下の方にある赤文字の行を追加します。

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service android:name=".MainActivity$TestService" />
</application>

サンプルコード③(activity_main.xml

特に複雑なものではありません。サービスの状態を表示するテキストビューと、サービスの起動と停止をする2つのボタンがあるだけのシンプルな構造です。

<TextView
android:id="@+id/infom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="7dp"
android:text="サービス停止中"
android:textSize="30sp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="START"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="STOP"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />

実行結果

実行すると「サービス停止中」というテキスト表示と「START」と「STOP」というラベルのボタンが画面上に表示されます。

f:id:vw-dsg:20181019000238g:plain

「START」ボタンを押してサービスを起動すると「サービス停止中」という表示が「サービス実行中」という表示に変わります。

f:id:vw-dsg:20181019000303g:plain

開発者ツールで実行中のサービスを確認すると今回作った「Service Test」というアプリの名前が実行中のサービスリストの中にありました。

f:id:vw-dsg:20181019000319g:plain

「STOP」ボタンを押したりサンプルアプリを終了すると・・・実行中のサービス一覧からサンプルアプリ「Service Test」が削除されました。

f:id:vw-dsg:20181019000333g:plain

その他・備考

この方法の他にバインドしてサービスを動かす方法がありますが、少しだけ複雑になりますのでまた次の機会にサンプルを作って説明したいと思います。 

END

GPSを利用したスピードメーター(速度計)の作り方

GPSを利用したスピードメーター(速度計)

今回はGPSを利用したシンプルなスピードメーター(速度計)の作り方です。

Android Java には現在の速度を「m/s」単位で取得できる関数「getSpeed」があるので、GPSの位置情報からいちいち速度を計算する必要はありませんが、取得できる間隔が「1秒」と長いので、短時間で速度が変化するような場合の速度測定には向かないかもしれません。

サンプルコード①(MainActivity.java

詳しい説明はコード内のコメントを見てください。 

//メインアクティビティ(implementsGPSを監視できるようにしてある)
public class MainActivity extends AppCompatActivity implements LocationListener {

private LocationManager locationManager; //ロケーションマネージャー
private TextView textView; //速度表示用
private float speed = 0f; //速度用の変数

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//レイアウトファイルをセット
setContentView(R.layout.activity_main);
//アクションバーを隠す
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
//ロケーションマネージャーに端末のロケーションサービスを関連付ける
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//レイアウトファイルからテキストビューを取得する
textView = (TextView) findViewById(R.id.speed_text);
}

@Override
protected void onPause() {
super.onPause();
//ポーズ時にはGPS(位置情報)の取得を解除する
locationManager.removeUpdates(this);
}

@Override
protected void onResume() {
super.onResume();
//GPS(位置情報)の取得が許可があるのかをチェック
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

//GPSの使用が許可されていなければパーミッションを要求し、その後再度チェックが行われる
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);

return;
}
//ロケーションマネージャーにGPS(位置情報)のリクエストを開始する
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}

@Override
public void onLocationChanged(Location location) {
  //
速度が出ている?
if(location.hasSpeed()) {
//速度が出ている時(km/hに変換して変数speedへ
speed = location.getSpeed() * 3.6f;
} else {
//速度が出ていない時
speed = 0;
}
//速度を表示する
textView.setText(speed + " km/h");
}

@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
//必要に応じてプログラムを書く(省略はできない)
}

@Override
public void onProviderEnabled(String s) {
//必要に応じてプログラムを書く(省略はできない)
}

@Override
public void onProviderDisabled(String s) {
//必要に応じてプログラムを書く(省略はできない)
}
}

サンプルコード②(activity_main.xml

レイアウトは、画面の中央にスピードを表示するテキストビューがあるだけのシンプルな構造です。 

<TextView
android:id="@+id/speed_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0 km/h"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

実行結果

実行するとアプリが「位置情報(GPS)」使用の許可を要求してくる。

f:id:vw-dsg:20181008223619j:plain

「OK(ALLOW)」を選択するとすぐに速度の測定が開始されます。

f:id:vw-dsg:20181008223055j:plain

備考・その他

このサンプルアプリは、バックグラウンドに移動するとGPSを停止して速度の測定を一時中断する仕組みになっているので、バックグラウンドに残してあってもGPSで電力を消費することはありません。 

END

ブラウザを起動するボタンを作る方法

ブラウザを起動するボタンを作る

今回はボタンをクリックするとブラウザが起動して「Yahoo!」サイトを表示するサンプルを作ります。

動作の流れは、Uriに「Yahoo!」のアドレスをセットし、UriをセットしたIntent(ACTION_VIEW)を作成して、最後にそのIntentをstartActivityで開始します。

手続きが少々面倒ですが知っておいて損はありませんので、このサンプルで流れをしっかり覚えてしまいましょう。

サンプルコード①(MainActivity.java

詳しい説明はコード内のコメントを参考にしてください。

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//レイアウトファイルをセット
setContentView(R.layout.activity_main);
//アクションバーを取得
ActionBar actionBar = getActionBar();
//アクションバーを隠す
actionBar.hide();

//レイアウトファイルのボタンを取得
Button button = (Button)findViewById(R.id.button);
//取得したボタンにクリックイベントをセット
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//ブラウザで開きたいサイトをuriにセット
Uri uri = Uri.parse("http://yahoo.co.jp");
//uriを開くインテントを作成
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
//uriを開くアクティビティをスタートします
startActivity(intent);
}
});
}
}

サンプルコード②(activity_main.xml) 

レイアウトファイルは中央にボタンがあるだけの単純な構造です。

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yahoo!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

実行結果

中央のボタンをクリックすると…

f:id:vw-dsg:20181005211902p:plain

 

Yahoo!」のウェブサイトが表示されました。

f:id:vw-dsg:20181005211923p:plain

END 

エミュレーター(AVD)の動作がおかしくなった時の対処方法

エミュレーターの動作がおかしくなったら…

アプリの開発を続けているとフリーズや予期しないシャットダウンなどで時々エミュレーターの動作が悪くなってしまうことがありますが、Android Studioエミュレーター(AVD)は一度調子が悪くなると自然に復旧することはまずありませんので、以下の手順で初期化して復旧させてください。

f:id:vw-dsg:20181003180605g:plain

不調の一例…起動しても画面が真っ黒になったまま…

エミュレーターを初期化する手順

エミュレーターを初期化する手順は以下となりますが、マウスで選択するだけなので特に難しいものではありません。

Android Studio の上部メニューから「AVDマネージャー」を起動します。

f:id:vw-dsg:20181003180747g:plain

② 調子が悪い機種の右端にある「▼」ボタンを押してメニューを開きます。

f:id:vw-dsg:20181003180820g:plain

③ 表示されたメニューから「Wipe Data」を選択します。

f:id:vw-dsg:20181003180906g:plain

④ ダイアログが表示され「ユーザーファイルをワイプしますか?」と確認されるので「Yes」をクリックします。

f:id:vw-dsg:20181003181259g:plain

⑤ ユーザーファイルが消去されるとその機種の使用ディスクサイズが少なくなるので、「初期化」されたことがすぐにわかると思います。

f:id:vw-dsg:20181003181753g:plain

⑥ 再び調子が悪かった機種のエミュレーターを起動すると、今度は正常に起動しました。

f:id:vw-dsg:20181003182026g:plain

備考

ユーザーファイルのワイプを実行すると、過去のアプリ制作で溜まってしまった古いファイルを大量に消去することができ、HDDの空き容量も確保できるので定期的にワイプすることをおすすめします。

END

バッテリーの状態を簡単に取得する方法

バッテリーの状態を取得する

今回はスマートフォンのバッテリー状態を取得する方法の説明です。

バッテリーの状態はスティッキーインテントなのでブロードキャストレシーバーが無くても取得ができるようになっていますが、バッテリーの状態の変化を常に監視するにはブロードキャストレシーバーを使用してインテントを受信する必要があります。

サンプルコード①(MainActivity.java

バッテリー情報を得るには「ACTION_BATTERY_CAHNGED」というインテントのフィルターを生成してそのフィルターをレシーバーへ登録します。その後、インテントから各バッテリーの状態を取得しています。

バッテリーの状態は数値で送られてくるので、数値だけでは判別できない「バッテリーの健康状態」「接続状態」「充電状態」は変換用の関数を作って数値から文字列に変換してから表示しています。 

public class MainActivity extends AppCompatActivity {

//結果表示用の変数
private String battery_info;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//レイアウトファイルのセット
setContentView(R.layout.activity_main);
//アクションバーを非表示にする
ActionBar actionBar1 = getSupportActionBar();
actionBar1.hide();
//レイアウトファイルのテキストビューを取得
TextView textView1 = (TextView)findViewById(R.id.battery_info);
//インテントフィルターの生成とレシーバーへの登録
IntentFilter intentFilter1 = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent intent1 = getBaseContext().registerReceiver(
null, intentFilter1);

//初期化
battery_info = "";

//残量を取得
int level = intent1.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
battery_info += "残量" + level + "%" + "\n";
//接続状態
int plugged = intent1.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
battery_info += plug(plugged) + "\n";
//健康状態を取得
int health = intent1.getIntExtra(BatteryManager.EXTRA_HEALTH, -1);
battery_info += health(health) + "\n";
//ステータスを取得
int statas = intent1.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
battery_info += stat(statas) + "\n";
//温度を取得
int ondo = intent1.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1);
battery_info += ondo / 10 + "\n";
//電圧を取得
int voltage = intent1.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1);
battery_info += voltage / 1000 + "V\n";

//結果レポートの出力
textView1.setText(battery_info);
}

//バッテリーの健康状態を返す関数
private String health(int h) {

String return_health =
"";

switch (h) {
case BatteryManager.BATTERY_HEALTH_COLD:
return_health =
"低温…";
break;
case BatteryManager.BATTERY_HEALTH_DEAD:
return_health =
"故障…";
break;
case BatteryManager.BATTERY_HEALTH_GOOD:
return_health =
"良好";
break;
case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
return_health =
"電圧オーバー";
break;
case BatteryManager.BATTERY_HEALTH_OVERHEAT:
return_health =
"オーバーヒート";
break;
case BatteryManager.BATTERY_HEALTH_UNKNOWN:
return_health =
"状態不明";
break;
case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
return_health =
"未確認エラー";
break;
}
//バッテリーの健康状態を返す
return return_health;
}

//接続状態を返す関数
private String plug(int p) {

String return_plug =
"";

switch (p) {
case BatteryManager.BATTERY_PLUGGED_AC:
return_plug =
"AC接続";
break;
case BatteryManager.BATTERY_PLUGGED_USB:
return_plug =
"USB接続";
break;
case BatteryManager.BATTERY_PLUGGED_WIRELESS:
return_plug =
"ワイヤレス接続";
break;
default:
return_plug =
"未接続";
}
//接続状態を返す
return return_plug;
}

//充電状態を返す関数
private String stat(int s) {

String return_status =
"";

switch (s) {
case BatteryManager.BATTERY_STATUS_CHARGING:
return_status =
"充電中";
break;
case BatteryManager.BATTERY_STATUS_FULL:
return_status =
"充電完了";
break;
case BatteryManager.BATTERY_STATUS_DISCHARGING:
return_status =
"放電";
break;
case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
return_status =
"未充電";
break;
case BatteryManager.BATTERY_STATUS_UNKNOWN:
return_status =
"状態不明";
break;
}
//充電ステータスを返す
return return_status;
}
}

サンプルコード②(activity_main.xml

レイアウトは画面の中央にテキストビューがあるだけのシンプルな構造です。 

<TextView
android:id="@+id/battery_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Battery"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

実行結果

バッテリー残量、接続状態、健康状態、充電状態、温度、電圧の6項目の状態を取得して表示することができました。

f:id:vw-dsg:20181003082254p:plain

備考

バッテリー状態の取得に関するより詳しい説明については「Android Developers」を参照ください。

https://developer.android.com/training/monitoring-device-state/battery-monitoring?hl=ja

END

Android Studio 3.2 でビルドエラー「No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android」が出た時の対処方法

Android Studio 3.2 にアップデート後にビルドエラーが発生

アンドロイドスタジオ(Android Studio)をアップデートした後に、以前に作ったアプリをビルドしようとすると「No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-androidというエラーが発生してビルドが停止してしまうことがあります。

詳しい原因はわかりませんが、どうやら Android Studio 3.2 になってビルドに必要な何かが廃止されたことによって発生するエラーらしいので、面倒な手続きをする必要があるみたいですが、いろいろと試していたところ割と簡単にエラーを排除できる方法をみつけましたので手順を説明したいと思います。

f:id:vw-dsg:20180930182427g:plain

エラーが発生するパターンと対処方法

Android Studio のバージョンを「3.2」にアップデートしてから、以前作ったアプリ(プロジェクト)を開こうとすると、「Gradle のプラグインをアップデートしますか?」と聞かれるので「Update」を選択してアップデートします。

f:id:vw-dsg:20180930183037g:plain

② 上で「Update」を選択するとビルドが開始されるのですが、Android Studio 3.2 より前の Android Studio で作成したアプリはほぼ確実に「No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android」というエラーメッセージが表示されてビルドが停止してしまいます。

f:id:vw-dsg:20180930183048g:plain

③ エラーが出たら慌てずに「File」→「Project Structure」画面を開きます。

f:id:vw-dsg:20180930183428g:plain

④ Project Structure 画面を開いたら左のメニューから「Project」を選択して「Android Plugin Version」を確認しますが、おそらくここが「3.2.0」以外になっているはずです。

f:id:vw-dsg:20180930183711g:plain

⑤ この「Android Plugin Version」の値を「3.2.0」に変更して「OK」ボタンを押します。

f:id:vw-dsg:20180930183939g:plain

⑥ 「OK」ボタンを押すと再度ビルドが始まるのでしばらく待っていると、今度は「Minimum supported Gradle version is 4.6. Current version is 3.3.」と「Please fix the project's Gradle settings.」というエラーメッセージが表示されるので、その下にある青字のリンク文字列(「Fix Gradle wrapper and re-import project」)をクリックします。

f:id:vw-dsg:20180930184110g:plain

⑦ 青字のリンク文字列をクリックすると再度ビルドが実行されるので、しばらく待つと正常にビルドが終わりようやく実行可能な状態になります。

f:id:vw-dsg:20180930184756g:plain

⑧ アプリによっては以下のようなメッセージが何行も表示される場合がありますが、このメッセージは「compile 設定は2018年末で廃止されますよ」という注意で、アプリ自体の実行は可能になっているのでとりあえず気にしないでください。

f:id:vw-dsg:20180930185246g:plain

備考・その他 

今回のアップデートで「Android Studio」のどこが変更されたのかはまだ詳しく調べていませんが、ひと通り動かしてみたところエミュレーターの起動が以前に比べてだいぶ早くなったような感じがします。これまでは起動してからしばらく待たされていましたのでうれしい改善ですね。 

タイマーを使って1秒間隔でシステム時間を取得する方法

1秒間隔でシステム時間を取得

「Timer」関数を使うと一定の間隔で処理を繰り返し実行させることができるので便利です。しかし、毎回僅かな遅延(1000分の数秒ほど)が発生しているので注意が必要です。それは、繰り返しの回数が増えれば増えるほど誤差が大きくなるからです。

サンプルコード①(MainActivity.java

タイマーを使い1秒間隔でカウントをアップし、それと同時にシステム時間を取得してログに出力しています。 

    private double systemtime1;             // システム時間
private DecimalFormat decimalFormat1; // フォーマット用
private TextView textView1; // テキストビュー
private Handler handler1; // ハンドラー
private Timer timer1; // タイマー
private int count1; // カウント用

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

//テキストビューを取得
textView1 = (TextView)findViewById(R.id.textview1);
//タイマーを新規生成
timer1 = new Timer();
//ハンドラーを新規生成
handler1 = new Handler();
//フォーマットを新規生成
decimalFormat1 = new DecimalFormat("0.000");
//カウンターを初期化
count1 = 0;

//タイマーに直接スケジュール(1秒後に1秒間隔の処理を開始)を追加して実行
timer1.schedule(new TimerTask() {
@Override
public void run() {
//システム時間を取得
systemtime1 = System.currentTimeMillis();
//"0.000"形式に成型してログに出力
Log.d("Sytem Time = ", decimalFormat1.format(systemtime1 / 1000) + "");
//直接だとエラーになるのでハンドラーを経由して画面表示を変更する
handler1.post(new Runnable() {
@Override
public void run() {
//レイアウトのテキストビューにカウント値を表示
textView1.setText(count1 + "");
}
});
//カウントアップ
count1 += 1;
}
}, 1000, 1000);
}

サンプルコード②(activity_main.xml

画面の中央にカウントを表示するテキストビューを配置したシンプルなレイアウトです。 

<TextView
android:id="@+id/textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Timer"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

実行結果①(ログ出力)

右端の数値が増えているので、毎回(1秒間隔)のように 1000分の数秒の遅れが発生しているというのがわかる。

f:id:vw-dsg:20180927192609p:plain

実行結果②(画面)

画面の中央の数値が1秒間隔でカウントアップするだけの構成。

f:id:vw-dsg:20180927192501p:plain

その他・備考

単純にカウントをアップして1/1000秒単位のストップウォッチを作ろうとタイマー処理の間隔を「1ms」に設定しても、毎回のように1000分の数秒の遅延が加算されているので1000回のカウントが1秒(1000ms)ということにはなりません。

簡単に一定の間隔で処理を実行できるタイマー機能ですが、毎回僅かな遅延が発生しているということを考慮して処理を考えなければなりませんね。 

END

GPSの使用権限「パーミッション」を取得する方法(Android 6.0~)

GPSの使用権限「パーミッション」を取得する方法

今回は、GPS(位置情報)の使用権限「パーミッション」を取得する方法の説明です。 

以前は「インストール時」に使用権限を取得していましたが、Android 6.0(APIレベル23)からは「アプリを実行してから」必要な使用権限を取得することになっています。

① サンプルコード(MainActivity.java

このサンプルでは、まず、アプリの起動時にGPSパーミッションをチェックして使用権限の有り無しを表示しています。

その後、「GPS情報を取得する」ボタンを押した時に、GPS情報の取得権限が無い場合は取得権限の許可を求めるダイアログが表示され、既にGPS情報の取得権限が有る場合は取得権限の許可を求めるダイアログが表示されることなくGPS情報の取得が開始される仕組みになっています。 

public class MainActivity extends AppCompatActivity implements View.OnClickListener, LocationListener {

private static LocationManager mLocationManager; //ロケーションマネージャー
private static Criteria mCriteria; //精度
private static String mProvider; //プロバイダー文字列
private static Button mButton; //ボタン
private static TextView mTextView; //テキスト表示

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//レイアウトファイルをセットする
setContentView(R.layout.activity_main);

//TextView取得
mTextView = (TextView)findViewById(R.id.textView);

//ボタン生成
mButton = (Button)findViewById(R.id.button);
//ボタンにクリックイベントを設定
mButton.setOnClickListener(this);

//GPSの精度を設定
mCriteria = new Criteria();
mCriteria.setAccuracy(Criteria.ACCURACY_FINE);
mCriteria.setPowerRequirement(Criteria.POWER_HIGH);

//ロケーションマネージャー取得
mLocationManager = (LocationManager)getSystemService(LOCATION_SERVICE);

p_check();
}

@Override
public void onClick(View v) {

switch (v.getId()) {

case R.id.button:
//ボタンが押されたら緯度経度の取得処理へ
gps_get();
break;
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);

switch (requestCode) {
case 1:

if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

//パーミッションチェック
p_check();
}

break;
}
}

//GPSパーミッションをチェックする
public void p_check() {

//GPSの使用が許可されているかをチェック
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

//テキスト表示変更
mTextView.setText("GPSの使用は許可されていません…");

} else {

mTextView.setText("GPSの使用は許可されています");
}
}

//GPSをゲットする
public void gps_get() {

//GPSの使用が許可されているかをチェック
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

//GPSの仕様が許可されていなければパーミッションを要求
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);

return;

} else {

mTextView.setText("GPS取得中・・・");
}

//プロバイダー生成
mProvider = mLocationManager.getBestProvider(mCriteria, true);
//GPS取得開始
mLocationManager.requestLocationUpdates(mProvider, 0, 0, this);
}

@Override
public void onLocationChanged(Location location) {
//位置情報が取得されると呼び出される(必要に応じて記述)
mTextView.setText("GSPを取得しました");
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
//必要に応じて記述
}

@Override
public void onProviderEnabled(String provider) {
//必要に応じて記述
}

@Override
public void onProviderDisabled(String provider) {
//必要に応じて記述
}
}

② サンプルコード(AndroidManifest.xml

GPS情報を取得するためにはマニフェストファイルに以下の記述が必要です。

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

③ サンプルコード(activity_main.xml

テキストビューとボタンだけの構成です。特筆すべきところはありません。

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="パーミッション情報"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="GPS情報を取得する"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

④ 結果

インストール直後はGPSの使用権限がありませんので、「GPSの使用は許可されていません…」と表示されます。

f:id:vw-dsg:20180915230537j:plain

そのまま「GPS情報を取得する」ボタンを押して位置情報を取得しようとすると、確認ダイアログが表示され「アプリに位置情報へのアクセスを許可しますか?」と聞かれます。

f:id:vw-dsg:20180915230751j:plain

確認ダイアログの「ALLOW(許可)」を選択すると、アプリに位置情報へのアクセスが許可され中央のメッセージが「GPSの使用は許可されています」に変わり、この時点で位置情報へのアクセスが可能になります。

f:id:vw-dsg:20180915231031j:plain

再度「GPS情報を取得する」ボタンを押すと、ダイアログが表示されることなく位置情報へのアクセスが開始され情報が取得されます。

f:id:vw-dsg:20180915231327j:plain

※今回のサンプルでは具体的な位置情報(緯度経度など)は取得していません。

⑤ 備考・その他

Android 6.0 からは使用権限(パーミッション)を機能ごとに許可できるようになったので、「カメラとマイクは許可するけど、位置情報は許可しない・・・」というような柔軟なアプリの使い方が可能になりますね。

終わり