Out of Memory error after using app for more than

2019-09-08 14:31发布

问题:

I've been getting following out of memory issue due to layout inflater when i use my app for little longer than 7-8 minutes. I have checked through many questions in stackoverflow but have not been able to find a good solution. I tried 'android:largeHeap="true"' too, but it seems to create more problem than solve this.

The Fragment that contains the listview where i have loaded large chunk of item details which is usually causing outOfMemory error is as follows:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    viewX = inflater.inflate(R.layout.item_list, container, false);
    baseURL = getResources().getString(R.string.baseURL);
    ((MainActivity) getActivity()).setBack(0);
    ((MainActivity) getActivity()).setBack_match(2);
    ((MainActivity) getActivity()).setBackIcon(0);  
    search = (SearchView) viewX.findViewById(R.id.search);
    listView = (SwipeMenuListView) viewX.findViewById(R.id.listView);
    layout = (LinearLayout) viewX.findViewById(R.id.layout2);
    progress = (ProgressBar) viewX.findViewById(R.id.progress2);
    list_notice = (TextView) viewX.findViewById(R.id.list_notice);
    list_title = (TextView) viewX.findViewById(R.id.list_title);

    me_latLng = ((MainActivity) getActivity()).getUserLatLng();
    likeFav = ((MainActivity) getActivity()).likeFavX();
    device_id = ((MainActivity) getActivity()).getDeviceId();
    token = ((MainActivity) getActivity()).getToken();
    BG = ((MainActivity) getActivity()).getCarBG();

    if (me_latLng == null) {
        me_latLng = new LatLng(0, 0);
        distance_check = 1;
    }        
    if (likeFav == 1) {
        list_title.setText("LIKED CARS");
        likeFav = 1;
        list("like");
    }
    if (likeFav == 0) {
        list_title.setText("FAVOURITE CARS");
        likeFav = 0;
        list("fav");
    }

    SwipeMenuCreator creator = new SwipeMenuCreator() {
        @Override
        public void create(SwipeMenu menu) {


            // create "delete" item
            SwipeMenuItem deleteItem = new SwipeMenuItem(
                    getActivity());
            // set item background
            deleteItem.setBackground(new ColorDrawable(Color.rgb(0x7a,
                    0x01, 0x3a)));
            // set item width
            deleteItem.setWidth(150);
            // set a icon
            deleteItem.setIcon(R.drawable.delete);
            // add to menu
            menu.addMenuItem(deleteItem);
        }
    };

listView.setMenuCreator(creator);
    listView.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(int position, SwipeMenu menu, int index) {
            int[] vNew = ((MainActivity) getActivity()).getPos();

            final int positionNew = vNew[position];
            switch (index) {
                case 0:
                    final int position2 = position;
                    new AlertDialog.Builder(getActivity())
                            .setTitle("")
                            .setMessage("Are you sure you want to delete car: " + brand_list[positionNew] + ", " + model_list[positionNew])
                            .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    if (likeFav == 1) {
                                        deleteLikeFav(baseURL + "RemoveLike", "" + assetId_list[positionNew]);
                                    } else {
                                        deleteLikeFav(baseURL + "RemoveFavourite", "" + assetId_list[positionNew]);
                                    }
                                    dialog.dismiss();
                                }
                            })
                            .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                }
                            })
                            .show();
                    break;
            }
           return false;
        }
    });

    listView.setSwipeDirection(SwipeMenuListView.DIRECTION_LEFT);
    search.setOnQueryTextListener(item_list.this);
    return viewX;
}

private void deleteLikeFav(final String s, final String assetIdXXX) {
    RequestQueue rq = Volley.newRequestQueue(getActivity());
    StringRequest postReq = new StringRequest(Request.Method.POST, s, new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {
            try {
                JSONObject jsonResponse = new JSONObject(response);

                String ResponseType = jsonResponse.getString("ResponseType"),
                        network = jsonResponse.getString("ResponseMessage");

                if (network.equals("success")) {
                    if (likeFav == 1) {
                        likeFav = 1;
                        list("like");
                    } else if (likeFav == 0) {
                        likeFav = 0;
                        list("fav");
                    }
                } else if (network.equals("Token Unavailabele or Expired!")) {
                    ((MainActivity) getActivity()).renewToken();
                    token = ((MainActivity) getActivity()).getToken();
                    deleteLikeFav(s, assetIdXXX);
                } 
            } catch (Exception e) {
                e.printStackTrace();
                 }


        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            System.out.println("Error [" + error + "]");

        }
    }) {


        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            params.put("deviceid", device_id);
            params.put("token", token);
            params.put("web-method", "api");
            params.put("AssetID", assetIdXXX);
            return params;
        }


    };
    rq.add(postReq);
}

