AndroidがAndroid3.0でビットマップの新しいメモリ管理を導入したため(ビットマップデータはDalvikヒープ内に割り当てられるようになりました)、このOutOfMemoryErrorエラーが発生してアプリがクラッシュします。
基本的に私は約のListViewを持っています。アセットフォルダからのビットマップを保持する1000個のImageView(解像度:300 x 200ピクセル)。
JellyBeanを実行しているHTCDesireでこの問題を検出しました。高速にスクロールすると、アプリのProバージョンがクラッシュします。(無料版のリストには150個のアイテムしかありません)エミュレーターでエラーを再現しようとしましたが、Androidバージョン3.0以降のDDMSのガベージコレクションメッセージが、古い2.3.6スマートフォンのようにGC_EXTERNAL_ALLOCではないことがわかりました。 (これは問題なくアプリを実行します)。したがって、大量のデータのメモリサイズは十分ではありません。ListViewが実際にすべてのビットマップをメモリに保持しているとは思いませんが、実際には150アイテムと1000アイテムの間に違いがあるはずです。
リストアダプタでGetView()をAsyncTaskしようとしましたが、AsyncTaskスレッドでOutOfMemoryが発生します。だから私はこれでどこにも行きません...
誰かがこの問題を解決するためのアイデアを持っていますか?
Googleの開発ガイドは私を助けませんでした
編集:
わかりました。APPをMAT分析しましたが、問題の原因はListViewではなく、ViewFlipperのようです。
MainMenu、SearchScreen、SearchResults(ListViewとGridView-切り替え可能)、およびDetailedViewはすべて、ViewFlipperから離れた単一の「ページ」です。
MainMenu、SearchScreen、DetailedViewは私のメモリの約20MBを占めます。コードからList-とGridviewを抽出しましたが、それらは8MBから最大13MBまでの形式をとっているようです(スクロールの実行速度によって異なります)。
Android SDKエミュレーター(4.2をエミュレート)のVMヒープサイズは32MBです。したがって、最初は機能します。高速にスクロールすると、メモリが不足し、エラーメッセージが表示されます。
skia decoder->decode returned false
さまざまなBitmap-decode-OutOfMemoryの問題が続きます。
だから私はViewFlipperのページをアンロード/キャッシュする必要があると思います-そうですか?どうやってするか???
これは、ListView/GridView実装の抽出されたソースです。
public class GridTestActivity extends Activity {
GridView gv;
ListView lv;
int lvScreenWidth;
int lvScreenHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_grid_test);
Display display = getWindowManager().getDefaultDisplay();
this.lvScreenWidth = display.getWidth();
this.lvScreenHeight = display.getHeight();
MyAdapter adp = new MyAdapter(this);
gv = (GridView)findViewById(R.id.gridView1);
gv.setAdapter(adp);
gv.setFastScrollEnabled(true);
lv = (ListView)findViewById(R.id.listView1);
lv.setAdapter(adp);
lv.setFastScrollEnabled(true);
ActivityManager am = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
Toast.makeText(this, "DALVIK HEAP SIZE: " + am.getMemoryClass() + "MB", 5).show();
}
static class ViewHolder{
TextView text;
ImageView icon;
}
public class MyAdapter extends BaseAdapter{
private LayoutInflater mInflater;
public MyAdapter(Context context) {
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return 1000;
}
@Override
public Object getItem(int arg0) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText("pos:" + position);
// best way to load an asset-image???
try {
InputStream ims = getAssets().open("assetpic_" + position + ".jpg");
BitmapDrawable d = (BitmapDrawable) Drawable.createFromStream(ims, null);
ims.close();
holder.icon.setImageDrawable(d);
if (parent.equals(lv)){
int oldWidth = d.getIntrinsicWidth();
int oldHeight= d.getIntrinsicHeight();
holder.icon.getLayoutParams().height = lvScreenWidth * oldHeight/oldWidth;
}
}
catch(IOException ex) {
Log.i("MyAdapter" , "Could not load 'assetpic_" + position + ".jpg' from Assets-folder");
}
return convertView;
}
}
}
よくわかりませんが、コードの詳細が不足している可能性がありますか?