- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
好的,所以我的方法是这样的。我在 Activity
的 AsyncTask
中解码本地存储的加密和序列化对象。 Activity
使用 BaseAdapter
(HistoryAdapter) 来显示数据。 AsyncTask
显示一个 ProgressDialog
,直到解码完成。首次调用 onProgressUpdate()
时,取消 ProgressDialog
。到目前为止,一切都很好。接下来,在 onProgressUpdate()
中,HistoryAdapter 以常用方式通知更改,触发它的 getView()
方法。在 HistoryAdapter 的 getView()
中,运行第二个 AsyncTask
来修改创建的 convertView
并将数据设置到 View
.
这就是我失败的地方。我在 onProgressUpdate()
中膨胀最终布局,并在 convertView
上设置属性和数据在这里就好了。即使设置了所有数据,更改也不会显示...
因此,HistoryAdapter 中的 AsyncTask
本身实际上可以完美运行,只是更改不可见。我尝试了 SO 中提到的许多建议,例如使 convertView
无效,传递对 ListView
的引用并使用 invalidateViews()
(导致永恒循环但没有可见的变化,这是有道理的)。
我真的很想要这个,因为我真的不想在数据可用之前加载带有图像占位符的布局。我开始工作了,但看起来很讨厌,而且喜欢简单的出路。所以我需要 ListView
仅在进度完成时更新(添加项目)。有什么想法吗?
编辑:澄清一下:数据是在正确的时间在适配器上设置的。问题是,适配器首先创建一个空白的View
(占位符)(不知道有什么其他方法,否则你会在getView中得到一个NullPointerException),然后这个View
在 onProgressUpdate()
中被另一个 View
膨胀/替换。第二个 View
应该是可见的。这有点管用,因为我可以在新膨胀的 View 上获取和设置属性。所做的更改是不可见的,我仍然看到最初创建的空白 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 的引用,但是话又说回来,它是正在进行中的代码。简化示例...
编辑
好吧,看来我的方法一开始就很糟糕,导致需要在我的 HistoryAdapter
中有一个 AsyncTask
。我解决了几个问题来解决这个问题。
PropertyChangeListener
。这实现了一个 OnSharedPreferenceChangeListener
,以便在我需要的数据发生变化时通知它。然后将更改传播到任何感兴趣的监听器。数据在应用程序启动时被解密并存储在一个全局变量中,该变量在整个应用程序中都是可访问的。将其视为他所说的“内存缓存”。AsyncTasks
。ListView
所需的图像存储在 SparseArray
中,因此它们只创建和存储一次。不要为此使用 HashMap
!此外,如果图像不在 HashMap
中,则仅为当前 View
创建图像(图像不是唯一的)。 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
最佳答案
Dmmh,你说的是你想做的(所以我需要 ListView 仅在进度完成时更新(添加项目))和你正在做的(getView 中的 AsyncTask)是完全相反的事情。
getView 末尾的 AsyncTask 用于(但以不同的方式)延迟图像加载,即显示大图像并显示文本 + 图像占位符,直到下载完成。
您尝试在第一个 AsyncTask 中逐渐填充适配器的数据源,但每次您通知观察者数据集的更改时,您将对数据集中的每个项目进行另一个 getView 调用周期。不好。
首先,永远不会,永远不会!!!假设 getView 会为您提供一个 convertview,这个位置之前已经填充了。所以你必须要么用新值重新填充转换 View ,要么关闭性能优化并在每次被要求时提供新 View 。 ListView 无法关闭回收尝试,因为这是 ListView 的本质,它是基于此构建的功能。
其次(源自第一个),绝对避免仅将耗时(或用户输入)数据存储到新创建的 View 中。 View 来来去去,您不想走很长的路来获取昂贵的数据(或者只是丢失用户输入)。唯一的部分排除是大图像延迟加载的简单无效实现。为了减少内存使用,他们只下载用户当前可见的图像。更有效的实现使用 off-ListView 缓存。
所以,如果你真的想让你的 ListView 中的项目一次添加一个,但又充满荣耀,你应该:
0*。如果您必须加载用户提供的图标并且这需要花费大量时间来加载(我不理解您最初的帖子)创建一个空的 ArrayList 来缓存加载的图标并通过索引访问它们。如果所有图像都已通过某个索引可用,请忽略此问题。
class DecryptedRecord {
String title = "";
String summary = "";
String date = "";
int contactViewIndex = -1;
int contactOptionsIndex = -1;
int contactImageIndex = -1;
int typeImageIndex = -1;
int optionsImageIndex = -1; //if option icon varies. ignore otherwise
}
声明 DecryptedRecord 类,包含填充 View 所需的数据,例如:
在您的 AsyncTask 中:加载每个 HistoryHolder 后,执行“重解密”并用值填充新的 DecryptedRecord。如果需要加载自定义图片(见编号0*),在这里加载它并将它的索引存储在缓存中(如果0*无关则忽略它)。使用 setTag() 将填充的 DecryptedRecord 附加到 HistoryHolder。调用 publishProgress(HistoryHolder)
在 onProgressUpdate 中,只需将 HistoryHolder 添加到 Adapter 并调用 historyAdapter.notifyDataSetChanged();
在 getView() 中,如果 convertView 为空,则同步膨胀 View ,并且在所有情况下用从 HistoryHolder.getTag 获取的 DecryptedRecord 中的数据填充它( ).包括在内,在您的 ImageView 上调用 setImageBitmap(),按索引在相应列表中寻址必要的位图。
这应该做你想做的。请,如果您有错误/问题,请尝试在您的问题中包含完整的代码,否则将很难理解您的情况的细节。希望对您有所帮助。
关于android - 当 AsyncTask 完成时强制 BaseAdapter 更新它的 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16677936/
我一直很难编辑我的 .htaccess 文件来一起做这三件事。我已经能够分别获得每个部分,但我只是不明白逻辑流程如何使它们全部工作。 这是我能够使用 bluehost support 上的演示进行整合
我制作的宏将模板工作簿保存为两个单独的文件。每个测试保存一个(位置 1、2、3 或 4),然后在另一个宏中使用每个测试的数据。第二个是保留用于备份的原始数据文件。现在的问题是每次我在每个位置运行测试并
我正在写一篇关于如何使用 OCaml 的模块系统而不是 Java 的 OO 系统(一个有趣的视角)的博客文章。我遇到了一些我不理解的关于强制的事情。下面是一个基本模块和两个包含它的模块: module
我有一段将被执行多次(5,000+)的代码,以及一个仅在第一次为真的 if 语句。我曾想过使用“FIRST”变量并每次都进行比较,但每次都检查它似乎是一种浪费,即使我知道它不需要。 bool FIRS
首先,我是 Perforce 的新手,我主要通过其文档进行学习。 因此,我们即将从 CVS 迁移到 Perforce,我最近学到了一个避免更改每个工作区的 P4CLIENT 的好方法,即在工作区根目录
我正在为一段代码编写测试,其中包含我试图涵盖的 IOException 捕获。 try/catch 看起来像这样: try { oos = new ObjectOutputStream(new
我正在尝试在新闻项目滚动之间添加延迟。我知道 $.each() 通过不等待动画完成来完成其工作,但我想知道如何制作它,以便一次向上滚动一个项目并等到最后一个动画完成后再继续在循环中。 $(functi
假设已经编写了一个方法,需要一个排序列表作为其输入之一。当然这将在代码中进行注释和记录,param 将被命名为“sortedList”,但如果有人忘记,则会出现错误。 有没有办法强制输入必须排序?我正
我正在尝试将传入请求重定向到 https://www.domain.com/和所有 https://www.domain.com/ {所有页面}并且没有什么麻烦。我试过的方法: 添加此行:Redire
我将如何实现以下内容: title_selection = raw_input("Please type in the number of your title and press Enter.\n%
我有一个登录表单,我需要强制关闭自动完成功能。我试过了 jquery: $('#login').attr("autocomplete", "off"); HTML: Javascript:docume
我想知道我应该怎么做才能强制从 dev 分支 merge 到我的 master 分支?使用“git merge dev”会导致很多冲突。但是,我不想单独处理它们。相反,我只是想使用我的 dev 分支中
当安装 Hl7.Fhir.DSTU2 和 Hl7.Fhir.R4 这两个 Nuget 包时,我们得到如下信息: DSTU2 包似乎在使用 Hl7.Fhir.Support.Poco 版本 3.4.0
我正在尝试让一个功能组件在 testFn 执行时强制重新渲染。我想使用状态来做到这一点(如果有更好的方法请说出来),这似乎成功地强制重新渲染但只有两次,然后什么都没有。 我构建了一个简单的演示来模拟这
默认情况下,g++ 似乎会省略未使用的类内定义方法的代码。示例 from my previous question : struct Foo { void bar() {} void baz(
我正在尝试使用 here 中介绍的技术使我的网站背景以比内容慢的速度滚动。我不希望背景固定,只希望更慢。 这是 HTML 的样子: .parallax { perspective: 1px;
我能找到的最相似的问题是 'how to create a row of scrollable text boxes or widgets in flutter inside a ListView?'
我有以下 eslint 配置: "object-curly-newline": ["error", { "ImportDeclaration": "never",
我正在使用 TinyMCE 插件并将 valid_elements 选项设置为: "a[href|target:_blank],strong/b,em/i,br,p,ul,ol,li" 即使没有列出数
您好,我想使用以下命令放置多行描述 p4 --field Description="MY CLN Header \\n my CLN complete description in two -thre
我是一名优秀的程序员,十分优秀!