public void list(String favLike) {
    if (favLike.equals("fav")) {
        getLikeFav(baseURL + "GetFavouriteCar");
    } else {
        getLikeFav(baseURL + "GetLikedCar");
    }
}

AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        int[] v = ((MainActivity) getActivity()).getPos();
        int x = v[position];
        ((MainActivity) getActivity()).setNum_list(x);
        ((MainActivity) getActivity()).setList_flag("on");
        ((MainActivity) getActivity()).setBack(1);

        Fragment fragment = new item_details();
        FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.linear_view, fragment).addToBackStack(null).commit();
    }
};


public void getLikeFav(final String url) {
    num_list = 0;
    layout.setVisibility(View.VISIBLE);
    RequestQueue rq = Volley.newRequestQueue(getActivity());
    StringRequest postReq = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {


            try {
                String text = "Liked Car";
                if (likeFav == 1) {
                    text = "Liked Car";
                } else {
                    text = "Favourite Car";
                }
                String network = new JSONObject(response).getString("ResponseMessage");
                if (network.equals("Token Unavailabele or Expired!")) {
                    ((MainActivity) getActivity()).renewToken();
                    token = ((MainActivity) getActivity()).getToken();
                    getLikeFav(url);
                }

                JSONArray array = new JSONObject(response).getJSONArray(text);

                arrayLength_list = array.length();
                assetId_list = new int[array.length()];
                brand_list = new String[array.length()];
                model_list = new String[array.length()];
                version_list = new String[array.length()];
                price_list = new int[array.length()];
                fuel_list = new String[array.length()];
                color_list = new String[array.length()];
                fav_list = new String[array.length()];
                trans_list = new String[array.length()];
                doors_list = new String[array.length()];
                newOld_list = new String[array.length()];
                image_list = new String[array.length()];
                d_num_list = new String[array.length()];
                d_name_list = new String[array.length()];
                d_street_list = new String[array.length()];
                d_zip_list = new String[array.length()];
                d_location_list = new String[array.length()];
                d_phone_list = new String[array.length()];
                d_email_list = new String[array.length()];
                d_image_list = new String[array.length()];
                d_lat_list = new String[array.length()];
                d_long_list = new String[array.length()];
                d_whatsApp_list = new String[array.length()];
                distance_list = new String[array.length()];
                ((MainActivity) getActivity()).setposPos(array.length());
                ((MainActivity) getActivity()).setDistance_array(array.length());


                for (int i = 0; i < array.length(); i++) {
                    JSONObject j_object = array.getJSONObject(i);
                    assetId_list[i] = j_object.getInt("AssetID");
                    brand_list[i] = j_object.getString("Brand");
                    model_list[i] = j_object.getString("Model");
                    version_list[i] = j_object.getString("Version");
                    price_list[i] = j_object.getInt("Price");
                    fuel_list[i] = j_object.getString("Fuel");
                    color_list[i] = j_object.getString("Color");
                    trans_list[i] = j_object.getString("Transmission");
                    doors_list[i] = j_object.getString("NumDoors");
                    newOld_list[i] = j_object.getString("NewVehicle");
                    image_list[i] = j_object.getString("ImagePath");
                    if (likeFav == 1) {
                        fav_list[i] = j_object.getString("Favourite");
                    } else {
                        fav_list[i] = "true";
                    }
                    d_num_list[i] = j_object.getString("RDCProviderNumber");
                    d_name_list[i] = j_object.getString("ProviderName");
                    d_street_list[i] = j_object.getString("ProviderStreetName");
                    d_zip_list[i] = j_object.getString("ProviderZipCode");
                    d_location_list[i] = j_object.getString("ProviderLocation");
                    d_phone_list[i] = j_object.getString("ProviderPhone");
                    d_whatsApp_list[i] = j_object.getString("WhatsAppNumber");
                    d_email_list[i] = j_object.getString("ProviderEmail");
                    d_image_list[i] = j_object.getString("ProviderImage");

                    d_lat_list[i] = j_object.getString("Latitude");
                    d_long_list[i] = j_object.getString("Longitude");

                }

                data = new ArrayList<Data>();
                for (int i = 0; i < brand_list.length; i++) {
                    String priceStandard = "";
                    String price2X = "" + price_list[i];
                    if (price2X.length() > 6) {
                        String priceX1 = new StringBuffer(price2X).insert(price2X.length() - 6, ".").toString();
                        priceStandard = new StringBuffer(priceX1).insert(priceX1.length() - 3, ".").toString();
                    } else {
                        priceStandard = new StringBuffer(price2X).insert(price2X.length() - 3, ".").toString();
                    }
                    if (d_lat_list[i].equals("")) {
                        d_lat_list[i] = "0.0";
                    }
                    if (d_long_list[i].equals("")) {
                        d_long_list[i] = "0.0";
                    }

                    distance_list[i] = getDistance(me_latLng, new LatLng(Double.parseDouble(d_lat_list[i]), Double.parseDouble(d_long_list[i])));
                    Data searchList = new Data(model_list[i], brand_list[i], version_list[i], image_list[i], priceStandard + ",-", newOld_list[i], fav_list[i], distance_list[i], i);

                    data.add(searchList);
                    ((MainActivity) getActivity()).setPos(i, i);
                }

                myAdapter = new MyAdapter(getActivity(), data);

                listView.setAdapter(myAdapter);
                listView.setTextFilterEnabled(true);
                listView.setOnItemClickListener(listener);
                ((MainActivity) getActivity()).setList(assetId_list, image_list, brand_list, model_list, version_list, price_list, newOld_list, color_list, fuel_list, doors_list, fav_list, trans_list,
                        d_name_list, d_location_list, d_street_list, d_phone_list, d_image_list, d_lat_list, d_long_list, d_whatsApp_list, d_num_list, d_email_list);

                if (array.length() == 0) {
                    layout.setVisibility(View.VISIBLE);
                    progress.setVisibility(View.GONE);
                    list_notice.setVisibility(View.VISIBLE);
                    if (likeFav == 1) {
                        list_notice.setText("No liked cars to display");
                    } else {
                        list_notice.setText("No favourite cars to display");
                    }

                } else {
                    layout.setVisibility(View.GONE);
                    progress.setVisibility(View.VISIBLE);
                    list_notice.setVisibility(View.GONE);
                }


            } catch (Exception e) {

            }


        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            System.out.println("Error [" + error + "]");
           }
    }) {


        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            params.put("deviceid", device_id);

            params.put("token", token);
            params.put("web-method", "api");
            return params;
        }


    };
    rq.add(postReq);


}


