handler.postを利用して画面が更新されないパターンがあるでしょうか?

2,353 views
Skip to first unread message

安藤大輔

unread,
Jul 10, 2011, 10:51:29 PM7/10/11
to android-g...@googlegroups.com
安藤と申します。初めて投稿させていただきます。

表題の件で、Exceptionが発生しないのに画面が更新されない、という状況が発生して困っています。
もし同じような現象や、何か調査した方がよいポイントなどをご存じの方がいましたら、ご意見いただければ
幸いです。

■環境
API Level 8


■詳細
一覧画面→詳細画面(該当の画面)→(物理キーで戻る)一覧画面→詳細画面

この動作を繰り返したときに、詳細画面に必要な情報が表示される場合と、表示されない場合が発生します。
表示される/されない確率は表示されない確率の方が高いです。
連続で表示される場合もありますが、一度表示されなくなる(といっても2,3回行き来すれば表示されなくなって
しまいますが)としばらく表示されない状態が続きます。
一番最初に詳細画面を表示する場合は、必ず取得した情報が表示されます。


handler.postについて、実行している処理は以下のような順序です。

1.UIスレッドから必要な情報をリクエスト(サービスを経由しています、インターネット越しのデータ取得のため)
2.レスポンスを受信したサービスからアクティビティへデータ受け渡し
3.レスポンス受信スレッドからhandler.postを経由してUIスレッドへデータ更新通知

UIスレッド上で、handler.post内の処理が呼び出されていることは確認したのですが、肝心の画面が
何も更新されない状況です。
(Exceptionの発生はなし)

なお、この画面はいくつかのTextView, ImageView, Gallery, TabWidgetsなどから構成されています。
ActivityにはTabActivityを利用していますが、画面が表示されない場合はcreateTabContent()メソッドが
呼び出されません。


■試してもダメだったこと
・TabActivitiy.onStop(), onPause()等でActivity.finish()を呼び出す
handler.post内の更新処理で各viewに対してsetVisibility(View.VISIBLE)を呼び出す
・TabActivity.onPause()でtabHost.clearAllTabs()を呼び出す


TabActivityを利用するための「お作法」が間違っているのだと思うのですが、どのあたりを中心に
調査/検証していけばよいか、混乱中です。
よろしくお願いいたします。

daisuke

unread,
Jul 11, 2011, 9:19:19 AM7/11/11
to 日本Androidの会
少し進展がありましたので追記いたします。

handler.post()しても表示が更新されないのは、おそらく各Viewが更新処理を行わない状態になっているためと思われます。
(onDraw()が呼ばれない!?androidのソースをまだ見ていないので、想像です。)

試しにアクティビティにIntentで渡したデータをUIスレッド上で(onCreate()で)セットしてみたところ、そのViewの情報は更新され
ました。
またTabActivityのcreateTabContent()メソッドが呼び出されなかったのはhandler.post()内で
addTab()していることに起因するようで、
handler.post()内でtabhost.clearAllTabs()を呼び出しておくと、createTabContent()が呼び出さ
れました。
(しかし相変わらずViewは更新されませんが)

とすると、別のスレッドから更新をかける場合のお作法、という話になってくるかと思います。
View.invalidate()を呼び出しておけば(または各Viewへのデータセット後に呼び出す)よいかと思いましたが、これもダメなようで
す。
そのため別スレッドから、更新したいViewにデータをセットする前に何か準備する(android内部で利用されるフラグを立てるなど?)
ことが解決方法かな、と考えています。。(が、ちょうどよいAPIを見つけられていないです。。)

Viewが更新されるときと、更新されないときがあるのがやはり不思議です。。
スレッドがデッドロックするのであれば分かるのですが。

何か情報をいただけますと、大変助かります。
よろしくお願いいたします。

yoshiyuki kanno

unread,
Jul 11, 2011, 10:03:17 AM7/11/11
to android-g...@googlegroups.com
菅野です。

