【教えてください】Activity起動遅延の原因について

1,884 views
Skip to first unread message

micco

unread,
Aug 29, 2010, 3:57:47 AM8/29/10
to 日本Androidの会
こんにちは。
miccoです。

ある記録を保存するアプリを作っています。
あらかじめ設定している最大件数(SharedPreferenceで約20,000件)が登録されたときの
挙動を確かめるために、ダミーデータを生成して保存してみました(2MB程度)。

そうしたときに、トップ画面のメニューボタンを押下して、新たなActivityを起動すると、少し
タイムラグがあって画面が表示されるようになりました。
ただ、アプリ起動直後の1回のみ発生し、アプリ内で画面遷移(Activity起動)を繰り返して
も発生しません(同じトップ画面のメニューボタンも同様)。
また、一度アプリを終了させて、すぐに再起動した場合は発生しませんが、他のアプリを
触って再起動した場合には発生します。

LogCatでActivityManagerの情報が表示されますが、
「Displayed activity パッケージ名/クラス名:6242ms(total 6242ms)」
のような表示がなされています。6秒かかっているということでしょうか。
問題ないときは100ms程度になっています。

保存データを全て削除すると再現しません。
原因が分からず困っていますので、どなたかお気づきの点があれば、ご教示ください。

テスト機種はIS01です。
よろしくお願いいたします。

丹羽直也

unread,
Aug 29, 2010, 4:07:49 AM8/29/10
to android-g...@googlegroups.com
> ある記録を保存するアプリを作っています。
> あらかじめ設定している最大件数(SharedPreferenceで約20,000件)が登録されたときの
> 挙動を確かめるために、ダミーデータを生成して保存してみました(2MB程度)。
>
> そうしたときに、トップ画面のメニューボタンを押下して、新たなActivityを起動すると、少し
> タイムラグがあって画面が表示されるようになりました。

その大量のデータを読み込んで、メモリに展開するのに時間がかかってるようです。

> ただ、アプリ起動直後の1回のみ発生し、アプリ内で画面遷移(Activity起動)を繰り返して
> も発生しません(同じトップ画面のメニューボタンも同様)。
> また、一度アプリを終了させて、すぐに再起動した場合は発生しませんが、他のアプリを
> 触って再起動した場合には発生します。

AndroidのドキュメントのActivityのライフサイクルの部分
http://developer.android.com/intl/ja/reference/android/app/Activity.html#ActivityLifecycle
(英語ですがぐぐると日本語訳があるはずですし、Android開発の書籍にもあります)
を読むと分かりますが、Activityは生成後、他のActivityやサービスなどでメモリが不足し、足りなくなったときに破棄されます。ですので、他の操作をしていると、メモリ不足で破棄されて作り直し(OnCreate)となるわけです。
他にも細かい動作はありますが概要はこんな感じです。

もしそれを改善するのであれば、読み込み時にプログレス(あのくるくる回るやつ)を使って「読込中」とするのがいいのではないのでしょうか?

>
> LogCatでActivityManagerの情報が表示されますが、
> 「Displayed activity パッケージ名/クラス名:6242ms(total 6242ms)」
> のような表示がなされています。6秒かかっているということでしょうか。
> 問題ないときは100ms程度になっています。
>
> 保存データを全て削除すると再現しません。
> 原因が分からず困っていますので、どなたかお気づきの点があれば、ご教示ください。
>
> テスト機種はIS01です。
> よろしくお願いいたします。
>

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

--
灘校パソコン研究部-Nada Personal Computer Users' Association
Naoya Niwa
MyBlog  Mine's Blog: http://mines-blogn.blogspot.com/
Twitter: @mine_studio
http://twitter.com/mine_studio

mosaki4

unread,
Aug 29, 2010, 4:32:12 AM8/29/10
to android-g...@googlegroups.com
大崎といいます

>SharedPreferenceで約20,000件
というのが問題のような気がします

その20000件のデータを一度に読み込んで処理する必要がないなら
(計算をするにしても1件づつループで可能と思われます)
SQLiteで保存したほうがいいと思います。

2010年8月29日16:57 micco <gou...@gmail.com>:

micco

unread,
Aug 29, 2010, 9:41:42 AM8/29/10
to 日本Androidの会
こんばんは。
miccoです。

>丹羽さん、大崎さん
早速のコメントありがとうございます。


トップ画面から呼び出したActivityでは、全部ではなく、一部のキー&バリュー(50組程度)しか
getInt()等で読み込んでいないので、画面がフリーズするほどの重い処理ではないと思ってい
ました。

