[Android] IllegalStateException: Cannot add header view to list : setAdapter has already been called.

Android アプリ開発にて、ListFragment で setListAdapter した後に addHeaderView や addFooterView を呼び出すと java.lang.IllegalStateException 例外が発生して、アプリがクラッシュしてしまいます。

Android 4 系だと例外は発生しなくて、Android 2.3 系だと例外でクラッシュするみたいです。

Stack Trace
_________________________________
0	java.lang.RuntimeException: Unable to resume activity {com.example/com.example.activity.MainActivity}:
 java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
1		at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2124)
2		at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139)
3		at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961)
4		at android.os.Handler.dispatchMessage(Handler.java:99)
5		at android.os.Looper.loop(Looper.java:123)
6		at android.app.ActivityThread.main(ActivityThread.java:3691)
7		at java.lang.reflect.Method.invokeNative(Native Method)
8		at java.lang.reflect.Method.invoke(Method.java:507)
9		at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
10		at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
11		at dalvik.system.NativeStart.main(Native Method)
12	Caused by: java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
13		at android.widget.ListView.addHeaderView(ListView.java:336)
14		at android.widget.ListView.addHeaderView(ListView.java:359)
15		at com.example.fragment.NewFragment.refreshListView(NewFragment.java:358)
16		at com.example.fragment.NewFragment.onResume(NewFragment.java:143)
17		at android.support.v4.app.Fragment.performResume(Fragment.java:1503)
18		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
19		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
20		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
21		at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1871)
22		at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:455)
23		at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:444)
24		at com.actionbarsherlock.app.SherlockFragmentActivity.onPostResume(SherlockFragmentActivity.java:69)
25		at android.app.Activity.performResume(Activity.java:3867)
26		at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2114)
27		... 10 more
28	java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
29		at android.widget.ListView.addHeaderView(ListView.java:336)
30		at android.widget.ListView.addHeaderView(ListView.java:359)
31		at com.example.fragment.NewFragment.refreshListView(NewFragment.java:358)
32		at com.example.fragment.NewFragment.onResume(NewFragment.java:143)
33		at android.support.v4.app.Fragment.performResume(Fragment.java:1503)
34		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
35		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
36		at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
37		at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1871)
38		at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:455)
39		at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:444)
40		at com.actionbarsherlock.app.SherlockFragmentActivity.onPostResume(SherlockFragmentActivity.java:69)
41		at android.app.Activity.performResume(Activity.java:3867)
42		at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2114)
43		at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139)
44		at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961)
45		at android.os.Handler.dispatchMessage(Handler.java:99)
46		at android.os.Looper.loop(Looper.java:123)
47		at android.app.ActivityThread.main(ActivityThread.java:3691)
48		at java.lang.reflect.Method.invokeNative(Native Method)
49		at java.lang.reflect.Method.invoke(Method.java:507)
50		at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
51		at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
52		at dalvik.system.NativeStart.main(Native Method)

正しいコード

// addHeaderView 後に setListAdapter
listView.addHeaderView(headerView);
listView.addFooterView(footerView);
 
setListAdapter(arrayAdapter);

IllegalStateException でクラッシュするコード

// setListAdapter 後に addHeaderView
setListAdapter(arrayAdapter);
 
listView.addHeaderView(headerView);
listView.addFooterView(footerView);

必ず setListAdapter する前に、addHeaderView や addFooterView を呼び出すようにしましょう。

[参考]

Note to self: ListFragment and header views

android – ListFragment add headerView gives java.lang.IllegalStateException:alled – Stack Overflow

Android – ListActivity, add Header and Footer view – Stack Overflow

android – How to add footer view dynamically – Stack Overflow

[Android] RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()

開発中の Android アプリが、下記のエラーでクラッシュしました。

RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

原因は、doInBackground() 内で UI に関する処理を行なっていたためでした。
(具体的には、エラーメッセージを Toast で表示しようとしていた)

エラーが発生したときは、doInBackground() 内でエラーダイアログの表示などは行わず return null を返して、 onPostExecute メソッド内で良しなにエラー通知をするべきです。

メソッドdoInBackgroundはUIスレッドとは別なプールから取得されたスレッド上で実行されるのでGUI操作をしてはならない。代わりにUTスレッドと同期されるonProgressUpdateやonPostExecuteメソッド内でGUI操作を完了できる。

[引用]:バックグラウンドスレッドでダイアログを生成してはいけない – Kazzzの日記

[参考]

Android Can't create handler inside thread that has not called Looper.prepare() – Stack Overflow

android – Can't create handler inside thread that has not called Looper.prepare() – Stack Overflow

[Android] リアルタイムでクラッシュレポートを自動送信するサービスまとめ

Android アプリに、リアルタイムでクラッシュレポートを自動送信するサービスやツールをまとめてみました。

Crittercism

Crittercism | Mobile Application Performance Management

スマートフォンアプリのクラッシュログ解析サービス (crittercism と bugsense) を使ってみた – むらかみの雑記帳

BugSense

BugSense | Crash Reports and Operational Intelligence for Android, iOS, Windows Phone & Windows 8 apps

超簡単!BugSenseでスマホアプリ/サイトのクラッシュ統計をとろう | Developers.IO

ACRA (Application Crash Report for Android)

ACRA/acra · GitHub

Android ACRAを使ってアプリのクラッシュ情報を自動送信する方法 | Tech Booster

以上です。

[Android] RuntimeException on AsyncTask : NullPointerException on doInBackground

Android アプリで、AsyncTask を実行中に RuntimeException が発生して、クラッシュするバグの解決方法をメモ。