安藤さんのケースとは若干異なるかもしれませんが、
TabActivityのタブをonCreate以外の場所で動的に作成する必要があったのですが(ネットワーク通信結果によってタブの内容が変わる)、
1.x系だと途中でNullぽで落ちる、2.x系だと表示されない場合がある、といった症状に遭遇した事があります。

どうやらonCreateで最低でも一つのTabコンテンツが作成されている前提があるようだったので、
onCreateではダミーのタブを作成しておき、以下のように非表示にしておきました。

TabHost tabHost = getTabHost();
tabHost.addTab(tabHost.newTabSpec("dummy").setIndicator("dummy").setContent(new Intent().setClass(HogeTabActivity.this, HogeContentActivity.class)));
tabHost.setCurrentTab(0);
tabHost.setVisibility(View.INVISIBLE);

で、handlerで通信結果を受け取ったら

tabHost.clearAllTabs();
tabHost.setVisibility(View.VISIBLE);
// 以下でaddTabするコード

のように非表示のダミーを削除後に、コンテンツを追加で無事期待通りの動作にいきつきました。

参考になれば幸いです。


2011年7月11日22:19 daisuke <do.da...@gmail.com>:
--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。


daisuke

unread,
Jul 11, 2011, 9:03:31 PM7/11/11
to 日本Androidの会
菅野さん

安藤です。
返信いただきありがとうございます!
なるほど、onCreateでダミーのタブ、試していませんでした。。

手元で確認できる端末が2.3系なのですが(でもfroyoベースで開発している、という。。)、いただいたようにonCreateでダミータブを入れ
てから
handlerで更新をかけてみましたが、状況は変わらず表示が更新されたりされなかったり、となりました。。
不思議ですね。。。
なお、ダミータブをVISIBLEにしておくとその情報が表示されるので、onCreate時点では更新が効く状態(100%成功する)ではあるようで
す。

stack overflowあたりでよく話題になっていますが、どうもTabActivityはバグが多いというか、仕様が安定していない雰囲気です
ね。。
(ちなみに私の実装は1つのTabActivityで全タブを処理する方式としています。handlerで処理するデータで全ての情報がまかなえるた
め)
ソースを見た方が早い気がしてきました。。

最悪タブのようなレイアウトを自前で構築してTabActivityの利用を止める、という方が解決が早いかもしれません。
とはいえもう少し試行錯誤してみます。みなさんにもよいフィードバックができるとよいですが。。

なお更新しようとしている画面のレイアウトですが、YouTubeの動画画面(縦)に近いです。
動画の代わりにImageViewで画像を表示しようとしています(この画像もUIとは別スレッド、handlerで取得したデータを元にwebから取
得します)。
画面中央~下段にタブコンテンツ(YouTubeでは動画の詳細情報などが表示されますね)を配置するようなレイアウトです。

また何かありましたら是非お知らせいただければ幸いです。
よろしくお願いいたします。


On 7月11日, 午後11:03, yoshiyuki kanno <nekota...@gmail.com> wrote:
> 菅野です。
>
> 安藤さんのケースとは若干異なるかもしれませんが、
> TabActivityのタブをonCreate以外の場所で動的に作成する必要があったのですが(ネットワーク通信結果によってタブの内容が変わる)、
> 1.x系だと途中でNullぽで落ちる、2.x系だと表示されない場合がある、といった症状に遭遇した事があります。
>
> どうやらonCreateで最低でも一つのTabコンテンツが作成されている前提があるようだったので、
> onCreateではダミーのタブを作成しておき、以下のように非表示にしておきました。
>
> TabHost tabHost = getTabHost();
> tabHost.addTab(tabHost.newTabSpec("dummy").setIndicator("dummy").setContent (new
> Intent().setClass(HogeTabActivity.this, HogeContentActivity.class)));
> tabHost.setCurrentTab(0);
> tabHost.setVisibility(View.INVISIBLE);
>
> で、handlerで通信結果を受け取ったら
>
> tabHost.clearAllTabs();
> tabHost.setVisibility(View.VISIBLE);
> // 以下でaddTabするコード
>
> のように非表示のダミーを削除後に、コンテンツを追加で無事期待通りの動作にいきつきました。
>
> 参考になれば幸いです。
>
> 2011年7月11日22:19 daisuke <do.dais...@gmail.com>:

