Android网格视图图像消耗所有内存和崩溃

时间:2015-02-09 12:29:12

标签: java android out-of-memory

我正在尝试调试我的应用程序中我消耗所有内存并导致应用程序崩溃的位置。

所有加载查找但是当我向下滚动网格视图时,我将更多图像加载到GridView一切正常。如果我向上滚动,我可以看到它们是从缓存中加载的。但随着我继续向下滚动,设备分配大约250mb并崩溃。我出错的任何想法。

我还应该注意到,这个Gird在崩溃时有大约150张图像(每张约20kb)。我希望得到更多。

请对我温柔,我是Java和Android的新手。

ItemAdapter

public ItemAdapter(Context context, int resource, List<Item> objects) {
    super(context, resource, objects);
    this.context = context;
    this.itemList = objects;

    final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
    final int cacheSize = maxMemory / 8;
    imageCache = new LruCache<>(cacheSize);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.feed_staggered_grid_view_item, parent, false);

    //Display item name in textview widget
    Item item = itemList.get(position);
    TextView item_title = (TextView) view.findViewById(R.id.textView1);
    item_title.setText(item.getTitle());

    TextView item_brand = (TextView) view.findViewById(R.id.textView2);
    item_brand.setText(item.getBrand());

    //display image
    Bitmap bitmap = imageCache.get(item.getItemId());
    if (bitmap != null) {
        ImageView image = (ImageView) view.findViewById(R.id.imageView);
        image.setImageBitmap(bitmap);
    } else {
        ItemAndView container = new ItemAndView();
        container.item = item;
        container.view = view;

        ImageLoader loader = new ImageLoader();
        loader.execute(container);
    }

    return view;
}

class ItemAndView {
    public Item item;
    public View view;
    public Bitmap bitmap;
}

private class ImageLoader extends AsyncTask<ItemAndView, Void, ItemAndView> {

    @Override
    protected ItemAndView doInBackground(ItemAndView... params) {
        ItemAndView container = params[0];
        Item item = container.item;

        try {
            StringBuilder sb = new StringBuilder();
            sb.append(FeedFragment.IMAGES_BASE_URL);
            sb.append(item.getCategory());
            sb.append("/");
            sb.append(item.getProductId());
            sb.append("/img1.jpg");
            String imageUrl = sb.toString();

            InputStream in = (InputStream) new URL(imageUrl).getContent();
            Bitmap bitmap = BitmapFactory.decodeStream(in);
            item.setBitmap(bitmap);
            in.close();
            container.bitmap = bitmap;
            return container;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(ItemAndView itemAndView) {
        ImageView image = (ImageView) itemAndView.view.findViewById(R.id.imageView);
        image.setImageBitmap(itemAndView.bitmap);
        if (imageCache.get(itemAndView.item.getItemId()) == null) {
            imageCache.put(itemAndView.item.getItemId(), itemAndView.bitmap);
        }
    }
}

FeedFragment

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (feedItemList == null) {
        requestData(FEED_BASE_URL + pageNum);
    }
    return inflater.inflate(R.layout.feed_staggered_grid_view, container, false);
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (feedItemList != null) {
        updateDisplay();
    }
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
}

private void requestData(String uri) {
    MyTask task = new MyTask();
    task.execute(uri);
    pageNum++;
}

protected void updateDisplay() {
    feedAdapter = new ItemAdapter(getActivity(), R.layout.feed_staggered_grid_view_item, feedItemList);
    feedGridView = (StaggeredGridView) getView().findViewById(R.id.grid_view);
    feedGridView.setAdapter(feedAdapter);
    feedGridView.setOnScrollListener(this);
    feedGridView.setOnItemClickListener(this);
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (!isLoading && totalItemCount != 0) {
        int lastItemInScreen = firstVisibleItem + visibleItemCount;
        if (lastItemInScreen >= totalItemCount) {
            isLoading = true;
            requestData(FEED_BASE_URL + pageNum);
        }
    }
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Item item = feedItemList.get(position);
    Intent intent = new Intent(getSherlockActivity(), ItemViewer.class);

    Bundle extras = new Bundle();
    extras.putString("item_title", item.getTitle());
    extras.putString("item_description", item.getDescription());
    extras.putString("item_brand", item.getBrand());
    extras.putDouble("item_price", item.getPrice());
    extras.putString("item_photo", item.getPhoto());
    intent.putExtras(extras);

    startActivity(intent);
}

private class MyTask extends AsyncTask<String, String, List<Item>> {

    @Override
    protected void onPreExecute() {
    }

    @Override
    protected List<Item> doInBackground(String... params) {
        String content = HttpManager.getData(params[0]);
        List<Item> data = ItemFeedJSONParser.parseFeed(content);
        if (feedItemList == null) {
            feedItemList = data;
        } else {
            feedItemList.addAll(data);
        }

        return null;
    }

    @Override
    protected void onPostExecute(List<Item> result) {
        if (pageNum <= 1) {
            updateDisplay();
        } else {
            feedAdapter.notifyDataSetChanged();
        }

        isLoading = false;

    }
}

这是错误消息

 FATAL EXCEPTION: AsyncTask #5
Process: com.test.game.test, PID: 10931
java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:300)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
        at java.util.concurrent.FutureTask.run(FutureTask.java:242)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)
 Caused by: java.lang.OutOfMemoryError: Failed to allocate a 429212 byte allocation with 80604 free bytes and 78KB until OOM
        at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
        at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
        at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:635)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:611)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:649)
        at com.test.game.adapters.ItemAdapter$ImageLoader.doInBackground(ItemAdapter.java:106)
        at com.test.game.adapters.ItemAdapter$ImageLoader.doInBackground(ItemAdapter.java:89)
        at android.os.AsyncTask$2.call(AsyncTask.java:288)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)

3 个答案:

答案 0 :(得分:0)

不要为每次调用创建 view ,而是尝试使用 convertView 。请在 getView 中的代码的前两行尝试以下代码:

View view;
if (convertView==null){
   LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
   view = inflater.inflate(R.layout.feed_staggered_grid_view_item, parent, false);
}else{
   view = convertView;
}

答案 1 :(得分:0)

这里的问题是你加载的位图太大了。不仅下载图像而且放置也应该在后台完成。使用AsyncTask执行此操作,或者始终使用PicassoIon。我遇到了同样的问题并使用Ion解决了它,效果非常好。

此外,不要为每个项目加载一个不同的视图,请使用convertView。

答案 2 :(得分:0)

我认为您需要转到mainfiest文件并在应用程序标记上添加以下行:

android:largeHeap="true"