Search code examples
androidlistviewandroid-cursoradapter

Update UI from CursorAdapter onClick


I have a listView that when a user clicks on the cardView I am calling a web service from an employeeNumber tied to that position. I get the data of the new web service call onResponse from OkHttp3s enqueue. How do I update the listView to populate the new data from the response?

Really lost as I know the listView is using the adapter which the on click is made. So not sure how to call the listView, to populate the adapter after the response is completed.

My MainActivity where the first ListView is populated and the adapter is attached.

public class MainActivity extends AppCompatActivity {

    private ProgressBar mProgressBar;
    EmployeeDBHandler dbHandler;
    private int mStartingEmployeeID = myStartingID;
    private String table = "employees";
    private static final String DATABASE_NAME = "OneTeam";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        dbHandler = new EmployeeDBHandler(getApplicationContext());
        mProgressBar.setVisibility(View.VISIBLE);
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

        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);
                        displayTopList();
                        displayBottomList();
                    }
                });
            }
        });
    }

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

    public void displayBottomList() {
        SQLiteDatabase db = dbHandler.getWritableDatabase();
        Cursor mBottomListCursor = db.rawQuery("SELECT * FROM " + table + " WHERE " + "Employee_number" + "!=" + mStartingEmployeeID, null);

        ListView mBottomListView = (ListView) findViewById(R.id.mDirectReportList);
        BottomListViewAdapter bottomAdapter = new BottomListViewAdapter(this, mBottomListCursor);
        mBottomListView.setAdapter(bottomAdapter);
    }

    @Override
    public void onBackPressed() {
        moveTaskToBack(false);
    }
}

The CursorAdapter that has the button's onClick

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) {
        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();
                dbHandler = new EmployeeDBHandler(context);
                callNewDirectReport();

            }
        });
    }

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

    private void callNewDirectReport() {
        String mDirectReportUrl = "https://b2aproxy.supervalu.com/OneTeam/OneTeamService.asmx/GetDirectReportsWithPicture";

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


            }
        });
    }
}

Solution

  • Maybe you can try to use Loaders.

    They let's you bind the data source (Content Provider or other) with the Activity or Fragment. While Loaders are active they should monitor the source of their data and deliver new results when the contents change.

    I will give you a general approach to how implement them (CursorLoader in particular). I hope to be clear :

    public class MainActivity extends AppCompatActivity implements
        LoaderManager.LoaderCallbacks<Cursor> {
    
        private static final int LOADER_INTEGER = 1;
    
        // ... existing code
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            getLoaderManager().initLoader(LOADER_INTEGER, null, this);
            super.onActivityCreated(savedInstanceState);
        }
    
        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            return new CursorLoader(
                this,
                ContentProvider.CONTENT_URI,
                projection,
                null,
                null,
                sortOrder
            );
        }
    
        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            mCursorAdapter.swapCursor(cursor);
        }
    
        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            mCursorAdapter.swapCursor(null);
        }
    }
    

    You can read a lot on internet about this, a good start is for example here.

    Hope this helps!