yoshiyuki kanno

unread,
Jul 11, 2011, 9:40:33 PM7/11/11
to android-g...@googlegroups.com
安藤さん
おつかれさまです。菅野です。

駄目でしたか。残念です。

>ソースを見た方が早い気がしてきました。。
最低でもframework/base.gitのソースはステップ実行できる状態にしておくと良いと思います。
TabActivityの独特の挙動もそれで割りと短時間で解決できたので。

検討いのってます

2011年7月12日10:03 daisuke <do.da...@gmail.com>:

yoshiyuki kanno

unread,
Jul 11, 2011, 11:54:31 PM7/11/11
to android-g...@googlegroups.com
安藤さん
おつかれさまです。菅野です。

ちょっと時間が取れたのでデバッグしてみましたが、1.x系だと
おそらく安藤さんが使われているTabContentFactoryによるViewの生成、破棄まわりにバグがありました。
(破棄する際にView.GONEではなく、View.INVISIBLEになっているため、別のタブに切り替えた際にコンテンツが表示されない)

ただ2系では直っていたので、これじゃーないっぽいですね。

ちなみにTabContentFactoryをどのように使ってますか?
自前でViewをコードで作成してるはずですよね。
このコードに問題があるような気もします。

#可能であれば、他の方法(リソースIDを使う方法か、Activityを使う方法)を試してみては?

2011年7月12日10:03 daisuke <do.da...@gmail.com>:

daisuke

unread,
Jul 12, 2011, 1:28:11 AM7/12/11
to 日本Androidの会
菅野さん

安藤です。ありがとうございます!
ようやくeclipse上でandroidソースをattachできたので、追いかけてみようと思います。

何か分かれば(分からなくても。。)レポートさせていただきますね。

よろしくお願いいたします。


On 7月12日, 午前10:40, yoshiyuki kanno <nekota...@gmail.com> wrote:
> 安藤さん
> おつかれさまです。菅野です。
>
> 駄目でしたか。残念です。
>
> >ソースを見た方が早い気がしてきました。。
> 最低でもframework/base.gitのソースはステップ実行できる状態にしておくと良いと思います。
> TabActivityの独特の挙動もそれで割りと短時間で解決できたので。
>
> 検討いのってます
>
> 2011年7月12日10:03 daisuke <do.dais...@gmail.com>:

daisuke

unread,
Jul 12, 2011, 2:31:11 AM7/12/11
to 日本Androidの会
菅野さん

安藤です。検証いただきありがとうございます!
ご質問のTabContentFactoryですが、以下のように使っています。
(コード全ては載せられないので。。部分抜粋しています。)

public class HogeActivity extends TabActivity implements
TabContentFactory {

private TabHost tabHost;
private Handler handler;
private LayoutInflater inflater;
private Map<String, Item> tagItems;
// その他、各種レイアウト、Viewをメンバに持ちます。

// サービスとのやり取りですが、AIDLを使っているので少し分かりづらいです。(処理内容をはしょってますし。。)
// 要するに、webからのレスポンスが返ってきたらcallbackで「handleResponse()」が呼ばれる、という流れで
す。
// ついでにサービスとの接続が確立したら(onServiceConnected())、webへリクエストしてます。(内部は記載しませ
んが。。)
private HogeService hogeService;
private ServiceConnection con = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder
service) {
hogeService= WebappComService.Stub.asInterface(service);
try {
hogeService.registerCallback(callback);
} catch (RemoteException e) {
Log.e(TAG, e.toString(), e);
}
requestData2Web();
}