getSharedPreferences()は、データファイルにアクセスするインターフェースのようなものとイメ
ージして使っていましたが、このgetSharedPreferences()で得られるインスタンスは、そのプリフ
ァレンス名で保存されているXMLファイル自体を取り込んでいるのかもしれません。
それが正しいなら、getInt()等で読み込むキー&バリューの量に関係なく、全体の永続化デー
タ量に比例して、プリファレンスインスタンスを生成する処理(メモリアサイン)が重くなるため、
このような遅延が発生する原因にもなり得ます。

現在は、すべてのキー&バリューを一つのプリファレンス名で永続化していますので、一つの
解決方法は、不要なキー&バリューを取り込まないよう、プリファレンス名を細かく設定して永
続化することかもしれません。

SQLiteは使ったことがないため、OpenSocailアプリで慣れたキー&バリュー形式での永続化を
前提に作っていましたので、幾つか作った記録系アプリを全て同じ設計にしています。。。
アプリ間で共有するデータでも無いため、SQLiteを勉強して実装しても良いのですが、大改造
になるので、まずはプリファレンス名の分散化を試してみようと思っています。

SQLiteを使った場合でもDBファイルの読み込みは発生しそうですが、同じような問題を惹起す
ることは無いと考えて良いでしょうか?今後のためにご教授ください。

以上、よろしくお願いいたします。
> > このグループから退会するには、android-group-j...@googlegroups.com<android-gro-up-japan%2Bunsu...@googlegroups.com>にメールを送信してください。
> > 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

yokmama

unread,
Aug 29, 2010, 10:07:17 AM8/29/10
to android-g...@googlegroups.com

夜子ままです、

Preferenseの分散化よりsqlのほうが実装のコストが楽じゃないのかな、

まずはデータにアクセスする部分をカプセル化してpreferenseでもsqlでも実装できるようにするような修正の進め方をすると相互で動作確認できるのでいいですよ

2010/08/29 22:41 "micco" <gou...@gmail.com>:

> ...

> 2010年8月29日16:57 micco <gou...@gmail.com>:

