如何在 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 秒以上才能开始使用应用程序。
我试图做的是找到一种方法来逐步加载每一行,并避免等待每一行加载后才能开始使用应用程序。我试过AsyncTasks
、Handlers
、Threads
、Hashmaps
.. 但我可以找到一种方法来管理这个任务。
我的活动是一个 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】:您应该在MessageListAdapter
的getView()
方法中进行,而不是解码所有位图并检索所有记录。在构造函数中传递 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?的主要内容,如果未能解决你的问题,请参考以下文章