ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »Android
カテゴリー「Android」の記事一覧

【AndroidStudio】AndroidStudio 2.x で DDMS を表示する  


 なんてことないことだけど、まぁ Android のネイティブは ADT(Eclipse)~ AndroidStudio 1.x の初期頃よくいじっていて、最近は触ってもいなかったわけですよ。で、久しぶりに最新版を触ると「DDMSどこやねん!」ってなったので(笑)、とりあえずメモ。VisualStudio なんかもそうだけど、ツールバーのデフォとかショートカットも変わっていくのは困るね。EclispeのショートカットをAndroidStudioに移行することもできるみたいだけど、結局はバージョンアップするたびに変わっていく可能性あるので、最近は常に最新のやり方に慣れる方法でやってる。インターネットのおかげでググれば大抵のことは出てくるしね。ただ英文も多いので日本語で簡単にまとめておくとイザというとき便利かと(笑)。

(※) Android Studio 2.3.3 / Windows10(x64) で確認



 AndroidStudio 2.x で DDMS を表示するには、大まかに以下のような流れになる。

1.ツールバーに「Android Device Monitor」を表示させる。

2.「Android Device Monitor」を起動して、「DDMS」のアイコンを押す。



 具体的には以下のようにする。

1.メニューから「File>Settings...」を開く。

2.左側の項目から「Appearance & Behavior>Menus and Toolbars」をクリックする(展開して選択)。

3.内容が表示されたら、「Main Toolbar>Android.Main.ToolBarActionGroup」(展開して探す)を選択し、ダイアログの右側にある「Add After...」を押す(※選択した位置の後ろにアイコンが追加される。「Add Separator」で縦線(区切り線)を入れることもできる。「Move Up/Down」で移動も可。位置は任意で良い)。


4.「Choose Actions To Add」のダイアログが開くので、「All Actions>Main menu>Tools>Android>Android Device Monitor」を選択し、「OK」を押す。


5.「Settings」のダイアログに戻ったら、下にある「OK」ボタンを押して適用する。


 これでツールバーに「Android Device Monitor」のアイコンが表示される。

 あとは「Android Device Monitor」を起動し、右上にある「DDMS」を押す。


 端末のファイルなどを見たい場合は、左ペインの「Device」で端末をクリックし、右ペインで「File Explorer」のタブを押せば、ファイルやディレクトリ構成が表示される。またファイルを選択し(アプリのデータなどは「data/data/[アプリのパッケージ名]/」以下に入っている)、「Pull」アイコンを押せばローカル(開発環境:PCなど)に落として中身を覗くこともできる。

(参考)
No shortcut for DDMS in Android Studio 2.2


(関連記事)
【Android】【Java】Preference 機能を使って設定データを読み込み・保存する
【Android】エミュレータでSDカードをマウントして使う方法 その2


スポンサーサイト

category: Android

thread: プログラミング

janre: コンピュータ

tag: AndroidStudio 
tb: 0   cm: --

【Android】【Java】音声入力(音声認識)で文字列を取得する  


 いずれネイティブプラグイン作ったりするときのための布石。最近はVRでも音声入力できるものあるので Cardboard などでもできたら面白いかもね(Cardboard の場合、ハンディマイクでも付けない限り、構造的な問題が大きいが…)。とりあえずいつものように一番簡単にしたコードを書いておく。簡略のため細かいチェックなどは入れてないが、実際のアプリに使う場合は、色々と手を加えた方が良いだろう。


(※) Android Studio 2.3.3 / Windows10(x64) / Galaxy S7 Edge (Android 7.0) で確認

●簡単な構成

 例えばオブジェクト(ウィジェット)の構成が以下のようになっているものとする。配置などは任意で構わないが、とりあえず音声入力を開始するボタンと入力されたテキストを表示できるものがあれば良い。ここではそれぞれ ButtonTextView を使っている。


 仕様としては、「音声入力」のボタンを押したとき、音声入力のウィジェットが表示され入力開始→入力終了したらテキストビューに認識された文字列が列挙されるといった具合だ。その実装クラスを MainActivity とすると、コードは以下のようになる(テンプレートとしては「Empty Activity」を使っている)。

