0

我很好奇 CustomAdapter 继续循环同样的事情是正常的吗?例如,我有 3 行来自数据库的记录,我想将它们显示在我的列表中。一旦我使用 customAdapter 显示,它将循环相同的东西 3 次。意味着如果我有 10 行 if 记录,它将循环 10 次 * 10 条记录 = 100 次循环。如果这样,我的程序肯定会耗尽内存。有什么解决办法吗?我已附上我的日志,如下所示。如果您注意到“~~ row id~~ 0”,它会保持相同的循环 3 次。

 public class ViewMsgMain extends ListActivity{

// Retrieve member id from local database
String memberid = FypGeneral.LOGINMEMBERID;
SharedPreferences sp_memberid;
int memid;

String sender_id="", content_type = "", content_path = "", content_id = "", imageaudio_id = "", content_date="";
String over_contentid = "", uploaded_content_id = "", receiver_id = "", read_status = "", 
        sender_member_image="", imageAudio_image="";
InputStream inputstream = null;
StringBuilder stringbuilder = null;
String result = null;

//  retrieved message
String retrieveMsgId[] , uploaded_content_type[];
private LayoutInflater mInflater;
private Vector<RowData> data;
RowData rd;
CustomAdapter adapter;
int pos=1;
String content_type_split[];
String content_date_split[];
String sender_member_image_split[], uploaded_content_id_split[];
String content_path_split[], content_id_split[];
String imageAudio_image_split[];

Bitmap bitmap;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.viewmsglist);

    //===================================================
    // Get member id from local database
    sp_memberid = getSharedPreferences(memberid, MODE_PRIVATE);
    if(sp_memberid.contains("memberid")==true)
    {memid = sp_memberid.getInt("memberid", 0);}
    Log.e("homepage member id == ", "~ "+memid);
    //===================================================

    try{
        //http post
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost("http://localhost/project/viewmessage.php?memberid="+memid);
        //httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); //encode a list of NameValuePair objects suitable for HTTP calls
        HttpResponse response = httpclient.execute(httppost); // to make an HTTPPOST call with the HttpClient
        HttpEntity entity = response.getEntity();
        inputstream = entity.getContent();
    }
    catch(Exception e){
        Toast.makeText(getBaseContext(),e.toString() ,Toast.LENGTH_LONG).show();
    }

    //Convert response to string  
    try
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputstream,"UTF-8"));

        stringbuilder = new StringBuilder();

        String line = null;

        while ((line = reader.readLine()) != null) 
        {
            stringbuilder.append(line + "\n");
        }

        inputstream.close();

        result = stringbuilder.toString();
    }
    catch(Exception e)
    {
        Toast.makeText(getBaseContext(),e.toString() ,Toast.LENGTH_LONG).show();
    }
    //END Convert response to string   
    try{
        JSONArray jArray = new JSONArray(result);
        JSONObject json_data=null;
        if(jArray.length() == 0)
        {
            Toast.makeText(getApplicationContext(), "Tiada mesej", Toast.LENGTH_SHORT).show();
        }
        else
        {
            for(int i=0;i<jArray.length();i++)
            {
                json_data = jArray.getJSONObject(i);
                content_type = content_type + json_data.getString("uploadedcontenttype")+",";
                content_path = content_path+"http://localhost/project/"+(String) json_data.getString("contentpath")+",";
                imageAudio_image = imageAudio_image + json_data.getString("imageaudiopath")+",";
                //r.add(json_data.getString("member_id") + json_data.getString("member_name") + json_data.getString("member_usernamepath"));
                content_id = content_id + json_data.getString("contentid")+",";
                imageaudio_id = imageaudio_id + json_data.getString("imageaudioid")+",";
                content_date = content_date + json_data.getString("contentdate")+",";
                over_contentid = over_contentid + json_data.getString("overallid")+",";
                uploaded_content_id = uploaded_content_id +  json_data.getString("uploadedcontentid")+",";
                sender_id = sender_id +  json_data.getString("senderid")+",";
                receiver_id = receiver_id + json_data.getString("receiverid")+",";
                read_status =read_status + json_data.getString("readstatus")+",";
                sender_member_image = sender_member_image + "http://localhost/project/www/"+json_data.getString("memberimage")+",";
            }
        }
        Log.e("retrieved ", "~ "+content_type + "@ " +  " # "+ content_path + " $ "+ sender_id);
    }
    catch(JSONException e1){
        Toast.makeText(getApplicationContext(), "Tiada mesej", Toast.LENGTH_SHORT).show();
        Log.e("erroe ", e1.toString() );
        //Toast.makeText(getBaseContext(),e1.toString() ,Toast.LENGTH_LONG).show();
    } catch (ParseException e1) {
        Toast.makeText(getBaseContext(),e1.toString() ,Toast.LENGTH_LONG).show();
    }

    // Split the data retrieved from database
    content_type_split = content_type.split(",");
    content_path_split = content_path.split(",");
    content_id_split = content_id.split(",");
    content_date_split = content_date.split(",");
    sender_member_image_split = sender_member_image.split(",");
    uploaded_content_id_split = uploaded_content_id.split(",");
    imageAudio_image_split = imageAudio_image.split(",");

    mInflater = (LayoutInflater) getSystemService(
            Activity.LAYOUT_INFLATER_SERVICE);
    data = new Vector<RowData>();
    for(int i=0;i<content_type_split.length;i++){

        try {
            rd = new RowData(i,content_type_split[i],content_date_split[i]);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        data.add(rd);
    }
    CustomAdapter adapter = new CustomAdapter(this, R.layout.list,
            R.id.title, data);
    setListAdapter(adapter);
    //getListView().setTextFilterEnabled(true);
}

