さて、私のアプローチはこのようなものです。ローカルに保存された暗号化およびシリアル化されたオブジェクトを でデコードAsyncTask
していActivity
ます。は、データを表示するために (HistoryAdapter) をActivity
使用します。BaseAdapter
は、デコードが完了AsyncTask
するまで a を示します。ProgressDialog
がonProgressUpdate()
最初に呼び出されると、ProgressDialog
はキャンセルされます。ここまでは順調ですね。次に、onProgressUpdate()
では、HistoryAdapter に共通の方法で変更が通知され、そのgetView()
メソッドがトリガーされます。HistoryAdapter のでは、作成された を変更し、データを に設定するためにgetView()
2 番目のコマンドAsyncTask
が実行されます。convertView
View
ここですべてが失敗します。で最終的なレイアウトを膨らませ、ここonProgressUpdate()
でプロパティとデータを適切に設定しconvertView
ます。すべてのデータが設定されているにもかかわらず、変更は表示されません...
したがって、AsyncTask
HistoryAdapter 自体は実際には完全に機能し、変更は表示されません。SO で言及されている多数の提案を試しました。たとえば、を無効化しconvertView
たり、参照を渡したりListView
、使用したりしinvalidateViews()
ます(永久ループが発生しますが、目に見える変化はありません。これは理にかなっています)。
データが利用可能になる前に、画像プレースホルダーを含むレイアウトをロードしたくないので、これが本当に必要です。私は仕事をしましたが、厄介に見え、簡単な方法のように見えます。ListView
そのため、進行状況が完了したときにのみ更新 (アイテムを追加) する必要があります。何か案は?
編集:明確にするために:データは適切なタイミングでアダプターに設定されます。問題は、アダプターがView
最初に空白 (プレースホルダー) を作成することです (他の方法はわかりません。そうしないと、getView で NullPointerException が発生しView
ますView
) onProgressUpdate()
。2番目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 を変更できることと、ビューへの参照を多くの場所で渡す必要がないことはわかっていますが、やはりコードが進行中です。簡単な例...
編集
さて、そもそも私のアプローチが貧弱だったようで、結果AsyncTask
としてHistoryAdapter
. これを解決するためにいくつかの問題に対処しました。
- @Delyan の提案に基づいて、実際に必要になる前にデータをロード/復号化するのが良いと判断しました。これには a を使用し
PropertyChangeListener
ています。これは を実装してOnSharedPreferenceChangeListener
、必要なデータへの変更が通知されるようにします。変更は、関心のあるリスナーに伝播されます。データはアプリケーションの起動時に復号化され、アプリケーション全体でアクセス可能なグローバル変数に格納されます。これを彼が言及した「メモリキャッシュ」と見なしてください。 - コメントと受け入れられた回答に基づいて、復号化はバックグラウンドで行われるようになったため、
AsyncTasks
. - アダプターのパフォーマンスをさらに最適化するために、 に必要なイメージを に保存して
ListView
いるSparseArray
ため、作成および保存は 1 回だけです。これには a を使用しないでくださいHashMap
。さらに、画像がまだView
存在しない場合にのみ、現在の画像が作成され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