我在BaseAdapter中使用以下代码作为我的getView()。
当我尝试旋转手机几次时,每次堆内存增加时。虽然我在内存分析器中对此进行了分析,但我发现正在创建新的TextView,但旧版本没有被破坏。
我该怎么做才能解决这个问题?
完整适配器代码:
package in.mypack.ui;
import static in.mypack.Util.getHelper;
import in.mypack.data.MyClass;
import in.mypack.MyMap;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map.Entry;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
private Filter filter;
private MyMap<String, MyClass> items;
private MyMap<String, MyClass> totalItems;
private Locale locale;
private LayoutInflater inflater;
@SuppressWarnings("unused")
private final String TAG = "MyAdapter";
public MyAdapter(MyMap<String, MyClass> objects) {
items = objects;
inflater = getHelper().getLayoutInflater();
}
private static class ViewHolder {
TextView one, two, three;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.one = (TextView) convertView.findViewById(R.id.one);
holder.two = (TextView) convertView.findViewById(R.id.two);
holder.three = (TextView) convertView.findViewById(R.id.three);
Typeface font = Typeface.createFromAsset(getHelper().getAssets(), getHelper().getString(R.string.font_custom));
holder.one.setTypeface(font);
holder.two.setTypeface(font);
holder.three.setTypeface(font);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
MyClass myObject = getItem(position);
holder.one.setText(myObject.getName());
holder.two.setText(myObject.getInfo());
holder.three.setText(myObject.getSize());
addColors(convertView, holder, myObject);
return convertView;
}
private void addColors(View convertView, ViewHolder holder, MyClass myObject) {
if (myObject.isValid()) {
convertView.setBackgroundColor(Color.argb(255,225,225,225));
holder.one.setPaintFlags(holder.one.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
holder.two.setPaintFlags(holder.one.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
else {
convertView.setBackgroundColor(Color.argb(255,185,185,185));
holder.one.setPaintFlags(holder.one.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
holder.two.setPaintFlags(holder.one.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
}
public Filter getFilter() {
if (filter == null) {
locale = Locale.getDefault();
filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence query) {
FilterResults results = new FilterResults();
if (totalItems == null) {
totalItems = new MyMap<String, MyClass>();
totalItems.putAll(items);
}
if (query == null || 0 == query.length()) {
results.count = totalItems.size();
results.values = totalItems;
}
else {
MyMap<String, MyClass> filteredList = new MyMap<String, MyClass>();
MyMap<String, MyClass> containsList = new MyMap<String, MyClass>();
int size = totalItems.size();
for (int i = 0; i < size; i++) {
Entry<String, MyClass> entry = totalItems.getEntry(i);
if (entry.getValue().getTitle().toLowerCase(locale).startsWith(query.toString().toLowerCase(locale))) {
filteredList.putEntry(entry);
} else if (entry.getValue().getTitle().toLowerCase(locale).contains(query.toString().toLowerCase(locale))) {
containsList.putEntry(entry);
}
}
filteredList.putAll(containsList);
results.count = filteredList.size();
results.values = filteredList;
}
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence query, FilterResults results) {
items.clear();
items.putAll((MyMap<String, MyClass>) results.values);
notifyDataSetChanged();
}
};
}
return filter;
}
public void filter(String query) {
getFilter().filter(query);
}
@Override
public int getCount() {
return items.size();
}
@Override
public MyClass getItem(int index) {
return items.get(index);
}
@Override
public long getItemId(int position) {
return position;
}
public void add(MyClass myObject) {
items.sortOnPut(myObject.getName(), myObject, MyMap.Sorting.Value);
}
}
答案 0 :(得分:1)
我在RecyclerViews中遇到了一个问题,因为当Fragment被破坏时,RecyclerView没有从适配器取消注册,因此泄漏了Fragment的View层次结构。
可能存在内存泄漏,与ViewHolders无关。
作为快速解决方案,您可以在#onDestroyView()中从适配器取消注册RecyclerView:
@Override
public void onDestroyView() {
super.onDestroyView();
mRecyclerView.setAdapter(null);
}
查看this,您可以在那里找到完整的解释。
答案 1 :(得分:0)
您不应在列表适配器中使用应用程序上下文,请使用活动上下文。
如果您在片段中使用并且不想重新创建它,请使用Fragment的setRetainInstance(boolean)
为true,但不要使用应用程序上下文。
答案 2 :(得分:0)
虽然TextViews被保留在内存中,但这并不意味着你使用View holder模式就是罪魁祸首。
在这种情况下,我相信它是你的过滤器 - 你正在创建一个内部匿名类,它保留对适配器的引用,它保留对Inflater的引用,它引用创建它的上下文。
过滤器(performFiltering)在后台线程中运行,并且会使您的活动保持活动时间超过预期。
尝试将Filter的实现移动到单独的类中,或者作为静态内部类。
答案 3 :(得分:0)
您是否尝试单独在 ViewHolder 中声明TextView,而不是将它们一起内联?