"Thread: AsyncTask #5, Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
	at android.os.AsyncTask$3.done(AsyncTask.java:278)
	at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
	at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
	at java.util.concurrent.FutureTask.run(FutureTask.java:137)
	at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
	at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.NullPointerException
	at com.example.myapp.d.c$a.doInBackground(SourceFile:1)
	at android.os.AsyncTask$2.call(AsyncTask.java:264)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
	... 5 more"

doInBackground メソッド内で、NullPointerException の例外が発生している箇所を try/catch ブロックで上手く囲んで、メソッドの最後で return null; を返すようにすればOKです。

また、このとき onPostExecute メソッド内で、引数に null が渡ってきたときに Async タスクが失敗したときの処理を行う必要があります。

[参考]

android – AsyncTask doInBackground returning a nullpointerexception only sometimes – Stack Overflow

Android : Getting RuntimeException on AsyncTask – Stack Overflow

[Android] アプリが実行できる最下位の API レベル (OSバージョン) は android:minSdkVersion で設定する

タイトルで完結していますが、Android アプリが実行できる最下位の API レベル (OSバージョン) は android:minSdkVersion で設定できます。

詳しくはこちら。

Android バージョン – Wikipedia

APIレベル(OSバージョン)については、ウィキペディアでも確認できます。

1. Android API レベル – ソフトウェア技術ドキュメントを勝手に翻訳

[iOS] iPhoneアプリのApp StoreダウンロードページのURLを申請前に作成する方法

iPhoneアプリのApp StoreダウンロードページのURLを申請前に作成する方法をメモ。

iPhoneアプリをDLするURLを申請前に作成する方法 – Sawalog

hyperlink – What is "mt=8" in iTunes links for the appstore? – Stack Overflow

[Android] Google Play Developer Console の「マーケティングの除外」について

Google Play Developer Console で Android アプリを申請する際に「マーケティングの除外」という項目があって、これについて調べたことをメモ。

「マーケティングの除外」の項目は、デフォルトでチェックがオフになっていて、チェックボックスの横には下記のような説明が書かれている。

Google Play と Google 所有のオンライン/モバイル サービス以外ではアプリケーションを宣伝しません。この設定への変更が有効になるまでに 60 日程度かかることについて了承します。

アプリケーションの宣伝のための露出が多い方が良いなら、未チェックのままでよさそうです。

下記の記事で詳しく考察されてます。

Androidの“マーケティングの除外”について – adsaria mood

マーケティング対象の限定

アプリのマーケティングを Google Play だけで行う場合は、次の方法で他でのマーケティングを除外できます:

Google Play デベロッパー コンソールにログインします。
スクロールして、マーケティングから除外するアプリを探します。
[価格と販売/配布地域] を選択します。
[同意事項] の下にある [マーケティングの除外] を選択します。

[引用元]:画像アセット – Android Developer ヘルプ

[Android] 正しく時刻設定してないと Twitter 認証時にエラー発生

Android アプリにて、正しく時刻設定してないと Twitter 認証時に下記のような例外が発生してしまいます。

Received authentication challenge is null
Relevant discussions can be found on the Internet at:
	http://www.google.co.jp/search?q=10f5ada3 or
	http://www.google.co.jp/search?q=e574403a
TwitterException{exceptionCode=[10f5ada3-e574403a b8c63e52-c913c2cc], statusCode=-1, message=null, code=-1, retryAfter=-1, rateLimitStatus=null, version=3.0.3}

動作試験で、時刻設定を未来の時間に設定したままで、今回のようなエラーが発生しました…。

とりあえず、バグではなかったので良かったです。

[Android] Facebook 認証できないエラー : com.facebook.FacebookOperationCanceledException: remote_app_id does not match stored id

Android アプリ開発で、Facebook 認証できないというエラーが発生しました。

com.facebook.FacebookOperationCanceledException: remote_app_id does not match stored id

Facebook アプリの設定画面に登録している Key Hashes が間違っている場合、このようなエラーが発生するようです。

下記のコードを onCreate に記載して、key hash をログに出力して確認します。

try {
    PackageInfo info = getPackageManager().getPackageInfo("com.example.packagename",
            PackageManager.GET_SIGNATURES);
    for (Signature signature : info.signatures) {
        MessageDigest md = MessageDigest.getInstance("SHA");
        md.update(signature.toByteArray());
        Log.d("YOURHASH KEY:",
                Base64.encodeToString(md.digest(), Base64.DEFAULT));
    }
} catch (NameNotFoundException e) {
 
} catch (NoSuchAlgorithmException e) {
 
}

key hash をコマンドラインで確認する方法もありますが、Windows用の OpenSSL を使わないといけないらしく、Mac用の OpenSSL だと正しい key hash が取得できないみたいです。

例えば、コマンドラインで keytool を使って debug.keystore の key hash を確認すると、 bvfSSDnrryuK8cbfekyHTs59l/A= です。

keytool -exportcert -alias androiddebugkey -keystore debug.keystore | openssl sha1 -binary | openssl base64
キーストアのパスワードを入力してください:  android
bvfSSDnrryuK8cbfekyHTs59l/A=

しかし、冒頭の方法で、アプリ実行時のログから key hash を出力させると dkgthMwGADFQ7/9fkMn4MUzpSWo= であり、こちらが正しい値です。

ややこしい話ですが、解決方法が分かって良かったです。

参考情報

[Android] keystore ファイルの内容を確認するコマンド

Android アプリの署名ビルドに使う keystore ファイルの内容を確認するコマンドをご紹介します。

Android

続きを読む