public String getDistance(LatLng my_latlong, LatLng frnd_latlong) {
    String dist;
    if (distance_check == 0) {
        Location l1 = new Location("One");
        l1.setLatitude(my_latlong.latitude);
        l1.setLongitude(my_latlong.longitude);

        Location l2 = new Location("Two");
        l2.setLatitude(frnd_latlong.latitude);
        l2.setLongitude(frnd_latlong.longitude);

        float distance = l1.distanceTo(l2);
        int dd = (int) (distance / 1000);
        dist = dd + "";
        if (dist.equals("0")) {
            dist = "<1";
        }
    } else {
        dist = " ";
    }


    return dist;
}

@Override
public boolean onQueryTextSubmit(String query) {
    if (searchCheck == 1) {
        myAdapter.getFilter().filter(query);
    }
    return false;
}

@Override
public boolean onQueryTextChange(String newText) {
    if (searchCheck == 1) {
        myAdapter.getFilter().filter(newText);
    }
    return false;
}


public class MyAdapter extends BaseAdapter implements Filterable {

    ArrayList<Data> dataList = null;
    ArrayList<Data> mStringFilterList;
    ValueFilter valueFilter;
    View row = null;
    private Context context;


    public MyAdapter(Context context, ArrayList<Data> data) {

        this.context = context;
        this.dataList = data;
        this.mStringFilterList = new ArrayList<Data>();
        this.mStringFilterList = data;
    }

    public class ViewHolderV {
        ImageView carImageV;
        TextView brandV;
        TextView modelV;
        TextView priceV;
        TextView newOldV;
        ImageView bgV;
        ImageView favV;
        TextView distanceV;
        TextView positionV;
    }

    @Override
    public int getCount() {

        return dataList.size();
    }

    @Override
    public Object getItem(int position) {
        return dataList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolderV viewHolder = new ViewHolderV();

        dataV = dataList.get(position);
        if (convertView == null) {

            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.list_view, parent, false);


            ((MainActivity) getActivity()).setNum_list(position);

            viewHolder.brandV = (TextView) row.findViewById(R.id.list_brand);
            viewHolder.modelV = (TextView) row.findViewById(R.id.list_here);
            viewHolder.priceV = (TextView) row.findViewById(R.id.list_price);
            viewHolder.newOldV = (TextView) row.findViewById(R.id.list_oldNew);
            viewHolder.distanceV = (TextView) row.findViewById(R.id.list_distance);
            viewHolder.carImageV = (ImageView) row.findViewById(R.id.list_car);
            viewHolder.bgV = (ImageView) row.findViewById(R.id.list_bg);
            viewHolder.favV = (ImageView) row.findViewById(R.id.list_fav);
            viewHolder.positionV = (TextView) row.findViewById(R.id.list_position);

            row.setTag(viewHolder);


        } else {
            viewHolder = (ViewHolderV) convertView.getTag();
        }