@Override
public void onServiceDisconnected(ComponentName name) {
try {
hogeService.unregisterCallback(callback);
} catch (RemoteException e) {
Log.e(TAG, e.toString(), e);
}
hogeService= null;
}
};
private ResponseListener callback = new ResponseListener.Stub() {
@Override
public void onResponse(Response response) throws
RemoteException {
handleResponse(response);
}
};

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hoge);

handler = new Handler();
inflater = (LayoutInflater)
getSystemService(LAYOUT_INFLATER_SERVICE);
tagItems = new HashMap<String, Item>();
tabHost = getTabHost();

// ここでダミータブを生成しましたが、うまくいきませんでした。

// メンバに持っている各種ViewをfindViewById(int)で生成

// これは100%更新されます。
String hogeText = getIntent().getStringExtra("key");
hogeTextView.setText(hogeText);

}

protected void onStart() {
super.onStart();
bindService(...);
}

protected void onStop() {
unbindService(...);
}

private void requestData2Web() {
// サービスにリクエスト処理を委譲してます。
}

// このメソッドを呼び出すスレッドはサービスからのcallbackになるためUIとは別スレッドです。
private void handleResponse(Response response) {
handler.post(new Runnable() {
tabHost.clearAllTabs();
// tabHost.setVisibility(View.VISIBLE);

// 画像のダウンロード(非同期)
imageDownloader.download(response.getUri(), imageView);
// ここでメンバに持っているViewの更新処理をしています。
// textView.setText(response.getText());といった処理です。

// タブを作成して、作成に必要なデータをメンバ変数に保持します。
for (Item i : response.getItems()) {
String tag = i.getTag();
tagItems.put(tag, i);
TabSpec spec =
tabHost.newTabSpec(tag).setIndicator(tag).setContent(HogeActivity.this);
tabHost.addTab(spec);
}
tabHost.setCurrentTab(0);
});
}

@Override
public View createTabContent(String tag) {
Item item = gagItems.get(tag);
LinearLayout layout = (LinearLayout)
inflater.inflate(R.layout.fuga, null);
// layoutから必要なViewをfindViewById(int)で生成します。

TextView fugaTextView = (TextView)
layout.findViewById(R.id.fugaText);
fugaTextView.setText(item.getFugaText());

return layout;
}

}


ちょっとおおざっぱですが、だいたい意図は伝わるのではないかな、と思っています。
このActivityが呼び出され(Intentで別のActivityから起動されます)、webからのレスポンスがある度に
createTabContent(String)は
呼ばれるようになったのですが(handler.postでclearAlltabsをしたことで)、肝心のデータ(View)が描画されないので
す。。
タブ自体も見えない状態(INVISIBLEというよりはGONEな状態)です。
handler.postの中で、タブとは別の場所にあるImageView(その他TextViewなどもありますが)を更新しているのですが、こち
らも更新がかかりません。

タブをActivityにすることもありかな、と思うのですが、タブの数がwebからのレスポンスデータによって不定なので、今のところこのような形を
取っています。。

何かおかしな点があれば是非ご指摘いただければ助かります。
よろしくお願いいたします。
(これからandroidソース追いかけたりしてみます。。)



On 7月12日, 午後12:54, yoshiyuki kanno <nekota...@gmail.com> wrote:
> 安藤さん
> おつかれさまです。菅野です。
>
> ちょっと時間が取れたのでデバッグしてみましたが、1.x系だと
> おそらく安藤さんが使われているTabContentFactoryによるViewの生成、破棄まわりにバグがありました。
> (破棄する際にView.GONEではなく、View.INVISIBLEになっているため、別のタブに切り替えた際にコンテンツが表示されない)
>
> ただ2系では直っていたので、これじゃーないっぽいですね。
>
> ちなみにTabContentFactoryをどのように使ってますか?
> 自前でViewをコードで作成してるはずですよね。
> このコードに問題があるような気もします。
>
> #可能であれば、他の方法(リソースIDを使う方法か、Activityを使う方法)を試してみては?
>
> 2011年7月12日10:03 daisuke <do.dais...@gmail.com>:
> ...
>
> もっと読む ≫