●音声入力された文字列を表示する
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.util.List;

public class MainActivity extends AppCompatActivity {

private TextView textDisplay;

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

textDisplay = (TextView)findViewById(R.id.text_display);
}

public void onClick(View v) {
//音声入力がサポートされているか?
if (getPackageManager().queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0).size() == 0) {
Log.d("tag", "Voice Input is not supported.");
return; //サポートされてないとき無視
}

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
startActivityForResult(intent, 0); //0:requestCode
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
if (data.hasExtra(RecognizerIntent.EXTRA_RESULTS)) {
//ここで認識された文字列を取得
List<String> results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if (results.size() > 0) {
String str = "";
for (String s : results) {
str += s + "\n";
}
textDisplay.setText(str);
}
}
}
}
}

 ここではコードを減らすため、ボタンのクリック動作をレイアウトの「activity_main.xml」で「Button」の属性に「android:onClick="onClick"」を追加しているので注意。自分で実装するなら「View.OnClickListener」を implements し、ボタンに setOnClickListener() を付ける必要がある。

 また本来 onClick の引数の Viewid を調べて音声入力のボタンかどうかをチェックする必要もあるが、ここでは1つしかボタンがないので省略している。また、システムが音声入力をサポートしているかどうかもここで判別しているが、OnCreate() で判別して使用できなかったら、ボタンを無効にするのも良いだろう。

 ボタンを押下したときの動作は、音声入力の Intent を生成し startActivityForResult() でシステムに処理を委ねているだけである。音声が認識されたら、onActivityResult() で受信し、TextView に表示することになる。ここでの注意点は onActivityResult() は他の Intent のやり取りも含まれるので、予め音声入力用の requestCode を合わせておくことと、認識されたデータ(文字列)があるか否かというくらいだ。ここではデータがないときは単に無視している。

 この例では認識された文字列を拡張for文(foreach)で結合して TextView に表示しているだけだが、ここで各々の文字列によって処理を分岐すれば、音声認識でアクションを起こせるアプリが作れる。

(実装例)
ユニティちゃんと音声認識でじゃんけん(Android 版)

(音声認識 参考)



(関連記事)
【Unity】Androidで音声認識を使う
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】Androidのテキスト読み上げ(TextToSpeech)を使う


category: Android

thread: プログラミング

janre: コンピュータ

tag: 音声認識 
tb: 0   cm: --

【Android】【Java】エラーをSDカードに書き出す  


 エミュレータではエラーが出ない(もしくは操作などの関係でテストしにくいなど)のに、実機ではエラーが出るときってあるよね。だけど「エラー:〇〇が予期せず停止しました。」だけだとデバッグするのが難しいので、例外のスタックトレースをそのままSDカードに保存する方法をやってみよう。あくまでも開発者用で特別な機能は何も付いてないので、その辺は自分で自由に付け足して使って欲しい。

●例外(エラー)のスタックトレースをSDカードに書き出すクラス
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import android.os.Environment;

