如何在 OnCreate 之后逐步创建位图和字符串更新的 ListView?

Posted

技术标签:

【中文标题】如何在 OnCreate 之后逐步创建位图和字符串更新的 ListView?【英文标题】:How can I create a ListView of bitmap and string updating progressively after OnCreate? 【发布时间】:2012-01-12 04:22:21 【问题描述】:

我在主要活动上有一个ListView,它在左侧显示一个联系人图片,在每一行的右侧显示一个文本视图。一切正常,但问题是当应用程序启动时,当有很多消息时,用户必须等待大约 10 秒以上才能开始使用应用程序。

我试图做的是找到一种方法来逐步加载每一行,并避免等待每一行加载后才能开始使用应用程序。我试过AsyncTasksHandlersThreadsHashmaps.. 但我可以找到一种方法来管理这个任务。

我的活动是一个 ListActivity。

活动的列表视图使用带有参数的自定义适配器(this,smsarray,picturearray)。 smsarray 是一个ArrayList<String>,包含每条短信的字符串,picturearray 是一个ArrayList<Bitmap>,其中包含每条短信的位图格式的联系人图片。

我有一个方法getSMSData(),它在光标的帮助下获取短信字符串和位图,并将字符串放在 smsarray 上的索引 0 处,并将位图放在图片数组上的索引 0 处,用于启动时的每个联系人。

public class MessageList extends ListActivity 

static List<String> smsarray;   static List<Bitmap> picturearray;
static MessageListAdapter smsadapter;


@Override
protected void onCreate(Bundle savedInstanceState) 

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    smsarray = new ArrayList<String>();
    picturearray = new ArrayList<Bitmap>();

    getSMSData();

    smsadapter = new MessageListAdapter(this,smsarray,picturearray);    
    getListView().setAdapter(smsadapter);



public void getSMSData() 

        Bitmap defaultbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.default_contact_picture);
        Bitmap contactbitmap;
        Cursor cursor = getContentResolver().query(Uri.parse("content://sms/inbox"),new String [] "person","address","body","date" , null, null,"date ASC");
        String[] displayname = new String[]ContactsContract.Contacts.DISPLAY_NAME;
        String name;
        String person;
        String address;
        String date;
        String body;
        int id; Cursor contactcursor;

            while (cursor.moveToNext()) 

            person = cursor.getString(cursor.getColumnIndex("person"));
            address = cursor.getString(cursor.getColumnIndex("address"));
            date = cursor.getString(cursor.getColumnIndex("date"));
            body = cursor.getString(cursor.getColumnIndex("body"));


            if (person != null)


                contactcursor = getContentResolver().query(Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, person),displayname, null, null, null);
                contactcursor.moveToFirst();
                name = contactcursor.getString(0);

                id = Integer.parseInt(person);
                InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(), ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id));
                contactbitmap = null;

                if (input == null) 
                    contactbitmap = defaultbitmap;

                 else 
                    contactbitmap = BitmapFactory.decodeStream(input);
                

                if (contactbitmap != null)
                    picturearray.add(0,contactbitmap);
                else 
                    picturearray.add(0,defaultbitmap);
                

                smsarray.add(0,getResources().getString(R.string.From) +" "+name+" "+"\n"+getResources().getString(R.string.Number)+" "+address+" " +"\n"+getResources().getString(R.string.At) +" "+date+"\n"+getResources().getString(R.string.Message)+" "+body);


            

            if (person == null) 
                picturearray.add(0,defaultbitmap);
                smsarray.add(0,getResources().getString(R.string.From) +" "+getResources().getString(R.string.Unknown)+" "+"\n"+getResources().getString(R.string.Number)+" "+address+" " +"\n"+getResources().getString(R.string.At) +" "+date+"\n"+getResources().getString(R.string.Message)+" "+body);

            

        

    




public class MessageListAdapter extends ArrayAdapter <String> 

final Context vcontext;
final List<String> varray;
final List<Bitmap> vpicture;
final LayoutInflater layoutinflater; 

public MessageListAdapter (Context context,List<String> smsarray, List<Bitmap> picturearray) 
    super(context, 0);
    vcontext = context;
    varray = smsarray;
    vpicture = picturearray;
    this.layoutinflater = LayoutInflater.from(context);

    

public int getCountpicture() 

    return vpicture.size();


public Bitmap getItempicture(int position) 

    return vpicture.get(position);


public long getItemIdpicture(int position) 

    return position; 


public int getCount() 

    return varray.size();


public String getItem(int position) 

    return varray.get(position);


public long getItemId(int position) 

    return position; 


public  class ViewHolder 
    TextView messagetext;
    ImageView image;