daisuke

unread,
Jul 12, 2011, 8:15:35 AM7/12/11
to 日本Androidの会
さらに追記です。

更新しようとしている画面のレイアウトが

TabHost
- ScrollView
+ LinearLayout
* TextView
* ImageView
* etc...
+ TabWidget
+ FrameLayout
* tabcontents...

という形なので、何か切り分けできないかと思い以下のように変更して、TabActivityではなくActivityを継承するように変更してみまし
た。

LinearLayout
- ScrollView
+ LinearLayout
* TextView
* ImageView
* etc...
+ TabHost
* TabWidget
* FrameLayout
~ tabcontents...

Activity内はgetTabHost()していたところを、findViewById(); tabHost.setup();で差し替えてみま
した。

この場合でも、今までと同様Intentによって先に更新されるViewは画面更新され、あとからhandler.post
更新されるViewはタブ含めて更新されないことが分かりました。

であれば、TabActivityというよりも、handlerの使い方か、Activityの使い方に問題があるような気がしています。

毎度途中経過ばかりで心苦しいですが、以上となります。
> ...
>
> もっと読む ≫

yoshiyuki kanno

unread,
Jul 12, 2011, 9:36:13 AM7/12/11
to android-g...@googlegroups.com
菅野です。

提示いただいたコードを見る限りだと問題なさそうに見えますね。。。

とりあえず、
・ViewのonDrawが呼ばれるているか、ステップ実行で確認する。(多分、これで原因がわかると思います)
をしてみる事をお勧めします。

後は、onCreateが走らなくても(pauseかstop状態からの復帰)、問題のないロジックになっているか?
もちょっと気になります。

2011年7月12日21:15 daisuke <do.da...@gmail.com>:
> ...
>
> もっと読む ≫

daisuke

unread,
Jul 13, 2011, 6:15:25 AM7/13/11
to 日本Androidの会
菅野さん

安藤です。確認いただきありがとうございました。

> 提示いただいたコードを見る限りだと問題なさそうに見えますね。。。

そうですか。。ありがとうございます。少しずつ確認するしかなさそうですね。。

ViewのonDrawに関してですが、androidのソースのattachがうまくいっておらず(エミュレータのバージョンとattachした
バージョンがなかなか合わず)苦労しましたが、ようやくステップ実行できるようになりました。

現状、TabHostの(正確にはViewGroupの)drawChildで止めて確認しているところです。
分かった点は、handler.postで設定したコンテンツについて、新たに追加したもの(タブのコンテンツ。
createTabContentでインフレートしたもの)についてはそもそもchildの中に入ってこない、
もともと(onCreateで)枠だけ生成されているViewについてはsetされた(したはずの)
データが入ってきていないため、View.drawが実行されても表示するデータがない、という状態のようです。
#だから何も画面が更新されない、ということの検証ができたような状況ですね。。

不思議ですね。。
この後はViewGroupのビューツリー構築処理あたりを見てみようと思います。
(内部過ぎて見えないかな・・・?)
post後にViewを追加するとうまくいかなくなってしまうパターンがあるのかな・・・?

なおpostの前にtabHost.postInvalidate()、postの最後にtabHost.invalidate()を入れてみましたが
変わらず。。でした。
また報告させていただきます。



On 7月12日, 午後10:36, yoshiyuki kanno <nekota...@gmail.com> wrote:
> 菅野です。
>
> 提示いただいたコードを見る限りだと問題なさそうに見えますね。。。
>
> とりあえず、
> ・ViewのonDrawが呼ばれるているか、ステップ実行で確認する。(多分、これで原因がわかると思います)
> をしてみる事をお勧めします。
>
> 後は、onCreateが走らなくても(pauseかstop状態からの復帰)、問題のないロジックになっているか?
> もちょっと気になります。
>
> 2011年7月12日21:15 daisuke <do.dais...@gmail.com>:
> ...
>
> もっと読む ≫