>
>
>
> > こんにちは。
> > miccoです。
>
> > ある記録を保存するアプリを作っています。
> > あらかじめ設定している最大件数(SharedPreferenceで約20,00...

> > このグループから退会するには、android-group-j...@googlegroups.com<android-gro-up-japan%2Bunsu...@googlegroups.com>にメールを送信してください。
> > 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。- 引用テキストを表示しない -
>
> - 引用テキストを表示 -


--

このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。

このグループに投稿するには、android-g...@googlegroups.com...

micco

unread,
Aug 30, 2010, 9:25:15 AM8/30/10
to 日本Androidの会
こんばんは。
miccoです。

夜子ままさん、いつもありがとうございます。

遅延だけなら、例のAsyncTaskでプログレスダイアログを表示して対
応しても良さそうですが、データ量が大きくなると、インスタンス生成で
Out Of Memoryになる場合もありそうですので、素直にSQLiteで実装
した方が良さそうですね。。。

最初にSQLiteを使うかプリファレンスで実現するか迷ったのですが、
プリファレンスでも支障はないんじゃないかと安易に判断しました。
プリファレンスを使って4種類の記録系アプリを作ってしまいましたので、
これら全てに再度手を入れるのは億劫になります;;

引き続きよろしくお願いします。

On 8月29日, 午後11:07, yokmama <hijirinhiji...@gmail.com> wrote:
> 夜子ままです、
>
> Preferenseの分散化よりsqlのほうが実装のコストが楽じゃないのかな、
>
> まずはデータにアクセスする部分をカプセル化してpreferenseでもsqlでも実装できるようにするような修正の進め方をすると相互で動作確認できるので-いいですよ
> <android-gro-up-japan%2Bunsu...@googlegroups.com<android-gro-up-japan%2-52Buns...@googlegroups.com>>にメールを送信してください。

yokmama

unread,
Aug 30, 2010, 9:44:54 AM8/30/10
to android-g...@googlegroups.com
夜子ままです

これは私がよく使う方法なので必ずしもベストというわけではないですが
参考程度に


まずロジック部分とデータ処理部分を分ける作業を考えます、
そのために、データを保持するクラスを JavaBeanにします。

JavaBeanにはGetとSetを設定しデータへのアクセスを実装させます。
ロジック部分ではこのBean経由でデータをアクセスすることになります。

そして、データの書き込み、読込み、検索はこのBeanを引数に渡すようにします。
例えばですが、

現在Preferenceを使われているならば、PreferenceからGetしている部分とPutしている
部分を全てやめて、とあるクラスで全部やらせるように修正します、
そして、利用側はBeanのみで受け取ったり渡したりするようにする。
この修正をするだけなら機能的には変わらなくてコードのみでかわるので必ず動くはずです。
というか動くようになるように実装しましょう。

例として

class Car {
   Map map;
   String getName(){ return map.get("name");}
   void setName(String s){ map.put("name", s);}
}

public class DataBase {

 public DataBase(Preference p){
   }

 public List<Car> getCarList(){
     ///Preference からCarのデータをとってきてCarのListを構築して返却する
   return list;
 }

 public void addCar(Car c){
  ///Preference にCarを追加する
 }

}


このようにするとロジックからはその先がPreferenceだろうがSQLだろうがどっちでもよくなります。
このような状態にしてからSQLLiteに変更をすれば比較的楽に移行できますよ。

ちょっと概念的でわかりにくかもしれません、分からない点があればまた質問してください。


2010年8月30日22:25 micco <gou...@gmail.com>:

egg

unread,
Aug 30, 2010, 10:01:56 AM8/30/10
to android-g...@googlegroups.com

miccoさん

江川です。
> getSharedPreferences()で得られるインスタンスは、そのプリフ
> ァレンス名で保存されているXMLファイル自体を取り込んでいるのかもしれません。
おっしゃる通りです。ファイルが大きくなればリニアに処理時間が長くなり使用するメモリ量が増えます。ファイルを分割すれば対象が小さくなるので軽減できます。

> SQLiteを使った場合でもDBファイルの読み込みは発生しそうですが、同じような問題を惹起す
> ることは無いと考えて良いでしょうか?今後のためにご教授ください。
SQLiteを使っていても、全部を読み込めば時間がかかるかもしれませんしメモリを圧迫するかもしれません。
Cursorを使って必要なだけをfetchするようにすれば回避できます。

よろしくお願いします。

------------------------------------------
EGAWA Takashi

2010/8/29 micco <gou...@gmail.com>:

micco

unread,
Aug 31, 2010, 9:22:35 AM8/31/10
to 日本Androidの会
江川さん

こんばんは。
miccoです。

疑問に答えて頂いてありがとうございます!
SQLiteならCursorを使って必要なレコードだけ取り出せば問題なさそうですね。
最初にきちんと理解しておけば良かったです。
> <android-gro-up-japan%2Bunsu...@googlegroups.com<android-gro-up-japan%2-52Buns...@googlegroups.com>>にメールを送信してください。
> >> > 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。-
>
> 引用テキストを表示しない -
>
>
>
>
>
> >> - 引用テキストを表示 -
>
> > --
> > このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> > このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> > このグループから退会するには、android-group-j...@googlegroups.com<android-gro-up-japan%2Bunsu...@googlegroups.com>にメールを送信してください。
> > 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。- 引用テキストを表示しない -
>
> - 引用テキストを表示 -- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

micco

unread,
Aug 31, 2010, 9:13:57 AM8/31/10
to 日本Androidの会
夜子ままさん

こんばんは。
miccoです。

アドバイスありがとうございます!
データへのアクセス部分を部品化してしまうということですね。
SQLiteも勉強しながら少しずつ試してみようと思います。
> > まずはデータにアクセスする部分をカプセル化してpreferenseでもsqlでも実装できるようにするような修正の進め方をすると相互で動作確認できるので--いいですよ
> > > <android-gro-up-japan%2Bunsu...@googlegroups.com<android-gro-up-japan%2-52Buns...@googlegroups.com>
> > <android-gro-up-japan%2-52Buns...@googlegroups.com<android-gro-up-japa-n%252-52Bun...@googlegroups.com>
> > >>にメールを送信してください。
> > > > > 詳細については、http://groups.google.com/group/android-group-japan?hl=ja
> > からこのグループにアクセスしてください。-
>
> > > 引用テキストを表示しない -
>
> > > > - 引用テキストを表示 -
>
> > > --
>
> > > このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> > > このグループに投稿するには、android-g...@googlegroups.com...
>
> > --
> > このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> > このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> > このグループから退会するには、android-group-j...@googlegroups.com<android-gro-up-japan%2Bunsu...@googlegroups.com>にメールを送信してください。

micco

unread,
Sep 2, 2010, 10:09:29 AM9/2/10
to 日本Androidの会
こんばんは。
miccoです。

以下のようなDBManegerというクラスを定義し、DB生成、挿入、更新、検索等を行う形で
実装しているところです(挿入等のメソッドは省略)。
各ActivityでDBManegerのインスタンスを生成していますが、DB操作を終えたらcloseメソ
ッドを呼び出し、再度DBを操作する際にgetWritableDatabaseメソッドを呼び出してdbを取
得しています。

SQLiteOpenHelperインスタンスは最初に生成したまま継続利用しています。
DBのopenとcloseは、この方法で正しいでしょうか?

実機で動いていますので、問題なさそうに見えますが、勝手な思い込みで作るのは手戻り
が不安ですので、恐れ入りますが、ご教授頂ければと思います。

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

public class DBManeger
{
private SQLiteDatabase db;
private DBHelper dbHelper;

//コンストラクタ
public DBManeger(Context context)
{
dbHelper = new DBHelper(context);
}

private class DBHelper extends SQLiteOpenHelper
{
//コンストラクタ
public DBHelper(Context context)
{
super(context,DB,null,DB_VERSION);
}
//データベース生成
public void onCreate(SQLiteDatabase db)
{
db.execSQL(CREATE_TABLE);
}
//データベースアップグレード
public void onUpgrade(SQLiteDatabase db,int oldVersion,int
newVersion)
{
}
}

//データベースオープン
public void open()
{
db = dbHelper.getWritableDatabase();
}

//データベースクローズ
public void close()
{
db.close();
> > > まずはデータにアクセスする部分をカプセル化してpreferenseでもsqlでも実装できるようにするような修正の進め方をすると相互で動作確認できるので---いいですよ
> > > > > > このグループから退会するには、android-group-j...@googlegroups.com<android-gro--up-japan%2Bunsu...@googlegroups.com>
> > > <android-gro-up-japan%2Bunsu...@googlegroups.com<android-gro-up-japan%2--52Bun...@googlegroups.com>
>
> > > > <android-gro-up-japan%2Bunsu...@googlegroups.com<android-gro-up-japan%2--52Bun...@googlegroups.com>
> > > <android-gro-up-japan%2-52Buns...@googlegroups.com<android-gro-up-japa--n%252-52Bun...@googlegroups.com>
> > > >>にメールを送信してください。
> > > > > > 詳細については、http://groups.google.com/group/android-group-japan?hl=ja
> > > からこのグループにアクセスしてください。-
>
> > > > 引用テキストを表示しない -
>
> > > > > - 引用テキストを表示 -
>
> > > > --
>
> > > > このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> > > > このグループに投稿するには、android-g...@googlegroups.com...
>
> > > --
> > > このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
> > > このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
> > > このグループから退会するには、android-group-j...@googlegroups.com<android-gro--up-japan%2Bunsu...@googlegroups.com>にメールを送信してください。
> > > 詳細については、http://groups.google.com/group/android-group-japan?hl=jaからこのグループにアクセスしてください。- 引用テキストを表示しない -
>
> > - 引用テキストを表示 -- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

yokmama

unread,
Sep 2, 2010, 8:31:00 PM9/2/10
to android-g...@googlegroups.com
夜子ままです

特に悪い点はないと思います、

あえてどこかって、いうとしたら
dbHelperの呼出が常にgetWritableDatabaseになっている点かなぁ、
検索しかしないような場所ではRead専用のDBをオープンしておこうという
ケースもあります。
ほかには、、トランザクションの管理機能をいれたりとか、
とはいってもあまり最初からがちがちに実装してしまうと、使い勝手が悪くなるので
自分のプロジェクトにあった要件を満たす最低限の実装でいいとおもいます。

だからまずはやってみて、不都合がでたときに考えてもいいとおもいます。


2010年9月2日23:09 micco <gou...@gmail.com>:
このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。


micco

unread,
Sep 3, 2010, 9:51:05 AM9/3/10
to 日本Androidの会
こんばんは。
miccoです。

夜子ままさん、ありがとうございます。
挿入・更新・削除等のメソッドごとにgetWritableDatabase/getReadableDatabase
でDBを開いて処理した後、当該メソッド内でcloseするように記述しようと思います。
トランザクションの管理機能ですか。。。勉強してみます。
ありがとうございました。
> > まずはデータにアクセスする部分をカプセル化してpreferenseでもsqlでも実装できるようにするような修正の進め方をすると相互で動作確認できるので----いいですよ
> > android-group-j...@googlegroups.com<android-group-japan%2Bunsu-...@googlegroups.com>
>
> ...
>
> もっと読む ≫- 引用テキストを表示しない -
>
> - 引用テキストを表示 -
Reply all
Reply to author
Forward
0 new messages