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

Reply via email to