I have a Custom Cursor Adapter. It shows a list of installed applications with an icon, name and checkbox on each line item. I cache the list of applications in a database for faster retrieve and to store the state of the checkbox. However, I can't store the application icon in the db because sqlite doesn't support blobs. They list works rather well except that it is "janky" as described by Brad Fitzpatrick at Google IO (https://wave.google.com/wave/waveref/ googlewave.com/w+3kgmObZwO ). I'm trying to make my app non-janky by following the tutorial here: http://github.com/bradfitz/zippy-android-talk/blob/master/src/com/google/io2010/zippy/JankableListAdapter.java but I'm having trouble.
The reason my list is janky is because I look up each icon as you scroll down the list. drawable = pm.getApplicationIcon(c.getString(c.getColumnIndex(SmartLockDbAdapter.KEY_PACKAGE))); getApplicationIcon takes too long to return to make for a smooth scrolling list. I would like to perform the action in the background with an AsyncTask but because bindView gets called repeatedly in a short time span, my icons end up with the wrong list item. I need help. I've posted my whole ListActivity below in hopes that it helps other people. It's much harder to find an example of a working CursorAdapter then it is an ArrayAdapter. PS if you have any other notes about how I could do things better please let me know. public class AppList extends ListActivity { private static final boolean DEBUG = true; private static final int MENU_ALL_APPS = 2; private static final int MENU_APPROVED_APPS = 1; public static SmartLockDbAdapter mDbHelper; private Cursor cursor; LayoutInflater inflater; ProgressDialog dialog; CheckBoxAdapter mAdapter; Activity activity; private AutoCompleteTextView filterText; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); activity = this; activity.requestWindowFeature(Window.FEATURE_PROGRESS); setContentView(R.layout.app_list); mDbHelper = new SmartLockDbAdapter(this); mDbHelper.open(); new populateDb().execute(this); cursor = mDbHelper.fetchAllApps(); startManagingCursor(cursor); mAdapter = new CheckBoxAdapter(this, cursor); setListAdapter(mAdapter); startManagingCursor(cursor); filterText = (AutoCompleteTextView) findViewById(R.id.search_box); filterText.setAdapter(mAdapter); filterText.setDropDownHeight(0); // hide the drop down, just filter the listActivity filterText.setThreshold(1); } private class populateDb extends AsyncTask<Context, Integer, Long> { protected Long doInBackground(Context... context) { PackageManager pm = getPackageManager(); SmartLockDbAdapter mDbHelper = new SmartLockDbAdapter(context[0]); mDbHelper.open(); Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> mApps; mApps = getPackageManager().queryIntentActivities(mainIntent, 0); int count = mApps.size(); for (int index=0; index<count; index++) { ResolveInfo content = mApps.get(index); // put in while loop to prevent db locking while(!mDbHelper.updateApp((String) pm.getApplicationLabel(content.activityInfo.applicationInfo), content.activityInfo.packageName, "1")) { Log.v("GoldFishView", "Conflict Resolving" ); try { Thread.sleep((long) 1000); } catch (InterruptedException e) { e.printStackTrace(); } } publishProgress((int) ((index / (float) count) * 10000)); // scale is 1..10000 } return null; } protected void onProgressUpdate(Integer... progress) { activity.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress[0]); } protected void onPostExecute(Long result) { activity.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_END);//go away activity.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_OFF); mAdapter.getCursor().requery(); // pull in new results if any } } /* Creates the menu items */ public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_ALL_APPS, 0, "Show All Apps").setIcon(R.drawable.ic_menu_sort_alphabetically); menu.add(0, MENU_APPROVED_APPS, 0, "Show Approved Apps").setIcon(R.drawable.ic_menu_mark); return true; } /* Handles item selections */ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ALL_APPS: cursor.close(); cursor = mDbHelper.fetchAllApps(); mAdapter.changeCursor(cursor); //setListAdapter(new CheckBoxAdapter(this, c)); return true; case MENU_APPROVED_APPS: cursor.close(); cursor = mDbHelper.fetchApprovedApps(); mAdapter.changeCursor(cursor); //setListAdapter(new CheckBoxAdapter(this, c)); return true; } return false; } @Override protected void onListItemClick(ListView l, View v, int position, long id) { if(DEBUG==true) Log.v("GoldFishView","app position " + position + "ID " + id + " item name" + v.getId()); mDbHelper.toggleApprove(id); mAdapter.getCursor().requery(); } @Override protected void onDestroy() { mDbHelper.close(); super.onDestroy(); } private static class CheckBoxAdapter extends CursorAdapter { static class ViewHolder { TextView text; ImageView icon; CheckBox checkbox; } PackageManager pm; Drawable drawable; ViewHolder holder; LayoutInflater inflater; public CheckBoxAdapter(Context context, Cursor c) { super(context, c); pm = context.getPackageManager(); } @Override public String convertToString(Cursor cursor) { int columnIndex = cursor.getColumnIndexOrThrow(SmartLockDbAdapter.KEY_APP_NAME); return cursor.getString(columnIndex); } @Override public Cursor runQueryOnBackgroundThread(CharSequence constraint) { if (constraint == null) return mDbHelper.fetchAllApps(); return mDbHelper.fetchFilterApps(constraint); //returns a cursor with the search results } @Override public void bindView(final View convertView, Context context, final Cursor c) { Log.v("DAVID IN","bindView"); holder = (ViewHolder) convertView.getTag(); holder.text.setText(c.getString(c.getColumnIndex(SmartLockDbAdapter.KEY_APP_NAME))); holder.checkbox.setChecked(c.getInt(c.getColumnIndex(SmartLockDbAdapter.KEY_APROVED)) == 1 ? true : false); try { drawable = pm.getApplicationIcon(c.getString(c.getColumnIndex(SmartLockDbAdapter.KEY_PACKAGE))); } catch (NameNotFoundException e) { e.printStackTrace(); } holder.icon.setImageDrawable(drawable); /*new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... unused) { try { drawable = pm.getApplicationIcon(c.getString(c.getColumnIndex(SmartLockDbAdapter.KEY_PACKAGE))); } catch (NameNotFoundException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { holder = (ViewHolder) convertView.getTag(); holder.text.setText(c.getString(c.getColumnIndex(SmartLockDbAdapter.KEY_APP_NAME))); holder.checkbox.setChecked(c.getInt(c.getColumnIndex(SmartLockDbAdapter.KEY_APROVED)) == 1 ? true : false); holder.icon.setImageDrawable(drawable); } }.execute();*/ /*try { drawable = pm.getApplicationIcon(c1.getString(c1.getColumnIndex(SmartLockDbAdapter.KEY_PACKAGE))); } catch (NameNotFoundException e) { e.printStackTrace(); }*/ //holder.icon.setImageDrawable(drawable); } @Override public View newView(Context context, Cursor c, ViewGroup parent) { Log.e("DAVID IN","newView"); View convertView; inflater = LayoutInflater.from(context); convertView = inflater.inflate(R.layout.app_item, parent, false); holder = new ViewHolder(); holder.text = (TextView) convertView.findViewById(R.id.text1); holder.icon = (ImageView) convertView.findViewById(R.id.icon); holder.checkbox = (CheckBox) convertView.findViewById(R.id.checkboximage); holder.text.setText(c.getString(c.getColumnIndex(SmartLockDbAdapter.KEY_APP_NAME))); holder.checkbox.setChecked(c.getInt(c.getColumnIndex(SmartLockDbAdapter.KEY_APROVED)) == 1 ? true : false); /*final int pos = c1.getPosition(); new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... unused) { try { drawable = pm.getApplicationIcon(c1.getString(c1.getColumnIndex(SmartLockDbAdapter.KEY_PACKAGE))); //drawable.setBounds(36, 36, 36, 36); } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { if(c1.getPosition() == pos) holder.icon.setImageDrawable(drawable); } }.execute();*/ convertView.setTag(holder); return convertView; } } } -- You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en