著者アーカイブ asaba

asaba 著者:asaba

【androidJava】LounchModeの属性を理解しながら説明してみる

androidのタスクの中のアクティビティを管理するには、LounchModeをうまく使う必要があります。

android:launchMode="singleTop"

この属性を使い分けることによって遷移先のアクティビティで前アクティビティを破棄したり、別のアプリから開いたときのアプリの優先順位を変えたりしてアプリのライフサイクルに変化をつけることができます。ここでは、ACTION_SENDを処理できるActivityAを持っているアプリXとその遷移元のsampleApplyを例にして見ていきます。

sampleApplyアプリで、intentを使ってアプリXに移動します。下は、LounchModeにsingleTopを設定してアプリXに移動した時のタスクの状態です。

—————

| sampleApply アプリX

—————

その後全く違うアプリに移動した時に、再度sampleApplyアプリを起動してみます。すると、タスク上で一番新しい画面のアプリXが表示されます。

図でも判るように、sampleApplyの後にアプリXが格納されていることが分かります。別のアプリに移った後でもまたsampleApplyを起動した場合は、アプリXが表示されます。singleTop適用下では呼び出し元のタスクから順に保持されるため、sampleApplyではなく画面Aが表示される仕組みになっています。つまり、一つのアプリのようにふるまわれる(連結しているような)状態でタスクに保持されます。

intent先でRESULT_CANCELEDを受け取るのを回避したい場合は、このモードを優先して使う必要があります。

次は、singleTask属性で同じことをしてみます。singleTaskモードを設定して別のアプリを起動後に同じようにsampleApplyを起動すると次のようなタスクになります。

—————

| sampleApply | アプリX

—————

さきほどのsingleTop属性と違い、一つ一つのアプリの画面が違うタスクとして分けられています。同じように別のアプリに移った後にホーム画面でsampleApplyを選択します。すると、アプリXに遷移したはずなのにsampleApplyの画面に移動してしまいます。これは、singleTop適用下において、呼び出し元がタスクにとっての最優先アクティビティとして区別されているためです。図で表すと以下のようになります。

—————

| アプリX | sampleApply

—————

ここでは、原点であるsampleApplyがまず呼ばれます。ここで戻るボタンを押した場合は、先ほど先頭に位置していたActivityAが表示されます。一回画面を離れたときに、セキュリティの都合でデータを残したくないアプリを作りたい時に有用そうですね。

asaba 著者:asaba

【android Permission】アプリでカメラ許可をしても落ちてしまう時の対処法

パーミッションを設けたアプリで許可をしても許可されずに強制的に落としてしまう時があります。

androidStudioでキャッシュを消すー>デバイスでインストールしたアプリをアンインストールで再インストールしてみましょう。

現行のandroidで試してみましたがこの方法ならば確実にパーミッションを許可できるのでおすすめです。

 

asaba 著者:asaba

【android-Java】ActivityとContextの違い

fragmentでActivityをいじっている時に、そういえばアプリ開発においてあまり意識していなかったけど、ActivityとContextの
違いってなんだろうと思い調べてみました。意味を調べた結果、そもそも双方とも同じ概念というか、もともとは一つのかたまりのような
ものでした。Contextは、Activityを含んだ全てのオブジェクトを指し、Activityは、Contextの一番新しい層に作られるオブジェクト
のことです。きんちゃく袋と飴ちゃんに例えると、きんちゃく袋がContextで、飴ちゃんがActivityの関係になります。




WebViewを使ったFragmentActivityで元のアクティビティの機能またはアクティビティそのものを取得したい時は、getActivityや
getContextを使います。自分は両方でアクティビティを取得してアプリの挙動を見てみたのですが、どちらも全く変わりない動きでした
ので、どっちのメソッドを使っても支障はないかと感じました。

※fragmentでthisを呼ぶとfragmentはContextを継承していないのでエラーを受けます。(当たり前ですが)

 

asaba 著者:asaba

【androidJava・fileProvider】外部ファイルを参照してくれない時の対処法

