【问题标题】:Slow loading ListView with image and text.How to implement loader.callbacks?加载带有图像和文本的ListView慢。如何实现loader.callbacks?
【发布时间】:2014-05-28 18:05:48
【问题描述】:

我正在构建一个短信应用程序,其中列出了联系人图片、姓名、消息、对话日期。 我正在使用自定义适配器来列出它们。下面是代码

public class ConvRowAdapter extends ArrayAdapter<ConvItem> {
private Context my_context;
// View lookup cache
private static class ViewHolder {
    TextView name,body,date;
    ImageView img;
}
public ConvRowAdapter(Context context, ArrayList<ConvItem> ConvItems) {
   super(context, R.layout.convitem, ConvItems);
   my_context=context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
   // Get the data item for this position
   ConvItem ConvItem = getItem(position);    
   // Check if an existing view is being reused, otherwise inflate the view
   ViewHolder viewHolder; // view lookup cache stored in tag
   if (convertView == null) {
      viewHolder = new ViewHolder();
      LayoutInflater inflater = LayoutInflater.from(getContext());
      convertView = inflater.inflate(R.layout.convitem, null);
      viewHolder.img = (ImageView) convertView.findViewById(R.id.iv_photo);
      viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);
      viewHolder.date = (TextView) convertView.findViewById(R.id.tv_date);
      viewHolder.body = (TextView) convertView.findViewById(R.id.tv_body);
      convertView.setTag(viewHolder);
   } else {
       viewHolder = (ViewHolder) convertView.getTag();
   }
   // Populate the data into the template view using the data object
   if(ConvItem.getPhotoUri()!=null)
   {
       Bitmap bitmap=BitmapFactory.decodeStream(my_context.getContentResolver().openInputStream(ConvItem.getPhotoUri()));
       viewHolder.img.setImageBitmap(bitmap);//Image is set
   }
   else
   {
       Bitmap bitmap=BitmapFactory.decodeResource(my_context.getResources(),R.drawable.contact_blue);
       viewHolder.img.setImageBitmap(bitmap);
   }
   if(ConvItem.getDisplayName()==null)
   viewHolder.name.setText(ConvItem.getAddress());//Phone number set
   else
   viewHolder.name.setText(ConvItem.getDisplayName());//If phone number exists in contacts display contact name
   viewHolder.date.setText(ConvItem.getDate());//set date
   viewHolder.body.setText(ConvItem.getBody());//setting the body of the message
   // Return the completed view to render on screen
   return convertView;
}
}

显示列表需要 8-9 秒。 有没有办法提高速度? 如果是这样,请发布正确的方法。

提前致谢:)

Edited:

为了检查加载延迟是否是由加载图像引起的,我尝试删除所有照片设置语句并运行它。仍然加载需要相同的时间。 通过使用简单的光标适配器,我可以立即显示正文、日期和消息。但是为了与他们一起显示照片,我尝试使用自定义适配器。 这是将所有短信返回到arraylist的函数。请检查代码的效率:

public ArrayList<ConvItem> getSMS(){
    ArrayList<ConvItem> ConvItems = new ArrayList<ConvItem>();
    Uri uriSMSURI = Uri.parse("content://mms-sms/conversations?simple=true");
    Cursor cur = getActivity().getContentResolver().query(uriSMSURI, null, null, null,
            "date desc");
    cur.moveToFirst();
    while (!cur.isAfterLast()) {
        ConvItem ConvItem = new ConvItem();
        String address = null, body = null, dname = null,res=null,id_dummy=null;
        Long date=null;
        Uri uriphotoid=null;
        //to obtain address from canonical-addresses
        res = cur.getString(cur.getColumnIndex("recipient_ids"));
        Uri ad =Uri.parse("content://mms-sms/canonical-addresses/");
        Cursor curad=getActivity().getContentResolver().query(ad, null,null, null, null);
        curad.moveToFirst();
        while(!curad.isAfterLast())
        {
            id_dummy=curad.getString(curad.getColumnIndexOrThrow("_id"));
            if(id_dummy.equals(res))
            address=curad.getString(curad.getColumnIndexOrThrow("address"));
            curad.moveToNext();
        }
        curad.close();
        body = cur.getString(cur.getColumnIndexOrThrow("snippet"));
        date = cur.getLong(cur.getColumnIndexOrThrow("date"));
        Date datenew=new Date(date);
        String formatted_date=new SimpleDateFormat("  "+"dd/MM/yyyy").format(datenew);
        thread_id = cur.getString(cur.getColumnIndexOrThrow("_id"));
        Long ContactID = fetchContactIdFromPhoneNumber(address);
        //uriphotoid = getPhotoUri(ContactID);
        dname = getcontactname(address);
        ConvItem.setDisplayName(dname);
        ConvItem.setThreadId(thread_id);
        ConvItem.setAddress(address);
        //ConvItem.setPhotoUri(uriphotoid);
        ConvItem.setDate(formatted_date);
        ConvItem.setBody(body);
        ConvItems.add(ConvItem);
        cur.moveToNext();
    }
    cur.close();
    return ConvItems;
    }

