好的,所以我的方法是这样的。我正在解码本地存储的加密和序列化对象AsyncTask
。Activity
使用Activity
( BaseAdapter
HistoryAdapter) 来显示数据。显示直到解码完成AsyncTask
。ProgressDialog
当onProgressUpdate()
第一次被调用时,ProgressDialog
被取消。到目前为止,一切都很好。接下来,在 中onProgressUpdate()
,HistoryAdapter 以常见的方式被通知更改,触发它的getView()
方法。在 HistoryAdapter 中getView()
,第二次AsyncTask
运行以修改创建convertView
的数据并将数据设置到View
.
这就是我失败的地方。我在 中膨胀最终布局,并在此处onProgressUpdate()
设置属性和数据就可以了。convertView
即使设置了所有数据,更改也不会显示...
因此,AsyncTask
HistoryAdapter 本身实际上可以完美运行,只是不可见更改。我尝试了 SO 上提到的许多建议,例如使无效convertView
、传递对ListView
和使用的引用invalidateViews()
(导致永恒循环但没有可见的变化,这是有道理的)。
我真的很想要这个,因为我真的不想在数据可用之前加载带有图像占位符的布局。我开始工作了,但看起来很讨厌,喜欢简单的出路。所以我ListView
只需要在进度完成后更新(添加项目)。有任何想法吗?
编辑:澄清:数据是在正确的时间设置在适配器上的。问题是,适配器首先创建一个空白View
(占位符)(不知道任何其他方式,否则您将在 getView 中得到 NullPointerException),View
然后View
在onProgressUpdate()
. 第二个View
是应该可见的。这有点工作,因为我可以在新膨胀的视图上获取和设置属性。这些更改是不可见的,我仍然看到最初创建的空白视图。我想在每个添加的项目上更新 ListView,而不是在所有项目都加载完成后...
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
//convertView = mInflater.inflate(R.layout.history_list_item_holo_dark, null);
convertView = mInflater.inflate(R.layout.blank, parent, false); // CHEAT: LOAD BLANK/ EMPTY LAYOUT
HistoryHolder item = history.get(position);
new AsyncRequest(convertView, position).execute(item);
}
this.parent = parent;
return convertView;
}//end method
static class ViewHolder {
TextView TITLE;
TextView SUMMARY;
TextView DATE;
ImageView CONTACT_ICON;
ImageView OPTIONS_ICON;
ImageView TYPE_ICON;
}//end class
private class AsyncRequest extends AsyncTask<HistoryHolder, View, View> {
ViewHolder holder = null;
String title = "";
String summary = "";
String date = "";
long id = 0;
private View convertView = null;
private String type = "";
private int position = -1;
public AsyncRequest(View superView, int position){
this.convertView = superView;
this.position = position;
}//end constructor
@Override
protected View doInBackground(HistoryHolder... item) {
Thread.currentThread().setName(getClass().getSimpleName());
if (item[0].TYPE.equals("log")){
//massive decrypting going on here 50-100 ms
//values like title and summray set here
}
if (item[0].TYPE.equals("sms")){
//massive decrypting going on here 50-100 ms
//values like title and summray set here
}
publishProgress(convertView);
return convertView;
}// end method
@Override
protected void onProgressUpdate(View... view) {
super.onProgressUpdate(view);
}// end method
@Override
protected void onPostExecute(View result) {
super.onPostExecute(result);
if (!MathUtils.isEven(position)){
result .setBackgroundColor(context.getResources().getColor(R.color.darker)); //this works as expected, list items vary in color
} else {
result .setBackgroundColor(context.getResources().getColor(R.color.medium_dark));
} //this works as expected, list items vary in color
result = mInflater.inflate(R.layout.history_list_item_holo_dark, parent, false);
result.setTag(id);
holder = new ViewHolder();
holder.TITLE = (TextView) result .findViewById(R.id.title);
holder.SUMMARY = (TextView) result .findViewById(R.id.summary);
holder.DATE = (TextView) result .findViewById(R.id.date);
holder.CONTACT_ICON = (ImageView) result .findViewById(R.id.icon);
holder.TYPE_ICON = (ImageView) result .findViewById(R.id.type);
holder.OPTIONS_ICON = (ImageView) result .findViewById(R.id.options);
holder.OPTIONS_ICON.setFocusable(false);
holder.OPTIONS_ICON.setTag(id);
holder.TITLE.setText(title); //this change doesnt show
holder.SUMMARY.setText(summary); //and so on
result .setTag(holder);
}//end method
}//end inner class
而且我知道我可以修改我的 AsynTask 并且我不需要在很多地方传递对 View 的引用,但话又说回来,它的代码正在进行中。简化示例...
编辑
好的,所以我的方法一开始似乎很糟糕,导致需要AsyncTask
在我的HistoryAdapter
. 我解决了几个问题来解决这个问题。
- 根据@Delyan 的建议,我决定在实际需要数据之前加载/解密数据是好的。我正在
PropertyChangeListener
为此使用。这实现了一个OnSharedPreferenceChangeListener
,以便它收到我需要的数据更改的通知。然后将更改传播给任何感兴趣的听众。数据在应用程序启动时被解密并存储在一个全局变量中,该变量在整个应用程序中都可以访问。将此视为他所指的“内存缓存”。 - 根据评论和接受的答案,现在解密是在后台完成的,因此不再需要
AsyncTasks
. - 为了进一步优化我的适配器的性能,我存储了
ListView
a所需的图像SparseArray
,因此它们只创建和存储一次。不要HashMap
为此使用 a !View
此外,仅当图像不在a中时才会为当前创建HashMap
图像(图像不是唯一的)。
public class HistoryAdapter extends BaseAdapter{
private static Context context = ApplicationSubclass.getApplicationContext_();
private Contacts contacts = Contacts.init(context);
private SparseArray<Drawable> c_images = new SparseArray<Drawable>();
private HashMap<Long, Drawable> contact_imgs = new HashMap<Long, Drawable>();
private ArrayList<HistoryHolder> history;
private LayoutInflater mInflater;
public HistoryAdapter(Context context) {
HistoryAdapter.context = context;
mInflater = LayoutInflater.from(context);
}//end constructor
...
public View getView(int position, View convertView, ViewGroup parent) {
final HistoryHolder item = history.get(position);
Drawable d = null;
if (c_images.get(position) == null){
if (!contact_imgs.containsKey(item.CONTACT_ID)){
if (item.IN_CONTACTS && item.CONTACT_ID != 0 && item.CONTACT_ID != -1){
Bitmap photo = contacts.getContactPhotoThumbnailByContactId(item.CONTACT_ID);
if (photo != null){
d = Convert.bitmapToDrawable(context, photo, 128, 128);
} else {
d = context.getResources().getDrawable(R.drawable.ic_contact_picture);
}
} else {
d = context.getResources().getDrawable(R.drawable.ic_contact_picture);
}
contact_imgs.put(item.CONTACT_ID, d);
}
}
c_images.put(position, contact_imgs.get(item.CONTACT_ID));
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.history_list_item_holo_dark, null);
holder = new ViewHolder();
holder.POSITION = position;
holder.TITLE = (TextView) convertView.findViewById(R.id.title);
holder.SUMMARY = (TextView) convertView.findViewById(R.id.summary);
holder.DATE = (TextView) convertView.findViewById(R.id.date);
holder.CONTACT_ICON = (ImageView) convertView.findViewById(R.id.icon);
holder.CONTACT_ICON.setTag(position);
holder.OPTIONS_ICON = (ImageView) convertView.findViewById(R.id.options);
holder.OPTIONS_ICON.setFocusable(false);
holder.OPTIONS_ICON.setTag(position);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.CONTACT_ICON.setBackgroundDrawable(c_images.get(position));
holder.TITLE.setText(item.TITLE);
holder.SUMMARY.setText(item.SUMMARY);
holder.SUMMARY.setMaxLines(2);
holder.DATE.setText(item.DATE);
if (!MathUtils.isEven(position)){
convertView.setBackgroundColor(context.getResources().getColor(R.color.darker));
} else {
convertView.setBackgroundColor(context.getResources().getColor(R.color.medium_dark));
}
return convertView;
}//end method
static class ViewHolder {
TextView TITLE;
TextView SUMMARY;
TextView DATE;
ImageView CONTACT_ICON;
ImageView OPTIONS_ICON;
int POSITION;
}//end inner class
}//end class