android7.0から利用が義務づけられているfileProviderですが、これを使ったファイルの保存方法が少し癖があったので載せておきます。今までのアンドロイド(5.0まで)の場合はEnvironment.getExternalStoragePublicDirectory()の後にDIRECTORY_DCIMを引数にしてファイル名を付けてあげれば自動で保存してくれていたのですが、7.0以降はなぜか全く別のディレクトリを探索する使用になっており、ここの軌道修正に随分と手を焼いてしまいました。ではどうやってファイルを保存したかというと下のpath.xmlを参照してみます。

</pre>
<pre><?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="storage/emulated/0" path="."/>
</paths></pre>
<pre>

三行目のname内。ここはandroid23以前でいつも参照されるファイルの保存場所になります。

「/storage/emulated/0/DCIM/Camera/21073354.jpg」<-は、android5.0で保存したファイルのディレクトリの全長になります。本来ならこのように自分でディレクトリを参照して探してくれるのですが、android7.0以降だとnameを適当な名前にしてしまうとその名前のディレクトリを探し始めるのでファイルが存在しないよと言われてしまう仕組みになっていました。

「/hogeFile/DCIM/Camera/21080925.jpg:picFile」では、本来存在しないはずの「hogeFile」を探してしまうのでエラーになります。という訳でpath.xmlファイルのnameには必ず外部ストレージと同じ名前をつけてあげてねという手厳しい指摘でした。というかどこにも書いていないのでものすごく大変でした今回・・・。

もし、fileProviderを使っていてファイルが保存できなかったり読み込めなかったときはxmlファイルのnameを疑ってみてくださいね。

 

asaba 著者:asaba

【android】No such file or directoryの対処法

FileNotFoundException(No such file or directory)例外でファイル又はディレクトリが見つからなかったので外部フォルダに真新しいフォルダを作る方法で回避しました。exeternal-pathを使う場合はそのままコピペでも使えますので試してみてください。

</pre>
<pre>//Cameraディレクトリ生成
File imageStorageDir = new File(
        Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DCIM),"Camera");

if(imageStorageDir.mkdirs()){
    imageStorageDir.mkdirs();
}else{
    System.out.println("既にディレクトリを生成しています。");
}</pre>
<pre>

mkdirs()は、ディレクトリ(フォルダとフォルダを繋ぐ道のりのようなもの)を生成します。
Environment.getExternalStoragePublicDirectory()だけだとファイルを作っただけで、双方フォルダのつながりはこの段階ではまだできていません。エミュレータでこれを書き忘れるとNo such file or directoryで血管が切れるので忘れずに記述しましょう。

ちなみにNo such file or directoryエラーは、androidAPI23以前だとpermission deniedという名前で出てきます。大半はファイルが保存されなかったまたは書き込みの失敗で出てくるので覚えておくと役に立つかもしれません。

asaba 著者:asaba

【android】fileProviderを導入したエミュレータでできること・できないこと

android7.0のエミュレータでfileProviderを試してみたのですが、使う範囲には限度があったというかできることがかなり少なく窮屈に感じました。まずディレクトリを直に作ることができないので、中のファイルがどこにいったかも分からず参照もできません。従ってディレクトリの中からファイルを探して何かする作業をすることができない状態なのです・・・!android7.0以降だと、no such no fileの警告を吐くだけでエラーの発信もしてくれないというかなり渋い振る舞い。(7.0以前だと即死もとい処理落ちしてくれます。)

何も手を加えていないエミュレータできること

onActivityの後にimageView.setImageURI(hoge);などのuriを貼り付ける作業

できないこと

・ディレクトリを参照してファイルを編集する作業

・アプリのカメラで保存した画像を編集して再保存

・アプリを閉じている時の非同期通信

少ないですねwディレクトリの操作やバックグラウンドでの処理機能は実機のほうが勝手がきくのでやはり複合機能を持ったアプリ開発には向かないですね。この他にも、エミュレータと実機で違う動きをしたらまた新たに要項追加していきたいと思います。

asaba 著者:asaba

【android】Failed to find configured root that containsの解決法

fileProviderをandroid7.0で動かしたのですがまたもエラーにかかりました。こんなエラーです↓


