-1

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;
}}

次に、ホームアクティビティから、シングルトンインスタンスを保持します

ListsApplication app = app.getInstance

ホームアクティビティでは、オンラインデータストアに変更があるたびにデータストアオンラインサーバーからトリガーされるリスナーをセットアップします

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 に入力する必要がある項目の ArrayList をクリアし、adapter.notifyDataSetChanged() を実行します。

私のカスタム 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 をチェックし、それが見つからないため、データストアからデータを取得し、ハッシュマップとビューにデータを挿入します。

ここまでは順調です。リストビューは正しく取り込まれ、ビューがスクロールされると、データはデータストアから何度もフェッチされるのではなく、ハッシュマップから正しく取得されます。

次に、別の電話から、リスナーをトリガーする新しいデータストアを追加します。私の電話では、「RECEIVED」トーストが表示されます。これは、リスナーがトリガーされたことを意味します。app.Fetch が true になり、 updateList() が呼び出されます。

app.Fetch の値を updateList() のどこかで確認すると、まだ true に設定されていますが、getView コードの実行中に確認すると、false に設定されているため、更新されたオンラインをフェッチする代わりに、ハッシュマップからデータを再度取得します。データストア。

getView コードは updateList 関数と並行して実行を開始するため、次の動作を示していると思います。

boolean true updateList() start adapter.notifyDataSetChanged() runs ListAdapter getView start updateList() end boolean false getView は boolean をチェックします。この時点では false であるため、ハッシュマップからデータを取得します。

リストビュー内のすべての項目が getView を介して実行されるまで updateList を待機させる方法はありますか?

4

1 に答える 1

0

はい、UI スレッドでのみ notifyDataSetChanged を呼び出すようにしてください。そうすれば、リストの読み込み中に呼び出されることはありません。非同期スレッドで呼び出す場合は、runOnUiThread ブロックを使用してその呼び出しを UI スレッドに移動します。これにより、描画中にリストを更新しようとすることがなくなり、問題全体を回避できます。

于 2015-01-21T20:03:36.333 に答える