Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android:BitmapFactory.NativeDecodeset上的OutOfMemoryError(蜂巢3.0及以上版本)_Android_Android Listview_Heap_Out Of Memory_Dalvik - Fatal编程技术网

Android:BitmapFactory.NativeDecodeset上的OutOfMemoryError(蜂巢3.0及以上版本)

Android:BitmapFactory.NativeDecodeset上的OutOfMemoryError(蜂巢3.0及以上版本),android,android-listview,heap,out-of-memory,dalvik,Android,Android Listview,Heap,Out Of Memory,Dalvik,由于安卓在安卓3.0中引入了一种新的位图内存管理(位图数据现在已分配),我得到了这个OutOfMemoryError错误,它使我的应用程序崩溃 基本上,我有一个ListView,其中大约有1000个ImageView,保存着我的资产文件夹中的位图(分辨率:300 x 200像素) 我在运行Jelly Bean的HTC Desire上发现了这个问题。如果我滚动到fast,我的应用程序的专业版将崩溃。(免费版列表中只有150项) 我试图在模拟器中重现错误,发现Android 3.0及以上版本中DDM

由于安卓在安卓3.0中引入了一种新的位图内存管理(位图数据现在已分配),我得到了这个OutOfMemoryError错误,它使我的应用程序崩溃

基本上,我有一个ListView,其中大约有1000个ImageView,保存着我的资产文件夹中的位图(分辨率:300 x 200像素)

我在运行Jelly Bean的HTC Desire上发现了这个问题。如果我滚动到fast,我的应用程序的专业版将崩溃。(免费版列表中只有150项) 我试图在模拟器中重现错误,发现Android 3.0及以上版本中DDM的垃圾收集消息与我的旧2.3.6智能手机(运行应用程序时没有任何问题)上的垃圾收集消息不同。因此,存储大量数据的内存大小是不够的。我不认为ListView真的保存了内存中的所有位图,但是150个项目和1000个项目之间肯定存在差异

我试图在我的列表适配器中异步处理GetView(),但随后在AsyncTask线程中出现OutOfMemory。所以我没有任何进展

有人有办法解决这个问题吗

没有帮我

编辑: 好的,我分析了我的应用程序,似乎不是ListView导致了问题,而是我的ViewFlipper

我的主菜单、我的搜索屏幕、我的搜索结果(ListView&GridView-Togleable)和我的DetailedView都是我的ViewFlipper上的单个“页面”

主菜单、SearchScreen和DetailedView占用了我大约20 MB的内存。 我从代码中提取了列表和网格视图,看起来它们的格式是8MB到13MB(取决于滚动的执行速度)

Android SDK模拟器(模拟4.2)的VM堆大小为32MB。因此,最初它可以工作,如果我滚动到fast,我会遇到内存不足的问题,并显示错误消息:

skia decoder->decode returned false
其次是各种位图解码出的内存问题

所以我想我必须卸载/缓存我的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;
        }

    }

}
我不确定,但也许我遗漏了一些代码的细节


不使用时,应回收位图

bitmap.recycle();
您可以使用通用图像加载器

您可以使用延迟加载图像

两者都使用缓存

。演讲内容涉及内存管理、位图回收以及如何使用MAT Analyzer检测内存泄漏

。使用视图保持架进行平滑滚动

。这次讲座是关于视图持有者和listview性能的


正如您所提到的,您已经高效地展示了位图。

这可能不是一个合适的解决方案,但这就是我现在要提供的全部内容。 添加您的清单(在应用程序标记中)


这可能会在一定程度上解决您的内存不足问题。如果您显示适配器和listview对,我可能会告诉您一些更合法的解决方案。

问题是AsyncTask只适用于少数图像,对于数百(或数千)个图像,它们处理得不太好

当然,缓存是绝对必要的,在你发布的Google链接上,有关于RAM和磁盘缓存的解释

对于这样的大型数据集,您实际上有两种选择:

  • 使用一个库(如通用图像加载器或惰性列表),它们并不完美,但大多数情况下都能很好地工作

  • 创建自己的实现。我以前实现过这些,我希望它们不是公司IP的一部分,因为我想开源。但是,对于从一个缓存或从另一个缓存或从联机加载的线程,您必须实现多组线程(使用),并返回结果,如果正在回收ImageView,请记住取消返回。这是一个漫长而复杂的过程,但如果你做得好,你会得到一些真正的黄油平滑滚动


  • 也许这可以为你指明正确的方向:@Erican。这家伙用大堆给了一个大警告。堆越大,Garbadge收集越频繁,导致性能降低。true。但我不能提供任何更好的没有销售代码。谢谢你的答复。我已经实现了您的一些提示(请参阅编辑后的原始添加源代码)。也许你知道一些技巧,如何解决浏览者问题?提前感谢您是否使用了通用图像加载器,但仍然遇到内存泄漏??。请在这里粘贴代码。只粘贴相关代码。没有人会看下载它的源代码。(25MB)我还没有试过UIL jet。我认为这个库/项目只用于远程加载图片,不用于本地图像加载。但看起来UILs多线程和缓存可能对我的项目有用。您也可以本地加载图像UISNUIL。
    android:largeHeap="true"