/**<h1>エラーを SDカードに書き出す</h1>
* <p>マニフェストファイルに WRITE_EXTERNAL_STORAGE の属性と、SDカードをあらかじめマウントしておくことが必要。</p>
*/
public class ErrorReporter implements UncaughtExceptionHandler {

//マニフェストファイルに
//<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
//が必要

//※SDカードのルートに保存される。ルートは実機によって「/sdcard」や「/mnt/sdcard」など異なる。
static final File errorReportFile = new File(Environment.getExternalStorageDirectory().getPath()
+ File.separator + "error_report.txt"); //※ファイル名は任意

//コンストラクタ
public ErrorReporter() {
}

//catch されなかった例外を受け取るハンドラ
@Override
public void uncaughtException(Thread thread, Throwable ex) {
PrintWriter pw = null;
try {
//※ここでエラーにならないように注意(要 SD カード[マウント])
pw = new PrintWriter(new FileOutputStream(errorReportFile));
ex.printStackTrace(pw);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
pw.close();
} catch (Exception e2) {
}
pw = null;
}
}
}

 使い方は以下に示す使用例のように Activity のコンストラクタ(または onCreate()) などでハンドラとしてインスタンス化すれば良いだけだ。ボタンなどはテスト用なので任意で良い。終了処理などは何も付けてないので、実際にエラーが発生したときはフリーズしたようになる。なので、アプリは手動で終了して欲しい。

 try~catch~finally ブロックは少し冗長に感じるが、try-with-resources 文は API 19(Android4.4)以降しか使えないようなので、この方が無難だろう。使用中はSDカードが実機に入っていることを前提としている。普通にSDカードが読み書きできている分にはここで例外が発生することは無いハズだ。もちろん、マニフェストファイルに「SDカードへ書き込み許可」を書いておくことも必要となる。例外捕捉中に例外を発生させないよう気をつけよう(笑)。

●SD カードの書き込みを許可するタグ(<manifest>~</manifest>の間が良い)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


●使用例(ボタンを押すとエラーが発生するテスト用)
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

int[] data = new int[3]; //エラーテスト用

public MainActivity() {
//catch されなかった例外を受け取るハンドラを設定
Thread.setDefaultUncaughtExceptionHandler(new ErrorReporter()); //onCreate() でも良い
}

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

setContentView(R.layout.activity_main); //ボタン1個のレイアウト(任意)

//わざと例外を発生させるボタン
Button button1 = (Button)this.findViewById(R.id.button1);
button1.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("LOG", "button1 onClick");
data[5] = 1; //ArrayIndexOutOfBoundsException
}
});
}
}

●出力された「error_report.txt」の内容
java.lang.ArrayIndexOutOfBoundsException
at com.example.testandroid.MainActivity$1.onClick(MainActivity.java:28)
at android.view.View.performClick(View.java:2408)
at android.view.View$PerformClick.run(View.java:8816)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)

 実際にメインに必要なコードは「Thread.setDefaultUncaughtExceptionHandler(new ErrorReporter());」の1行だけになる。上の例ではコンストラクタで定義しているが、onCreate() でも構わない。もちろん、エラーが発生する前である必要はある。

 出力されたテキストファイルはSDカードのルートに置かれ(実機によって「/sdcard」や「/mnt/sdcard」など異なる)、スマホに元から入っている「マイファイル」(アプリ名は端末よる)などでそのまま覗ける。エミュレータ上でも「DDMS」で右上にある「pull」ボタンを押せば、ローカルに落とせる。テキストエディタなどで確認すれば良い。なお、ファイル名は任意で良い。


 ちなみに元ネタは「アプリがエラーで強制終了したときに、バグレポートを送信する機能」で、それを超簡単にして、SDカードにエラーを吐き出させる機能のみに限定したものだったりする。なのでユーザー向けでなく、自分用(開発者用)という感じなので、ダイアログすら付けてない。ちゃんとしたものが欲しければ以下のURLを参照して欲しい。メモリ使用状況やビルドのバージョン情報などを付加するのもデバッグの役に立つかも知れない。

(参考)
Androidアプリのバグ報告システムを考える
Android キャッチされなかった例外を処理する
Android でアプリケーションが強制終了したとき、エラーレポートを送るようにする

(SDカードの書き込み権限など)
【スマホのコツ】Android5.0以上でSDカードへ書き込みができるファイラーアプリとその方法