        ((MainActivity) getActivity()).setDistance_list(dataV.getDistance_data());
        ((MainActivity) getActivity()).setPos(position, dataV.getPosition_data());
        viewHolder.brandV.setText(dataV.getBrand_data() + " " + dataV.getModel_data());
        viewHolder.modelV.setText(dataV.getVersion_data());
        viewHolder.priceV.setText("" + dataV.getPrice_data());
        viewHolder.newOldV.setText(dataV.getNewOld_data());
        viewHolder.positionV.setText("" + dataV.getPosition_data());
        Picasso.with(getActivity()).load(dataV.getImage_data()).into(viewHolder.carImageV);
        Picasso.with(getActivity()).load(BG).into(viewHolder.bgV);
        viewHolder.distanceV.setText(dataV.getDistance_data() + " KM");
        if (dataV.getFav_data().equals("true")) {
            viewHolder.favV.setImageResource(R.drawable.fav);
        } else {
            viewHolder.favV.setImageResource(R.drawable.fav2);
        }

        searchCheck = 1;
        return row;
    }

    @Override
    public Filter getFilter() {
        if (valueFilter == null) {
            valueFilter = new ValueFilter();
        }
        return valueFilter;
    }

    private class ValueFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();
            ((MainActivity) getActivity()).setPosNil();

            if (constraint.length() == 0) {
                results.count = mStringFilterList.size();
                results.values = mStringFilterList;
                // mStringFilterList.addAll(dataList);
                ((MainActivity) getActivity()).setposPos(mStringFilterList.size());
            } else {

                ArrayList<Data> filterList = new ArrayList<Data>();

                for (int i = 0; i < mStringFilterList.size(); i++) {
                    if ((mStringFilterList.get(i).getBrand_data().toUpperCase() + " " + mStringFilterList.get(i).getModel_data().toUpperCase())
                            .contains(constraint.toString().toUpperCase()) || (mStringFilterList.get(i).getVersion_data().toUpperCase())
                            .contains(constraint.toString().toUpperCase())) {

                        Data d = new Data(mStringFilterList.get(i)
                                .getModel_data(), mStringFilterList.get(i)
                                .getBrand_data(), mStringFilterList.get(i)
                                .getVersion_data(), mStringFilterList.get(i)
                                .getImage_data(), mStringFilterList.get(i)
                                .getPrice_data(), mStringFilterList.get(i)
                                .getNewOld_data(), mStringFilterList.get(i)
                                .getFav_data(), mStringFilterList.get(i)
                                .getDistance_data(), mStringFilterList.get(i)
                                .getPosition_data());

                        filterList.add(d);
                    }
                }
                results.count = filterList.size();
                results.values = filterList;
                ((MainActivity) getActivity()).setposPos(filterList.size());
            }
            return results;

        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint,
                                      FilterResults results) {
            dataList = (ArrayList<Data>) results.values;
            notifyDataSetChanged();
        }

    }
}

回答1:

the problem is with your view holder. ViewHolder pattern is used to optimise the memory taken by the list. it will create View objects only for the visible part, but in your case every time you are creating a ViewHolder, so whenever you scroll the number of objects will increase and it will cause OutOfMemoryException, the only way to correct is, you need to have some changes in you code. please refer this url. also see the example

    @Override
public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolderItem viewHolder;


      // The convertView argument is essentially a "ScrapView" as described is Lucas post 
      // http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
      // It will have a non-null value when ListView is asking you recycle the row layout. 
      // So, when convertView is not null, you should simply update its contents instead of inflating a new row    layout.

    if(convertView==null){

        // inflate the layout
        LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
        convertView = inflater.inflate(layoutResourceId, parent, false);

        // well set up the ViewHolder
        viewHolder = new ViewHolderItem();
        viewHolder.textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);

        // store the holder with the view.
        convertView.setTag(viewHolder);

    }else{
        // we've just avoided calling findViewById() on resource everytime
        // just use the viewHolder
        viewHolder = (ViewHolderItem) convertView.getTag();
    }
....................
.............
}