此函数在我的主活动类中的 onCreate 方法上运行。


我使用 loader.callbacks 来纠正延迟问题。

public class InboxLoaderFragment extends Fragment implements LoaderCallbacks<Cursor>{

private static final int LOADER_ID = 1;//identify which loader
LoaderManager lm;
SimpleCursorAdapter mAdapter;
ListView lv;
private LoaderManager.LoaderCallbacks<Cursor> mCallbacks;

public InboxLoaderFragment(){}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootview=inflater.inflate(R.layout.inboxloaderfragment,container,false);  
    lv=(ListView)rootview.findViewById(R.id.list);
    // Create an empty adapter we will use to display the loaded data.

    String[] uiBindFrom = {"recipient_ids","recipient_ids","snippet"};
    int[] uiBindTo = {R.id.iv_photo,R.id.tv_name,R.id.tv_body};

    mAdapter = new SimpleCursorAdapter(getActivity(),R.layout.convitem,null,uiBindFrom,uiBindTo, 0);

    mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {

        @Override
        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {

            switch(view.getId()) 
            {
            case R.id.iv_photo:
                String res=null,address=null;
                //to obtain address from canonical-addresses
                res = cursor.getString(cursor.getColumnIndex("recipient_ids"));
                address=getadd(res);
                Long ContactID = fetchContactIdFromPhoneNumber(address);
                Uri uriphotoid = getPhotoUri(ContactID);
                setcontactimage(uriphotoid,view);
                //set photo using uri
                return true;

            case R.id.tv_name:
                String res1=null,address1=null;
                res1 = cursor.getString(cursor.getColumnIndex("recipient_ids"));
                address1=getadd(res1);//to obtain address from canonical-addresses
                String dname = getcontactname(address1);
                if(dname!=null)//contact exits
                ((TextView)view).setText(dname);//contact exists
                else
                ((TextView)view).setText(address1);//set display name
                return true;

            case R.id.tv_body:
                String body = cursor.getString(cursor.getColumnIndexOrThrow("snippet"));
                ((TextView)view).setText(body);//set message body
                return true;

            default:
            return false;
            }
        }
    });
    lv.setAdapter(mAdapter);
    mCallbacks=this;
    lm = getLoaderManager();
    //Initiating the loader
    lm.initLoader(LOADER_ID, null,mCallbacks);
    return rootview;
}
@Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(
        int arg0, Bundle arg1) {
    Uri baseUri = Uri.parse("content://mms-sms/conversations?simple=true");
    return new CursorLoader(getActivity(), baseUri,
               null, null, null,"date desc");
}
@Override
public void onLoadFinished(
        android.support.v4.content.Loader<Cursor> arg0, Cursor arg1) {
    switch (arg0.getId()) {
      case LOADER_ID:
        mAdapter.swapCursor(arg1);
        break;
    }
    // The listview now displays the queried data
}
@Override
public void onLoaderReset(android.support.v4.content.Loader<Cursor> arg0) {

    mAdapter.swapCursor(null);
}

}///main activity

现在应用加载速度非常快。但是滚动很慢。如何在自定义的 simplecursoradapter 或 cursoradapter 中实现 viewholder 设计模式?

【问题讨论】:

  • 对于初学者来说,不要使用数组适配器。使用游标适配器,因为选择查询将比将所有 ConvItem 从数据库加载到内存中更快。
  • 另一个有相关答案的问题:Lazy load of Images in ListView
  • 你说的是 simplecursoradapter 对吧?但是如何为每一行设置照片呢?

标签: android android-asynctask android-arrayadapter loader android-cursorloader


【解决方案1】:

有没有办法提高速度?

将您的照片加载移动到后台线程,可能通过使用像 Picasso 这样的图像管理库。

除此之外,使用 Traceview 和其他工具来具体确定您的问题所在。

【讨论】:

  • 你能举例说明移动照片加载到后台线程吗?
  • @user3370397:您可以单击我的答案中的链接并阅读毕加索文档。他们的 GitHub 存储库有一个示例应用 IIRC,这是另一个(也演示了他们的 Retrofit 库的使用):github.com/commonsguy/cw-omnibus/tree/master/HTTP/Picasso
  • 感谢您的评论。但是当我尝试删除所有照片设置语句并运行代码时,它需要相同的延迟量。请检查编辑后的帖子:)
  • @user3370397:然后,正如我在回答中指出的那样,使用 Traceview 来确定您的时间都花在了哪里。您可能会发现这一切都在您的 N 个query() 调用中。
  • 我了解到无法有效管理查询是这里存在的问题。可以使用 Loader.Callbacks 进行纠正。有人可以帮我在这段代码中实现加载器吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
相关资源
最近更新 更多