我为我的 Android 应用程序运行了以下单例
public class ListsApplication extends Application {
public DbxDatastoreManager datastoreManager;
public HashMap<String, ViewItemContainer> itemsSync;
public Typeface Font;
public boolean Fetch;
private static ListsApplication singleton;
public static ListsApplication getInstance() {
return singleton;
}
@Override
public void onCreate() {
super.onCreate();
singleton = this;
itemsSync = new HashMap<>();
Font = Typeface.createFromAsset(getAssets(), "fonts/GoodDog.otf");
Fetch = true;
}}
然后从 Home 活动中,我通过
ListsApplication app = app.getInstance
在 Home 活动中,我设置了一个侦听器,只要在线数据存储发生变化,就会从数据存储在线服务器触发
private void setUpListeners() {
app.datastoreManager.addListListener(new DbxDatastoreManager.ListListener() {
@Override
public void onDatastoreListChange(DbxDatastoreManager dbxDatastoreManager) {
// Update the UI when the list of datastores changes.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
app.Fetch = true;
Home.this.updateList();
app.Fetch = false;
}
}, 7000/* 3sec delay */);
Toast toast = Toast.makeText(getApplicationContext(), "RECEIVED", Toast.LENGTH_SHORT);
toast.show();
}
});
updateList();
app.Fetch = false;
}
在运行 updateList() 之前我允许一些时间,因为对数据存储的更新不是原子的,因此在线数据存储上的所有行需要大约 2 秒,暂时忽略 app.Fetch,我稍后会解释。
updateList() 清除必须填充 listAdapter 并运行 adapter.notifyDataSetChanged() 的项目的 ArrayList
在我的自定义 listAdapter 中,我将 getView 设置如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder mHolder;
if (convertView == null) {
/*Toast toast = Toast.makeText(context, "nullConvertView", Toast.LENGTH_SHORT);
toast.show();*/
mHolder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listitem, parent, false);
mHolder.PetName = (TextView) convertView.findViewById(R.id.PetName);
mHolder.BuyFood = (ImageView) convertView.findViewById(R.id.PetBuyFood);
mHolder.PetImage = (RoundedImageView) convertView.findViewById(R.id.PetImage);
convertView.setTag(mHolder);
} else {
mHolder = (ViewHolder) convertView.getTag();
}
updateItem(mHolder, this.getItem(position));return convertView;}
和 updateItem(mHolder, this.getItem(position))
public void updateItem(final ViewHolder currentViewFromList, final DbxDatastoreInfo info){
app = ListsApplication.getInstance();
if (app.itemsSync.containsKey(info.id) && !app.Fetch){
/*Toast toast = Toast.makeText(context, "not fetching "+info.title, Toast.LENGTH_SHORT);
toast.show();*/
ViewItemContainer cont = app.itemsSync.get(info.id);
currentViewFromList.PetName.setTypeface(app.Font);
currentViewFromList.PetName.setText(cont.PetName);
currentViewFromList.PetImage.setImageBitmap(cont.PetImage);
if (cont.BuyFood) currentViewFromList.BuyFood.setVisibility(View.VISIBLE);
else currentViewFromList.BuyFood.setVisibility(View.INVISIBLE);
}
else{
ViewItemContainer cont = new ViewItemContainer();
try {
Toast toast = Toast.makeText(context, "entrato"+info.title, Toast.LENGTH_SHORT);
toast.show();
DbxDatastore datastore = app.datastoreManager.openDatastore(info.id);
datastore.sync();
if (info.title!=null){
currentViewFromList.PetName.setTypeface(app.Font);
cont.PetName = info.title;
currentViewFromList.PetName.setText(cont.PetName);
}
DbxTable table = datastore.getTable("ITEMS");
DbxRecord record = table.get("INFO");
if (record!=null && record.hasField("PETPICTURE")){
byte[] b = record.getBytes("PETPICTURE");
//Bitmap picture = Misc.ByteArrayToImg(b);
cont.PetImage = Misc.ByteArrayToImg(b);
if (cont.PetImage!=null) currentViewFromList.PetImage.setImageBitmap(cont.PetImage);
} else currentViewFromList.PetImage.setImageResource(R.drawable.ic_launcher);
if (record!=null){
cont.BuyFood = record.getBoolean("BUYFOOD");
if (cont.BuyFood) currentViewFromList.BuyFood.setVisibility(View.VISIBLE);
else currentViewFromList.BuyFood.setVisibility(View.INVISIBLE);
}
datastore.close();
} catch (DbxException e) {
e.printStackTrace();
}
app.itemsSync.put(info.id,cont);
}
}
基本上,当应用程序启动时,app.Fetch 设置为 true,来自 Home 的 updateList() 创建适配器并调用 adapter.notifyDataSetChanged()。
此时,listAdapter getView 会为列表中的每个项目调用,检查 id 作为 hashmap 中的键,但没有找到它,因此它从数据存储中获取数据,并将数据插入到 hashmap 和视图中。
到目前为止,一切都很好。列表视图被正确填充,当视图被滚动时,数据会从哈希图中正确检索,而不是从数据存储中一遍又一遍地获取。
然后,我从另一部手机添加了一个新的数据存储,它触发了监听器,在我的手机上它显示“RECEIVED”toast,这意味着监听器已被触发。app.Fetch 变为 true,然后调用 updateList()。
如果我在 updateList() 中的任何地方检查 app.Fetch 值,它仍然设置为 true,而如果我在 getView 代码运行时检查它,它会设置为 false,因此它会再次从 hashmap 中检索数据,而不是在线获取更新的数据数据存储。
我认为 getView 代码开始与 updateList 函数并行运行,因此它显示以下行为:
boolean true updateList() start adapter.notifyDataSetChanged() runs ListAdapter getView start updateList() ends boolean false getView 检查布尔值,因为此时它为假,它从哈希图中检索数据。
有什么办法可以让 updateList 等到 listview 中的所有项目都通过 getView 运行?