public void onListItemClick(ListView parent, View v, int position,
        long id) {
    // Show details in another page
    Intent viewMsgIntent = new Intent(ViewMsgMain.this, ViewMsgDetails.class);
    viewMsgIntent.putExtra("content_type", content_type_split[position]);
    viewMsgIntent.putExtra("content_path", content_path_split[position]);
    viewMsgIntent.putExtra("sender_member_image", sender_member_image_split[position]);
    viewMsgIntent.putExtra("imageAudio_image", imageAudio_image_split[position]);
    startActivity(viewMsgIntent);
}
private class RowData {
    protected int mId;
    protected String mTitle;
    protected String mDetail;
    RowData(int id,String title,String detail){
        mId=id;
        mTitle = title;
        mDetail=detail;
    }
    @Override
    public String toString() {
        Log.e("rowdata",mId+" "+mTitle+" "+mDetail);
        return mId+" "+mTitle+" "+mDetail;
    }
}
private class CustomAdapter extends ArrayAdapter<RowData> {

    public CustomAdapter(Context context, int resource,
            int textViewResourceId, List<RowData> objects) {               

        super(context, resource, textViewResourceId, objects);
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {   

        ViewHolder holder = null;
        TextView title = null;
        TextView detail = null;
        ImageView i11=null;
        ImageView i112=null;
        RowData rowData= getItem(position);
        Log.e("content_type_split.length ", "## "+content_type_split.length+"   ~~ row id~~   "+ rowData.mId);
        if(null == convertView){
            convertView = mInflater.inflate(R.layout.list, null);
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        }
        holder = (ViewHolder) convertView.getTag();
        title = holder.gettitle();
        title.setText(rowData.mTitle);
        detail = holder.getdetail();
        detail.setText(rowData.mDetail);                                                     

        i11=holder.getImage();
        if(content_type_split[rowData.mId].equals("1"))
        {
            i11.setImageResource(R.drawable.imageicon2);
        }
        else if(content_type_split[rowData.mId].equals("2"))
        {
            i11.setImageResource(R.drawable.audioicon2);
        }
        else if(content_type_split[rowData.mId].equals("3"))
        {
            i11.setImageResource(R.drawable.videoicon2);
        }

        Log.e("get view ," , " ~ "+sender_member_image_split[rowData.mId]);

        i112=holder.getImage2();
        try {
            Log.e("enter bitmap ", "yes");
            bitmap = BitmapFactory.decodeStream((InputStream)new URL(sender_member_image_split[rowData.mId]).getContent());
            i112.setImageBitmap(bitmap);

        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return convertView;
    }
    private class ViewHolder {
        private View mRow;
        private TextView title = null;
        private TextView detail = null;
        private ImageView i11=null;
        private ImageView i112=null; 

        public ViewHolder(View row) {
            mRow = row;
        }
        public TextView gettitle() {
            if(null == title){
                title = (TextView) mRow.findViewById(R.id.title);
            }
            return title;
        }     

        public TextView getdetail() {
            if(null == detail){
                detail = (TextView) mRow.findViewById(R.id.detail);
            }
            return detail;
        }
        public ImageView getImage() {
            if(null == i11){
                i11 = (ImageView) mRow.findViewById(R.id.img);
            }
            return i11;
        }

        public ImageView getImage2() {
            if(null == i112){
                i112 = (ImageView) mRow.findViewById(R.id.img2);

            }
            return i112;
        }
    }
}

}

日志

            05-15 21:59:52.660: E/content_type_split.length(7388): ## 3   ~~ row id~~   0
            05-15 21:59:52.670: D/dalvikvm(7388): GC_CONCURRENT freed 352K, 11% free 9318K/10439K, paused 2ms+3ms
            05-15 21:59:52.690: E/get view ,(7388):  ~ http://localhost/project/www/username/kids.jpg
            05-15 21:59:52.690: E/enter bitmap(7388): yes
            05-15 21:59:52.720: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:52.740: E/content_type_split.length(7388): ## 3   ~~ row id~~   1
            05-15 21:59:52.740: E/get view ,(7388):  ~ http://localhost/project/www/username/1_2012512080548_DSC00701.JPG
            05-15 21:59:52.740: E/enter bitmap(7388): yes
            05-15 21:59:52.790: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:52.810: D/dalvikvm(7388): GC_FOR_ALLOC freed 562K, 14% free 9034K/10439K, paused 23ms
            05-15 21:59:52.810: I/dalvikvm-heap(7388): Grow heap (frag case) to 9.477MB for 614416-byte allocation
            05-15 21:59:52.850: D/dalvikvm(7388): GC_FOR_ALLOC freed <1K, 14% free 9633K/11079K, paused 22ms
            05-15 21:59:52.880: E/content_type_split.length(7388): ## 3   ~~ row id~~   2
            05-15 21:59:52.890: E/get view ,(7388):  ~ http://localhost/project/www/username/kids.jpg
            05-15 21:59:52.890: E/enter bitmap(7388): yes
            05-15 21:59:52.930: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:52.950: E/content_type_split.length(7388): ## 3   ~~ row id~~   0
            05-15 21:59:52.950: E/get view ,(7388):  ~ http://localhost/project/www/username/kids.jpg
            05-15 21:59:52.950: E/enter bitmap(7388): yes
            05-15 21:59:52.980: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:52.990: E/content_type_split.length(7388): ## 3   ~~ row id~~   1
            05-15 21:59:52.990: E/get view ,(7388):  ~ http://localhost/project/www/username/1_2012512080548_DSC00701.JPG
            05-15 21:59:52.990: E/enter bitmap(7388): yes
            05-15 21:59:53.040: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:53.060: D/dalvikvm(7388): GC_FOR_ALLOC freed 1064K, 19% free 9034K/11079K, paused 23ms
            05-15 21:59:53.100: E/content_type_split.length(7388): ## 3   ~~ row id~~   2
            05-15 21:59:53.100: E/get view ,(7388):  ~ http://localhost/project/www/username/kids.jpg
            05-15 21:59:53.100: E/enter bitmap(7388): yes
            05-15 21:59:53.130: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:53.170: D/dalvikvm(7388): GC_CONCURRENT freed 820K, 19% free 9033K/11079K, paused 2ms+2ms
            05-15 21:59:53.170: E/content_type_split.length(7388): ## 3   ~~ row id~~   0
            05-15 21:59:53.180: E/get view ,(7388):  ~ http://localhost/project/www/username/kids.jpg
            05-15 21:59:53.180: E/enter bitmap(7388): yes
            05-15 21:59:53.210: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:53.230: E/content_type_split.length(7388): ## 3   ~~ row id~~   1
            05-15 21:59:53.240: E/get view ,(7388):  ~ http://localhost/project/www/username/1_2012512080548_DSC00701.JPG
            05-15 21:59:53.240: E/enter bitmap(7388): yes
            05-15 21:59:53.280: W/System.err(7388): Error reading from ./org/apache/harmony/awt/www/content/image/jpeg.class
            05-15 21:59:53.320: D/dalvikvm(7388): GC_CONCURRENT freed 268K, 13% free 9640K/11079K, paused 3ms+2ms
            05-15 21:59:53.330: E/content_type_split.length(7388): ## 3   ~~ row id~~   2
            05-15 21:59:53.350: E/get view ,(7388):  ~ http://localhost/project/www/username/kids.jpg
            05-15 21:59:53.350: E/enter bitmap(7388): yes
4

2 回答 2

2

正如 Dheeresh Singh 所说,问题不应该是调用 getView() 的次数。尽管这确实突出了可能的问题。因为 getView() 可以并且将被无数次调用,所以 getView() 中的代码需要高效。您对 getView() 的实现有几个问题。

1) 内存不足问题 (OOM) 很可能是由位图引起的。

  • 当您完成位图时,它没有被正确处理,因为即使在 getView() 退出后它仍然驻留在内存中。这就是 Android 中位图的本质。调用 bitmap.recycle() 将释放此内存并应防止 OOM。

  • 调整位图大小或降低分辨率可以提高内存使用率。