(関連記事)
【Android】エミュレータでSDカードをマウントして使う方法 その2
【Android】SDカードにテキストファイルを保存する
【Android】SDカードからテキストファイルを読み込む
【Android】内部ストレージにテキストファイルを保存する
【Android】Preference 機能を使ってデータを読み込み・保存する
【Android】【Applet】【Java】テキストファイルの読み込み・保存 まとめ


category: Android

thread: プログラミング

janre: コンピュータ

tag: テキストファイル保存  SDカード 
tb: 0   cm: --

【PHP】【Android】apk ファイルを PHP でダウンロードする  


 内容的には「画像を PHP から送信して、Android で受信する」とあまり変わらない。

 サーバーによっては、「.htaccess」に、

AddType application/vnd.android.package-archive .apk

を追加しただけで、リンクからダウンロードできる場合もあるが、レンタルサーバーなどは上手くできない事もあるので、そういうとき PHP でダウンロードできるようにするスクリプト。

 とりあえずファイル名を「dl.php」とすると、

■apk 用 ダウンローダ PHP (dl.php)
<?php
$filename = $_SERVER['QUERY_STRING'].'.apk';

if (file_exists($filename)) {
header('Content-Type: application/vnd.android.package-archive');
header('Content-disposition: attachment; filename='.$filename);
header('Content-Length: '.filesize($filename));
readfile($filename);
exit;
}
?>

でOK。header() で Content-type を出力してるので、「<?php」タグより以前に文字列などを書かないように注意。改行1つでも入ると、PHP では text/html として出力されてしまう。

 ダウンロード用のリンクは、

<a href="dl.php?Sample">Sample</a>

のように名前(Sample)だけ「?」の後に書いておけば、「Sample.apk」としてダウンロードされる。

 また、ブラウザが HTML5 仕様なら、<A> タグの download 属性 を付けた方が良いかも知れない。

(参考)
PDFなどのファイルを強制的にダウンロードさせる3つ方法の比較


 ちなみに野良アプリ配布の場合は、スマホ端末の「提供元不明のアプリのインストールを許可」してないとインストールできない事があるので、注意書きをして置くと親切かもしれない。

 少し改造して、名前ごとのカウントをデータベースに記録しておけば、ダウンロード数なども表示できると思う。


(関連記事)
【PHP】【Android】画像を PHP から送信して、Android で受信する


category: Android

thread: プログラミング

janre: コンピュータ

tag: PHP  通信 
tb: 0   cm: --

【Android】【Java】Bitmap.getConfig() がなぜか null になる  


 う~ん、どうもこの問題は海外サイトまで調べたけど、いまいち原因は書かれてないな…。

 私が実験していたのは、他者のライブラリで画像も適当なサンプルを使っていたので、画像フォーマットの問題なのかと思ったのだが、同じ条件で新しく作った画像でも、片方は上手くいって、片方は null が返ってきたりする…。なんじゃこりゃ。

 というわけで、あまりいい対処法は見つからなかった。無理矢理やるなら、try~catch で 囲って、エラーが出たら、Config.ARGB_8888 でやるしかないのかもね。Android のバージョンにもよるみたいなことも書いてあったが、詳細は不明。

 例えば、

Bitmap image1, image2;
try {
image1 = BitmapFactory.decodeResource(getResources(), drawableID);
image2 = image1.copy(image1.getConfig(), isMutable); //getConfig() = null になることがある
} catch (Exception e) {
image2 = image1.copy(Config.ARGB_8888, isMutable); //こっちなら大丈夫
}

みたいな感じに。

 Bitmap.createBitmap(w, h, image.getConfig()) みたいなコードもね。取得できないことがたまにあるので、エラーが出る。使わない方が無難かな…。


category: Android

thread: プログラミング

janre: コンピュータ

tag: グラフィックス  トラブルシューティング 
tb: 0   cm: --
IS<インフィニット・ストラトス> アーキタイプ・ブレイカー
キルドヤ


プロフィール

Twitter

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop