androidlistviewandroid-cursoradapterstartactivityforresult

Update same ListView with new data in CursorAdapter


I am really stuck and have no idea what to do. I have looked into startActivityForResult and Content providers and I have no clue how to implement any of them for this app.

I am not seeing how to get the data from the database and update the displayBottomList using same listview so I don't have to redirect the user to a new layout/activity. Not sure if I can even call a new query and set that to a different cursor and switch between them. I have seen swapCursor but how does that work when using the same adapter?

I have a ListView that I want to refresh with new data from a web service call when the user clicks on a row within the list. I am using a CursorAdapter. I can get the data correctly onClick of the row.

Where I am stuck, is how do I update that listView to repopulate with the new info from the database/response without sending me to another Activity. I want the user to stay on the same screen but just update the listView with the new data.

Not sure how to get the adapter to notify the adapter to update and populate a new ListView when the onClick is in the adapter, but the ListView is being created in the MainActivity.

The Adapter for BottomListView, the one I want to update when a row is clicked.

public class BottomListViewAdapter extends CursorAdapter {

    private String mEmployeeNumber;
    private EmployeeDBHandler dbHandler;

    public BottomListViewAdapter(Context context, Cursor cursor) {
        super(context, cursor, 0);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return LayoutInflater.from(context).inflate(R.layout.contact_cardview_layout, parent, false);
    }

    @Override
    public void bindView(View view, final Context context, final Cursor cursor) {
        dbHandler = new EmployeeDBHandler(context);
        ViewHolder holder;
        holder = new ViewHolder();
        holder.tvFirstName = (TextView) view.findViewById(R.id.personFirstName);
        holder.tvLastName = (TextView) view.findViewById(R.id.personLastName);
        holder.tvTitle = (TextView) view.findViewById(R.id.personTitle);
        holder.mPeepPic = (ImageView) view.findViewById(R.id.person_photo);
        holder.mDetailsButton = (ImageButton) view.findViewById(R.id.fullDetailButton);
        holder.mCardView = (CardView) view.findViewById(R.id.home_screen_cardView);

        String mFirstName = cursor.getString(cursor.getColumnIndexOrThrow("First_name"));
        String mLastName = cursor.getString(cursor.getColumnIndexOrThrow("Last_name"));
        String mTitle = cursor.getString(cursor.getColumnIndexOrThrow("Payroll_title"));
        String mThumbnail = cursor.getString(cursor.getColumnIndexOrThrow("ThumbnailData"));

        holder.tvFirstName.setText(mFirstName);
        holder.tvLastName.setText(mLastName);
        holder.tvTitle.setText(mTitle);

        if (mThumbnail != null) {
            byte[] imageAsBytes = Base64.decode(mThumbnail.getBytes(), Base64.DEFAULT);
            Bitmap parsedImage = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);
            holder.mPeepPic.setImageBitmap(parsedImage);
        } else {
            holder.mPeepPic.setImageResource(R.drawable.img_place_holder_adapter);
        }

        final int position = cursor.getPosition();

        holder.mDetailsButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                cursor.moveToPosition(position);
                String mEmployeeNumber = cursor.getString(1);
                String mEmail = cursor.getString(8);
                String mFirstName = cursor.getString(2);
                String mLastName = cursor.getString(3);
                String mPhoneMobile = cursor.getString(4);
                String mPhoneOffice = cursor.getString(5);
                String mCostCenter = cursor.getString(10);
                String mHasDirectReports = cursor.getString(7);
                String mTitle = cursor.getString(6);
                String mPic = cursor.getString(9);
                Intent mIntent = new Intent(context, EmployeeFullInfo.class);
                mIntent.putExtra("Employee_number", mEmployeeNumber);
                mIntent.putExtra("Email", mEmail);
                mIntent.putExtra("First_name", mFirstName);
                mIntent.putExtra("Last_name", mLastName);
                mIntent.putExtra("Phone_mobile", mPhoneMobile);
                mIntent.putExtra("Phone_office", mPhoneOffice);
                mIntent.putExtra("Cost_center_id", mCostCenter);
                mIntent.putExtra("Has_direct_reports", mHasDirectReports);
                mIntent.putExtra("Payroll_title", mTitle);
                mIntent.putExtra("ThumbnailData", mPic);
                mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                view.getContext().startActivity(mIntent);
            }
        });

        holder.mCardView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                cursor.moveToPosition(position);
                mEmployeeNumber = cursor.getString(1);
                Toast.makeText(context, mEmployeeNumber, Toast.LENGTH_SHORT).show();
                callNewDirectReport();
                notifyDataSetChanged();

            }
        });
    }

    public static class ViewHolder {
        TextView tvFirstName;
        TextView tvLastName;
        TextView tvTitle;
        ImageView mPeepPic;
        ImageButton mDetailsButton;
        CardView mCardView;
    }

    private void callNewDirectReport() {
        String mDirectReportUrl = "mURL";

        HttpUrl.Builder urlBuilder = HttpUrl.parse(mDirectReportUrl).newBuilder();
        urlBuilder.addQueryParameter("manager_employee_number", mEmployeeNumber);
        String url = urlBuilder.build().toString();


        OkHttpClient client = getUnsafeOkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                    final String responseData = response.body().string();
                    final InputStream stream = new ByteArrayInputStream(responseData.getBytes());
                    final XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                    final ArrayList<Employee> employees = (ArrayList<Employee>) parserHandler.parse(stream);

                    for (Employee e : employees) {
                        dbHandler.addEmployee(e);
                    }
            }
        });
    }

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
    }
}

My MainActivity that is calling the adapter

public class MainActivity extends AppCompatActivity {

    private ProgressBar mProgressBar;
    private BottomListViewAdapter mBottomAdapter;
    private View mDividerView;
    EmployeeDBHandler dbHandler;
    private int mStartingEmployeeID = mStartingID;
    private String table = "employees";
    private static final int LOADER_INTEGER = 1;
    private Cursor mBottomCursor, mTopCursor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        mDividerView = findViewById(R.id.divider);
        dbHandler = new EmployeeDBHandler(getApplicationContext());
        mProgressBar.setVisibility(View.VISIBLE);
        mDividerView.setVisibility(View.GONE);
        getXMLData();

        //GUI for seeing android SQLite Database in Chrome Dev Tools
        Stetho.InitializerBuilder inBuilder = Stetho.newInitializerBuilder(this);
        inBuilder.enableWebKitInspector(Stetho.defaultInspectorModulesProvider(this));
        Stetho.Initializer in = inBuilder.build();
        Stetho.initialize(in);
    }

    public void getXMLData() {
        OkHttpClient client = getUnsafeOkHttpClient();
        Request request = new Request.Builder()
                .url(getString(R.string.API_FULL_URL))
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                final String responseData = response.body().string();
                final InputStream stream = new ByteArrayInputStream(responseData.getBytes());
                final XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                final ArrayList<Employee> employees = (ArrayList<Employee>) parserHandler.parse(stream);

                for (Employee e : employees) {
                    dbHandler.addEmployee(e);

                }

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mProgressBar.setVisibility(View.GONE);
                        mDividerView.setVisibility(View.VISIBLE);
                        displayTopList();
                        displayBottomList();
                    }
                });
            }
        });
    }

    public void displayTopList() {
        SQLiteDatabase db = dbHandler.getWritableDatabase();
        mTopCursor = db.rawQuery("SELECT * FROM " + table + " WHERE " + "Employee_number" + "=" + mStartingEmployeeID, null);
        ListView mTopListView = (ListView) findViewById(R.id.mTopList);
        TopListCursorAdapter topAdapter = new TopListCursorAdapter(this, mTopCursor);
        mTopListView.setAdapter(topAdapter);
    }

    public void displayBottomList() {
        SQLiteDatabase db = dbHandler.getWritableDatabase();
        mBottomCursor = db.rawQuery("SELECT * FROM " + table + " WHERE " +
                "Employee_number" + "!=" + mStartingEmployeeID + " AND " +
                "Manager_employee_number" + "=" + mStartingEmployeeID + " ORDER BY " +
                "Last_name" + " ASC", null);

        ListView mBottomListView = (ListView) findViewById(R.id.mDirectReportList);
        mBottomAdapter = new BottomListViewAdapter(this, mBottomCursor);
        mBottomListView.setAdapter(mBottomAdapter);
        mBottomAdapter.notifyDataSetChanged();

    }
}

Solution

  • Right now your code in callNewDirectReport() makes an API request and stores the results in the database. This will not update the adapter to show the new items, instead you need to requery the database and get a newer Cursor. Below is an example of how you may do it:

    public class BottomListViewAdapter extends CursorAdapter {
    
        private String mEmployeeNumber;
        private EmployeeDBHandler dbHandler;
        private Activity activityRef;   
    
        public BottomListViewAdapter(Context context, Cursor cursor) {
            super(context, cursor, 0);
            // keep a reference to the activity
            activityRef = (Activity) context;
        }
            
        //...
    
        private void callNewDirectReport() {
            //...
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                        final String responseData = response.body().string();
                        final InputStream stream = new ByteArrayInputStream(responseData.getBytes());
                        final XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                        final ArrayList<Employee> employees = (ArrayList<Employee>) parserHandler.parse(stream);
    
                        for (Employee e : employees) {
                            dbHandler.addEmployee(e);
                        }
                        // the new items are in the database so requery the database to get a new fresher Cursor:
                        SQLiteDatabase db = dbHandler.getWritableDatabase();
                        Cursor fresherCursor = db.rawQuery("SELECT * FROM " + table + " WHERE " +
                            "Employee_number" + "!=" + mStartingEmployeeID + " AND " +
                            "Manager_employee_number" + "=" + mStartingEmployeeID + " ORDER BY " +
                            "Last_name" + " ASC", null);
                        //change the adapter's Cursor
                        activityRef.runOnUiThread(new Runnable() {
                            public void run() {
                                swapCursor(freshedCursor);
                            }
                        });
                }
            });
        }
    }