Android

Google Play審査リジェクト「不適切な広告」に対応する

拙作のタイ語辞書アプリ「ごったい」のアップデート時の審査で、「不適切な広告に関するポリシー違反」ということでリジェクト(非承認)を喰らってしまいました。同様にリジェクトされてしまった人の参考になるかと思い、対応とあきらめの歴史を記事にしておこうと思います。 ...続きを読む

Google Play審査リジェクト「不適切な広告」に対応する Read More »

Google Play審査リジェクト「ユーザー作成コンテンツ」に対応する

Google Playで公開済みのAndroidアプリのアップデートをリリースしようしたら、審査でリジェクト(非承認)されてしまいました。なんとか対応できて無事公開に漕ぎつけることができたので、その方法を記事にしておきます。 ...続きを読む

Google Play審査リジェクト「ユーザー作成コンテンツ」に対応する Read More »

【Android】OnScrollListener#onScroll備忘録 – ListViewのフッターが見えたら何かする

よく忘れるのでメモ。

override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int)

  1. view — スクロールを検知したView。ListViewとか。
  2. firstVisibleItem — 表示されているItemのうち一番上のもののIndex。一部しか見えていない場合でもよい。
  3. visibleItemCount — 表示されているItemの数。一部しか見えていないものもカウントする。
  4. totalItemCount — 非表示の部分も含めたItemの合計数。なお、ヘッダー・フッターもカウントする。

例えばListViewのフッターViewにProgressBarを配置しておき、このフッターが表示されたら追記読み込みをする・・・といった場合の末尾到達判定は以下のようになる。(kotlin)

📄OnScrollListener
...
override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
    if (firstVisibleItem + visibleItemCount >= totalItemCount) {
        // do something
    }
}
...

 

【Android】OnScrollListener#onScroll備忘録 – ListViewのフッターが見えたら何かする Read More »

【Android】アップデート情報を表示するライブラリ【ReleaseAnimal】

Androidアプリを開発していると、アップデート後にリリースノートを表示したくなることがある。簡単に表示してくれるライブラリでもないかなと探してみたけど見つからなかったので、自分で『ReleaseAnimal』というものを作ってみた。

ReleaseAnimal

こんな感じのダイアログを簡単に表示できる。

もちろん1度表示したものは2度と表示しない。アプリを初めてインストールするより前のリリース情報は無視するとか、最低限の考慮はできていると思う。

Usageとか

githubに書いた通りだけど、インストール方法はbuild.gradleに1行追加するだけ。(バージョン番号は適宜変更してください)

📄build.gradle
dependencies {
    ...
        compile 'itmammoth.releaseanimal:ReleaseAnimal:0.0.3'
    ...
}

そして自分のapp内にres/xml/releaseanimal.xmlというファイルを作成する。中身は次のような感じで。

📄res/xml/releaseanimal.xml
<?xml version="1.0" encoding="utf-8"?>
<releaseNotes>
    <note date="2016-11-20" versionName="0.0.0.2">
        <message>- New awesome features!</message>
        <message>- Small bug fixes</message>
    </note>
    <note date="2016-11-25" versionName="0.0.1.0">
        <message>- Foo bar yeah!</message>
        <message>- Pen pineapple apple pen!</message>
        <message>- Blah blah blah</message>
    </note>
</releaseNotes>

dateにはリリース日、versionNameには、そのままんだけどversionNameを指定する。例えば今日アップデートをリリースする予定だとすると、dateには今日の日付、versionNameにはアップデート後のversionNameを指定する。messageは適当に改行でjoinされて表示される。

表示するJavaコードは次のように。

📄MainActivity.java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        new ReleaseAnimal.Builder(this).show();
    }
    ...
}

これだけ。我ながら楽チン。

その他詳しいことはgithubを見てほしい。 ...続きを読む

【Android】アップデート情報を表示するライブラリ【ReleaseAnimal】 Read More »

【Android】安全にonActivityResultを実行する

アクティビティから他のアクティビティを呼び出して、その結果を貰い何かを実行する場合がある。定石としてはonActivityResultメソッドをオーバーライドして、その中で処理を実行するというものだが、この方法だと稀にわけの分からん例外が発生する。

📄BaseActivity.java
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=null} to activity {your_class}: java.lang.NullPointerException

この例外を発生させずに安全にコードを実行するサンプルを書いてみてる。

例外の原因

いろいろ調べてみた結果、次のような記事を発見した。

“Failure Delivering Result ” – onActivityForResult

この回答によると、

At the time that onActivityResult() is called, the activity/fragment’s state may not yet have been restored, and therefore any transactions that happen during this time will be lost as a result.

らしい。要するにonActivityResultが呼ばれたときにアクティビティ/フラグメントが完全にリストアされているかどうか保証されていないということ。

解決策としては復帰後に呼ばれるonPostResumeメソッドでやりたい処理を実行すればよいとのこと。これは順序的にはonActivityResult => onPostResume => onResume にとなっており、onPostResumeメソッドは、アクティビティ/フラグメントがリストア済で呼び出されるようだ。

解決コード

というわけでStackoverflowの回答を発展させて、次のようなコードを書いた。

public abstract class BaseActivity extends AppCompatActivity {

    private class ActivityResult {
        private final int requestCode;
        private final int resultCode;
        private final Intent data;

        private ActivityResult(int requestCode, int resultCode, Intent data) {
            this.requestCode = requestCode;
            this.resultCode = resultCode;
            this.data = data;
        }
    }

    private ActivityResult activityResult;

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        activityResult = new ActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        if (activityResult != null) {
            onPostResumeWithActivityResult(activityResult.requestCode, activityResult.resultCode, activityResult.data);
            activityResult = null;
        }
    }

    protected void onPostResumeWithActivityResult(int requestCode, int resultCode, Intent data) {
        // override if necessary
    }
}

大して難しいことはしていなくて、単にonActivityResultメソッドで結果を保持しておいて、onPostResumeメソッドが呼び出されたときにonPostResumeWithActivityResultメソッドを呼び出してあげる。

各アクティビティクラスは次のような感じになる。

📄MainActivity.java
public class MainActivity extends BaseActivity {

...

    @Override
    protected void onPostResumeWithActivityResult(int requestCode, int resultCode, Intent data) {
        super.onPostResumeWithActivityResult(requestCode, resultCode, data);
        // ここで煮るなり焼くなりする
    }

...

}

各アクティビティのonPostResumeWithActivityResultメソッドには、従来onAcitivityResultメソッドに書いていた処理を書くことになるわけだ。

とりあえずこれで上手くいっている。なんか問題あったら教えてください。

【Android】安全にonActivityResultを実行する Read More »