public View getView(int position, View convertView, ViewGroup parent) 

    ViewHolder holder;

    if (convertView == null)
        convertView = layoutinflater.inflate(R.layout.listitem, null);
        holder = new ViewHolder ();

        holder.messagetext = (TextView) convertView.findViewById(R.id.messagetext);
        holder.image = (ImageView) convertView.findViewById(R.id.contactimage);
        convertView.setTag(holder);

     else 
        holder = (ViewHolder) convertView.getTag();
    

    holder.image.setImageBitmap(vpicture.get(position));
    holder.image.setPadding(2, 1, 0, 0);

    holder.messagetext.setText(varray.get(position));
    holder.messagetext.setPadding(10, -1, 10, 5);

    return convertView;




感谢您的宝贵帮助。

【问题讨论】:

【参考方案1】:

您应该在MessageListAdaptergetView() 方法中进行,而不是解码所有位图并检索所有记录。在构造函数中传递 Cursor 并在适配器内部使用它。

编辑:

你可以将你的 getSMSData() 方法修改成这样:

public Cursor getSMSData() 
     Cursor cursor = getContentResolver().query(Uri.parse("content://sms/inbox"),new String [] "person","address","body","date" , null, null,"date ASC");
     return cursor;

并在您的onCreate 中使用此光标创建MessageListAdapter,如下所示:

Cursor cursor = getSMSData();
smsadapter = new MessageListAdapter(this, cursor);

修改MessageListAdapter构造函数接收并保存光标:

public MessageListAdapter (Context context,Cursor cursor) 
    super(context, 0);
    vcontext = context;
    vcursor = cursor;
    this.layoutinflater = LayoutInflater.from(context); // alternately, you could use the View.inflate() method

然后在适配器的getView 方法中使用此光标:

public View getView(int position, View convertView, ViewGroup parent) 
    // ...
    vcursor.moveToPosition(position);
    // Now use this cursor to populate your convertView
    return convertView;

这样,您只需为用户可见的行加载数据。我希望这会有所帮助。

如果您认为解码每条记录的联系人图片(每次调用 getView 方法)会减慢您的速度,您可以考虑将联系人图片保存在 Map 中(但不要一开始就通过迭代整个光标。这会让你回到第一格)并从那里加载它。 您也可以考虑使用AsyncTask 加载联系人图片,但由于您使用的是convertView,因此您需要小心。

【讨论】:

感谢您的回答; ) 我会努力的。你能指导我多一点我应该怎么做,它肯定会让我从这个负担中解脱出来,我的应用程序快完成了。谢谢。 @user1079001 我已将代码 sn-ps 添加到我的答案中。希望对您有所帮助。 非常感谢您的帮助。它肯定应该以这种方式工作 =))【参考方案2】:

我已经设法通过 CursorAdapter 的设置完成了所有工作。现在,我的适配器在我的 bindView 方法中直接使用光标获取联系人的号码、日期、消息和 id(如果存在),但是如果有 id,我不知道如何设置联系人的姓名。我认为这会起作用:

public void bindView(View view, Context context, Cursor cursor) 

String contact = cursor.getString(cursor.getColumnIndex("person"));
TextView contacttext = (TextView) view.findViewById(R.id.from);
             String name = "";

                if(contact == null) 
                    name = "unknown";
                

                if(contact != null) 
                    Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI,contact);
                    Cursor contactnamecursor = getContentResolver().query(uri, new String[]ContactsContract.Contacts.DISPLAY_NAME, null, null, null);
                    name = contactnamecursor.getString(contactnamecursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                

             contacttext.setText(name);

但似乎我无法在我的 CursorAdapter 中使用新光标。当我滚动列表时它给了我一个例外(当它到达应该显示联系人姓名的行时,通常)为什么我不能使用我的新联系人名称光标?我也尝试使用适配器的光标,但它也给了我一个例外......我会尝试不同的方法,但如果你有答案,了解它为什么失败应该有助于我和其他读者提高他们的知识; )

【讨论】:

我发现了问题!我只是忘了添加contactnamecursor.moveToFirst();在名称之前 = 联系人姓名光标......

以上是关于如何在 OnCreate 之后逐步创建位图和字符串更新的 ListView?的主要内容,如果未能解决你的问题,请参考以下文章

在扩充XML文件之后,不会调用onCreate()

是否可以在OnStop()上回收所有数据并使用保留片段?

如何逐步规划软件项目?

是否可以在 OnStop() 回收所有数据并使用保留片段?

将视图添加到窗口时如何获取视图宽度和高度?

如何在 LAWSUIT 上使用图像创建自己的位图字体?