java.lang.IllegalArgumentException: Failed to find configured root that contains

どうやらパスの指定を間違えていたみたいです。fileProviderを使う時に必ずxmlファイルにpath.xmlを突っ込むのですが、ここでパスの指定先を間違えるとこのようなエラーにハマってしまいます。

このパスでは動かない↓

</pre>
<external-path name="share_images" path="image"/>
<pre>

このパスなら問題なく動く。↓

<external-path name="share_images" path="."/>

どのディレクトリにも行けるように初期位置に配置することがポイントです。また、Environment.getExternalStoragePublicDirectoryを
使っている時に<file-path>を使ってもエラーが出るのでここでは<eternal-path>タグを使いましょう。

asaba 著者:asaba

【Excel】フィルタリングに失敗した時の対処法(自分用)

エクセルファイルを作成している時によく使うフィルタ機能ですが、偶に一番上のデータだけそのままの位置に残ってしまう時があります。

表を作る時にハマりがちなのですが、自分は一番上のデータにカーソルを合わせた状態でフィルタリングすることでさくっと対処できました。フィルタリングしたいデータを全部囲むときにバグが生じるらしいのですが、一つのデータの位置が違うことって意外と気づかないので結構怖いです。

同じような現象に遭遇したら試してみてください。

asaba 著者:asaba

gradleの依存関係を調べる(自分用)

ライブラリの依存関係を調べる方法と言えば./gradlew dependenciesですが、自分のpcではファイルとして認識されなくて少しはまりました。調べてみると簡単に解決したので、また忘れたときのために置いておきます。

とりあえずコマンドを再起動して依存関係を確認したいプロジェクトに移動してgradlew :app:dependenciesと変更して難なく成功。先頭の/.を消去してgradlewとdependenciesの間に「app」を挟むのがポイントです。

なぜ「app」を挟まなないと動いてくれないかは説明できません。自分はドキュメントに直接プロジェクトを保存していますが、それがいけないのでしょうか。

入力方法です↓

cd documents\sampleAppで移動ー>ディレクトリsampleAppに移動したらgradlew :app:dependenciesで入力ー>ライブラリの依存関係がドバっと出てくる。ー>good!

 

asaba 著者:asaba

【androidStudio】レガシーになったGooglePlayServiceライブラリを卒業してみた

もう何年もメンテナンスしていないソースコードでは、大抵はライブラリが昔のバージョンのまま放置されています。古いうえにライブラリに新しいクラスがつっこまれたりしているので新しいAndroidAPIで動かしてみても勿論死にます。自分の担当したアプリも例外でなく、このcompile ‘com.google.android.gms:play-services:8.0.0’というライブラリに手を焼いておりました。

GoogleAPIでも書かれていますが、こいつはもうそのままでは使えません。GooglePlayServiceは大量のクラスを持っているので新規で追加されたライブラリの中で一個でも同じクラスがあった場合は競り合いとみなされ速攻でクラッシュします。厳密には、一つの機能しかないアプリならまあ古いバージョンでも使えますが、それでは実用性がないのでやっぱり使うのにはおすすめしません。

これからはAPI別に機能が分けられたbuild.Gradleを記述することで使えるようになるので、そちらの方法で使いましょう。と公式先生がおっしゃっていたのでそちらに従ってライブラリを入れましょうということです。

例えば、新しいバージョンでもGooglePlayServiceのLocationServices機能が使いたい!と思ったときは既存のGooglePlayServiceを消してこんな感じにgradleに書いていきます。

これを削除

</pre>
compile 'com.google.android.gms:play-services:8.4.0'
<pre>

でこちらを代わりに導入します。

</pre>
<pre>implementation 'com.google.android.gms:play-services-location:16.0.0'</pre>
<pre>

こんな感じで大元のcompile ‘com.google.android.gms:play-services:8.4.0’を削除してアプリの機能にあったライブラリをいれていきます。公式を見ながらでも全然できますが、アプリで使われているライブラリが何なのか先見しておいて調べておくと入れ替えがもっと楽になるのでおすすめです。

公式→https://developers.google.com/android/guides/setup