2) 每次运行 getView() 时,每次都下载并解码所需的位图。

  • 这是不可取的,因为这些密集任务在 UI 线程上运行(活动在其上运行,并且所有 ui 更改都必须发生在该线程上)。如果完成这些任务的时间超过约 5 秒,Android 会将应用程序标记为停止并发出应用程序无响应 (ANR)。即使没有发生 ANR,ListView 的滚动性能也会很糟糕。

  • 为了解决这个问题,下载、解码和位图更改(如果需要)这些任务应该发生在另一个线程中(如AsyncTaskHandlerThread)。一个典型的场景是,当您需要位图时,您会触发 AsyncTask 或向位图处理线程发出请求。作为线程请求的一部分,应该提供一个侦听器,以便当位图在位图线程上准备就绪时,它将使用侦听器向 UI 线程发出信号以更新 ImageView。这个实现并不简单,但对于健壮的 Android 应用程序来说是必需的。

  • 一个重要的旁注:不要将 Activity 泄漏给其他线程。当发生泄漏并且 Activity 被 Android 销毁时(这种情况经常发生并且由于各种原因,方向变化就是其中之一),由于实例存在于另一个线程中,因此无法对 Activity 进行垃圾收集。然后,Android 会启动一个新的 Activity 实例,而死掉的 Activity 仍然存在。最终会发生 OOM。例如,在为位图线程创建侦听器时,不要将 ImageView(因为它具有 Activity 上下文)作为侦听器的一部分——除非您在 Activity 的 onDestroy() 中从位图线程中显式删除侦听器。这与 AsyncTask 不同 - 只需处理 onPostExecute() 中的所有 ui 更改。

    事件侦听器中的内存泄漏

  • 应该使用缓存来避免重复下载和处理位图。一种可能的实现方式是使用LruCache作为内存缓存,使用DiskLruCache作为磁盘缓存。

    http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

3) ViewHolder 使用。

  • 我不确定在其 ViewHolder 中引用“convertView”是否有用。这个循环引用的唯一用途是实现 getter,尽管这对于快速执行 getView() 来说效率略低。这将是 ViewHolder 作为 Activity 的内部类而不是 CustomAdapter 的典型实现。

    private class CustomAdapter extends ArrayAdapter<RowData> {
    
        public CustomAdapter(Context context, int resource,
                int textViewResourceId, List<RowData> objects) {               
    
            super(context, resource, textViewResourceId, objects);
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {   
    
            ViewHolder holder = null;
            RowData rowData= getItem(position);
            Log.e("content_type_split.length ", "## "+content_type_split.length+"   ~~ row id~~   "+ rowData.mId);
            if(null == convertView){
                convertView = mInflater.inflate(R.layout.list, null);
                holder = new ViewHolder(convertView);
                convertView.setTag(holder);
                holder.title = (TextView) convertView.findViewById(R.id.title);
                holder.detail = (TextView) convertView.findViewById(R.id.detail);
                holder.i11 = (ImageView) convertView.findViewById(R.id.img);
                holder.i112 = (ImageView) convertView.findViewById(R.id.img2);
    
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
    
            holder.title.setText(rowData.mTitle);
            holder.detail.setText(rowData.mDetail);                                                     
    
            if(content_type_split[rowData.mId].equals("1"))
            {
                holder.i11.setImageResource(R.drawable.imageicon2);
            }
            else if(content_type_split[rowData.mId].equals("2"))
            {
                holder.i11.setImageResource(R.drawable.audioicon2);
            }
            else if(content_type_split[rowData.mId].equals("3"))
            {
                holder.i11.setImageResource(R.drawable.videoicon2);
            }
    
            Log.e("get view ," , " ~ "+sender_member_image_split[rowData.mId]);
    
    
            try {
                Log.e("enter bitmap ", "yes");
                bitmap = BitmapFactory.decodeStream((InputStream)new URL(sender_member_image_split[rowData.mId]).getContent());
                holder.i112.setImageBitmap(bitmap);
    
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            return convertView;
        }
    }
    
    private class ViewHolder {
        TextView title = null;
        TextView detail = null;
        ImageView i11=null;
        ImageView i112=null;
    }
    
于 2012-05-31T01:47:51.207 回答
1

请看这个答案

多次调用自定义列表视图适配器 getView 方法,并且顺序不一致

这不是问题,绝对不能保证调用 getView() 的顺序或调用次数。

于 2012-05-15T14:20:14.003 回答