daisuke

unread,
Jul 13, 2011, 7:00:53 AM7/13/11
to 日本Androidの会
あ、ちなみにonPauseやonStop、onResumeやonStartといったメソッドについては今のところ全く考慮していません。。
一応、詳細画面から一覧画面に戻ったときにonDestroyが呼ばれて、一覧から詳細に再度遷移するときにonCreateが
呼ばれていることは確認しながら実行しています。。


On 7月12日, 午後10:36, yoshiyuki kanno <nekota...@gmail.com> wrote:
> 菅野です。
>
> 提示いただいたコードを見る限りだと問題なさそうに見えますね。。。
>
> とりあえず、
> ・ViewのonDrawが呼ばれるているか、ステップ実行で確認する。(多分、これで原因がわかると思います)
> をしてみる事をお勧めします。
>
> 後は、onCreateが走らなくても(pauseかstop状態からの復帰)、問題のないロジックになっているか?
> もちょっと気になります。
>
> 2011年7月12日21:15 daisuke <do.dais...@gmail.com>:
> ...
>
> もっと読む ≫

yoshiyuki kanno

unread,
Jul 13, 2011, 11:54:55 AM7/13/11
to android-g...@googlegroups.com
菅野です。

>ViewのonDrawに関してですが、androidのソースのattachがうまくいっておらず(エミュレータのバージョンとattachした
>バージョンがなかなか合わず)苦労しましたが、ようやくステップ実行できるようになりました。
とりあえず一歩前進ですね(^^

>もともと(onCreateで)枠だけ生成されているViewについてはsetされた(したはずの)

>データが入ってきていないため、View.drawが実行されても表示するデータがない、という状態のようです。
>#だから何も画面が更新されない、ということの検証ができたような状況ですね。。
例えばTextViewがあるなら、setTextでブレークしてステップしてみてください。
見た目に影響を与えるメソッドは、ほぼ例外なく内部でinvalidateするので、
Viewを更新するインタフェースの入り口でブレークすることで、その呼び出し前後どちらに問題があるのか判断できると思います。

2011年7月13日19:15 daisuke <do.da...@gmail.com>:
> ...
>
> もっと読む ≫

yoshiyuki kanno

unread,
Jul 13, 2011, 11:59:48 AM7/13/11
to android-g...@googlegroups.com
>あ、ちなみにonPauseやonStop、onResumeやonStartといったメソッドについては今のところ全く考慮していません。。
>一応、詳細画面から一覧画面に戻ったときにonDestroyが呼ばれて、一覧から詳細に再度遷移するときにonCreateが
>呼ばれていることは確認しながら実行しています。。
あ、これはちょっと自分が思っていたのと違う挙動ですね。。。

>またTabActivityのcreateTabContent()メソッドが呼び出されなかったのはhandler.post()内で
>addTab()していることに起因するようで、
以上のような説明があったので、これが呼び出されないケースってすでに
createTabContent()が呼び出されてViewがFactoryクラスにキャッシュされているケースなんですよね。
なので、Activityはリサイクルされているのかな?と思っていました。

ちょっと気になりますね。

2011年7月13日20:00 daisuke <do.da...@gmail.com>:
> ...
>
> もっと読む ≫

daisuke

unread,
Jul 13, 2011, 10:27:45 PM7/13/11
to 日本Androidの会
菅野さん

安藤です。
長々とお付き合いいただき本当にありがとうございます。

> 以上のような説明があったので、これが呼び出されないケースってすでに
> createTabContent()が呼び出されてViewがFactoryクラスにキャッシュされているケースなんですよね。
> なので、Activityはリサイクルされているのかな?と思っていました。

そうなんです、launchModeは"standard"なので、基本的に常にTabActivityがnewされると思っていましたが、
onCreateが呼び出されるにも関わらず、このcreateTabContentが呼ばれない、という点がものすごくひっかかっていました。
実はTabActivityがnewされていないんじゃないか、あるいはViewのどれかがどこかにキャッシュされているのでは、と。

取り急ぎですが、原因だけがはっきりしました。(ようやく。。。)
ポイントは全く別のところにあり、webとの通信処理を委譲しているサービスとのやり取りの部分でおかしな動きになっています。

一部抜粋ですがコードを記載させていただいた際、サービスからcallbackされる、という処理があったかと思います。
ここで、場合によってサービスから呼び出されるActivityのインスタンスが古いことがある、ということが判明しました。
(ResponseListener.onResponseが呼び出されるインスタンス)

一覧画面→詳細画面(インスタンスA)→一覧画面(バックキー)→詳細画面(インスタンスB)

この流れで、インスタンスBでサービスから呼び出されるはずのcallbackを処理するオブジェクトが何故かインスタンスAに
なることがあるようです。
まさかここで引っかかっているとは思いもせず。。

まだ、どうやって修正したものか検討/調査しているところですが、この問題についても同じような状況にある人もいるかと
思いますので、解決したら(するまで)引き続きレポートさせていただきます。。


On 7月14日, 午前12:59, yoshiyuki kanno <nekota...@gmail.com> wrote:
> >あ、ちなみにonPauseやonStop、onResumeやonStartといったメソッドについては今のところ全く考慮していません。。
> >一応、詳細画面から一覧画面に戻ったときにonDestroyが呼ばれて、一覧から詳細に再度遷移するときにonCreateが
> >呼ばれていることは確認しながら実行しています。。
> あ、これはちょっと自分が思っていたのと違う挙動ですね。。。
>
> >またTabActivityのcreateTabContent()メソッドが呼び出されなかったのはhandler.post()内で
> >addTab()していることに起因するようで、
> 以上のような説明があったので、これが呼び出されないケースってすでに
> createTabContent()が呼び出されてViewがFactoryクラスにキャッシュされているケースなんですよね。
> なので、Activityはリサイクルされているのかな?と思っていました。
>
> ちょっと気になりますね。
>
> 2011年7月13日20:00 daisuke <do.dais...@gmail.com>:
> ...
>
> もっと読む ≫

yoshiyuki kanno

unread,
Jul 14, 2011, 1:49:44 AM7/14/11
to android-g...@googlegroups.com
菅野です。

なるほどですね。謎は全て解けたかもしれません。

>ここで、場合によってサービスから呼び出されるActivityのインスタンスが古いことがある、ということが判明しました。
onDestroy -> onCreateのライフサイクルを辿ったとしても、Activityインスタンス自体は再利用される事があるんです。
なので、これら一連のライフサイクル間で呼び出されるコールバックメソッドで初期化してないインスタンス変数は、
そのまま残る事があります。
というわけでサービスとのバインドに関連するインスタンス変数が、完全に初期化されてないのが原因ぽいですね。

#あとは単純に詳細画面のlaunchモードをsingleInstanceにしてしまうのが手っ取り早いかもしれません。

2011年7月14日11:27 daisuke <do.da...@gmail.com>:
> ...
>
> もっと読む ≫

daisuke

unread,
Jul 14, 2011, 2:44:31 AM7/14/11
to 日本Androidの会
安藤です。

> onDestroy -> onCreateのライフサイクルを辿ったとしても、Activityインスタンス自体は再利用される事があるんです。
> なので、これら一連のライフサイクル間で呼び出されるコールバックメソッドで初期化してないインスタンス変数は、
> そのまま残る事があります。

なるほど。。そういうことでしたか。てっきりnewされているのかと思いきや。。
それでインスタンス変数の初期化で安心せずに、onCreateで初期化するように、といった注意も見かけるわけですね。
組み込みらしい仕組みですね。(組み込みの経験がないのでこのあたりの仕掛けになかなか慣れないです。)

> というわけでサービスとのバインドに関連するインスタンス変数が、完全に初期化されてないのが原因ぽいですね。

なるほど、上記を踏まえるとこのような可能性もありますね。
サービスからcallbackを登録した元のインスタンス(Activity)をどうやって特定しているんだろう?というところを主に
調べていました。

onDestroyしたときのActivity.toStringのhash codeとonCreate時のhash codeが違うので、別のイン
スタンスだろうと
思います。サービス内部でRemoteCallbackListを利用しているのですが、このあたりが怪しいのかな、と。。
ServiceConnectionのあたりも調べた方がよさそうですね。

ちなみに、詳細画面のlaunchモード、singleinstanceにしてみたのですが、一度表示して一覧に戻り、再度詳細画面を
表示するとhash codeが異なるので、どうもnewされているような雰囲気です。一覧はstandardにしているので同じタスク
だと思っているのですが。
(そのおかげでやはりViewが表示されないわけですが)

ここはまだちょっと動きが謎ですね。。


On 7月14日, 午後2:49, yoshiyuki kanno <nekota...@gmail.com> wrote:
> 菅野です。
>
> なるほどですね。謎は全て解けたかもしれません。
>
> >ここで、場合によってサービスから呼び出されるActivityのインスタンスが古いことがある、ということが判明しました。
> onDestroy -> onCreateのライフサイクルを辿ったとしても、Activityインスタンス自体は再利用される事があるんです。
> なので、これら一連のライフサイクル間で呼び出されるコールバックメソッドで初期化してないインスタンス変数は、
> そのまま残る事があります。
> というわけでサービスとのバインドに関連するインスタンス変数が、完全に初期化されてないのが原因ぽいですね。
>
> #あとは単純に詳細画面のlaunchモードをsingleInstanceにしてしまうのが手っ取り早いかもしれません。
>
> 2011年7月14日11:27 daisuke <do.dais...@gmail.com>:
> ...
>
> もっと読む ≫

daisuke

unread,
Jul 14, 2011, 3:52:08 AM7/14/11
to 日本Androidの会
安藤です。

問題が解決しましたのでご報告させていただきます。

ActivityとServiceとのやり取りで、Service→Activityのデータ受け渡しに使っているcallbackですが、これの
unregisterを明示的に
呼び出すことで解決しました。
ActivityのonStopでunbindServiceを呼び出しているのですが、この際に自動的にunregisterされると勝手に勘違いし
ておりました。

unregisterしていなかったため、Service内で保持しているcallback list内にcallbackが保持され続け、新しい
Activityが登録した
callbackが呼び出されたり、残っていたcallbackが呼び出されたりしていたのだと思います。

初期の質問からずいぶん離れたところの解決となってしまいましたが、以上となります。

>菅野さん
私の目の付け所が悪かったせいで、デバッグ/検証等、手を動かすことまでやっていただき大変心苦しいです。。
最後までお付き合いいただき、本当にありがとうございました。
おかげさまで、情報を整理しながら解決までこぎ着けることができましたし、androidのソースを読み、内部で細かくデバッグ
したりと、今後の開発にも大変有用となる知識を得ることができました。
また質問することもあると思いますが、私からも何らかフィードバックできることがあればやっていきたいなと思います。

以上です。
> ...
>
> もっと読む ≫

yoshiyuki kanno

unread,
Jul 14, 2011, 8:01:08 AM7/14/11
to android-g...@googlegroups.com
安藤さん
菅野です。

おお、解決おめでとうございます。
自分もまだandroid歴4ヶ月の若輩者ですので
今回のやり取りを通して色々と勉強になっています!
のであまり気にせず、今後も相互扶助の精神でがんばりましょー。

2011年7月14日16:52 daisuke <do.da...@gmail.com>:
> ...
>
> もっと読む ≫

Reply all
Reply to author
Forward
0 new messages