Исключение нехватки памяти при нажатии на элемент ListView

#android #listview #android-studio

#Android #listview #android-studio

Вопрос:

Я пытаюсь создать listview с фоновым изображением для каждого элемента и текстовым представлением, которое отображается сверху. Представление списка заполняется нормально, но нажатие на элемент напрямую выдает ошибку.

Вот мой элемент просмотра списка xml (menu_section.xml )

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="75dp">

    <ImageView
        android:id="@ id/section_bg_image"
        android:layout_width="match_parent"
        android:layout_height="75dp"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"/>


        <TextView
            android:id="@ id/section_title"
            android:layout_width="match_parent"
            android:layout_height="75dp"
            android:layout_gravity="end"
            android:background="@color/colorBlackTranslucent"
            android:gravity="right|center_vertical"
            android:paddingLeft="20dp"
            android:paddingRight="20dp"
            android:text="Hello World"
            android:textColor="@color/colorWhite"
            android:textSize="24sp" />

</RelativeLayout>
  

Это мой адаптер MenuAdapter.java . Я загружаю изображения для фона из папки активов. Каждое изображение имеет ~ 50 КБ, и на данный момент в общей сложности ~ 400 КБ изображений (с 8 элементами в списке)

 import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

import java.util.List;

import com.myapp.hotel.MyUtility;
import com.myapp.hotel.R;

public class MenuAdapter extends ArrayAdapter<MenuSection> {

    Context context;
    List<MenuSection> menuSections;
    AssetManager assetManager;
    String imageUrl;

    public MenuAdapter(Context context, int resource, List<MenuSection> objects) {
        super(context, resource, objects);
        this.context = context;
        this.menuSections = objects;
        this.assetManager = context.getAssets();
    }

    @Override
    public int getCount() {
        return menuSections.size();
    }

    @Override
    public MenuSection getItem(int i) {
        return menuSections.get(i);
    }

    @Override
    public long getItemId(int i) {
        return menuSections.indexOf(getItemId(i));
    }

    /* private view holder class */
    private class ViewHolder {
        ImageView menuSectionImage;
        TextView menuSectionItemText;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder holder = null;


        LayoutInflater mInflater = (LayoutInflater) context
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        if (view == null) {
            view = mInflater.inflate(R.layout.menu_section, null);
            holder = new ViewHolder();
            holder.menuSectionItemText = (TextView) view.findViewById(R.id.section_title);
            holder.menuSectionImage = (ImageView) view.findViewById(R.id.section_bg_image);

            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }

        MenuSection menuSection = menuSections.get(i);

        holder.menuSectionItemText.setText(menuSection.getSectionName());

        try {
            imageUrl = menuSection.getImagePath();
            if (!MyUtility.isNullOrEmpty(imageUrl)) {
                Picasso.with(holder.menuSectionImage.getContext())
                        .load(Uri.parse(imageUrl))
                        .into(holder.menuSectionImage);
            }
        } catch (Exception ex) {
            ex.printStackTrace();

        }

        return view;
    }
}
  

и это фрагмент RestaurantFragment.java

 import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import java.util.List;

import com.myapp.hotel.MyUtility;
import com.myapp.hotel.R;


/**
 * A simple {@link Fragment} subclass.
 */
public class RestaurantFragment extends Fragment {
    MenuAdapter adapter;
    List<MenuSection> menuSections;
    View view;

    public RestaurantFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        if(view == null) {
            view = inflater.inflate(R.layout.fragment_restaurant, container, false);
        }
        //adapter = new ArrayAdapter<String>(RestaurantFragment.this.getContext(), R.layout.menu_view, R.id.menu_text, MyUtility.getMenuSections().toArray(new String[MyUtility.getMenuSections().size()]));
        ListView listView = (ListView) view.findViewById(R.id.menu);
        menuSections = MyUtility.getMenuSections();

        adapter = new MenuAdapter(RestaurantFragment.this.getContext(), R.layout.menu_section, menuSections);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(RestaurantFragment.this.getActivity(), "Hello World",
                        Toast.LENGTH_SHORT).show();
            }
        });
        //listView.setOnItemClickListener();
        //listView.setAdapter(adapter);

        /*
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {
                Intent intent = new Intent(RestaurantFragment.this.getContext(), RestaurantMenuDetailsActivity.class);
                intent.putExtra("menu_section", adapter.getItem(position).toString());
                startActivity(intent);
            }
        });
        */
        return view;
    }
}
  

Это ошибка, которую я вижу в logcat

 10-07 19:27:14.445 14925-14925/com.myapp.hotel E/InputEventReceiver: Exception dispatching input event.
10-07 19:27:14.445 14925-14925/com.myapp.hotel E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
10-07 19:27:17.155 14925-14925/com.myapp.hotel E/art: Throwing OutOfMemoryError "Failed to allocate a 10109874 byte allocation with 8141766 free bytes and 7MB until OOM"
10-07 19:27:18.195 14925-14925/com.myapp.hotel E/art: Throwing OutOfMemoryError "Failed to allocate a 10109874 byte allocation with 8141862 free bytes and 7MB until OOM"
10-07 19:27:18.195 14925-14925/com.myapp.hotel E/MessageQueue-JNI: java.lang.StackOverflowError: stack size 8MB
10-07 19:27:19.695 14925-14925/com.myapp.hotel E/art: Throwing OutOfMemoryError "Failed to allocate a 10735842 byte allocation with 7722526 free bytes and 7MB until OOM"
10-07 19:27:20.255 14925-14925/? E/art: Throwing OutOfMemoryError "Failed to allocate a 10735842 byte allocation with 7722654 free bytes and 7MB until OOM"
  

Что я упускаю / делаю не так?

Обновить

Все мои изображения общим весом ~ 400 КБ. 8 изображений размером около 50 Кб каждое. Проблема в том, что даже если я закомментирую всю загрузку изображения и просто загружу текст, при нажатии на любой элемент listview выдается та же ошибка. Так что это определенно не имеет ничего общего с изображениями. Я думаю, что что-то не так с адаптером.. просто не могу понять, что это может быть! Это просто простой адаптер!

Комментарии:

1. MessageQueue больше похоже на утечку обработчика.

Ответ №1:

Я думаю, что это не имеет ничего общего с обработкой изображений. Это переполнение стека из-за бесконечной рекурсии в getItemId()

 @Override
public long getItemId(int i) {
    // calls itself with the same value, it can not end well !
    return menuSections.indexOf(getItemId(i));
}
  

Комментарии:

1. БОЖЕ.. Большое вам спасибо 🙂

Ответ №2:

Вы можете использовать largeheap="true" в Android-манифесте внутри тега приложения. Но лучше изменить размер изображения.

Сколько составляет высота, ширина вашего отдельного изображения?