Googleapiclient inside recycleViewAdapter?

Asked

Viewed 43 times

0

The app has a fragment with a recyclerview and a FAB. By clicking on FAB, opens a dialog where the user informs addresses, among other information.

Address input fields are of the Autocompletetextview type and receive address suggestions as the user enters the information.

This was done using GoogleApiClient with GEO_DATA_API, according to the following code:

public class RecyclerFragment extends Fragment
        implements AlertDialog.OnClickListener,
        GoogleApiClient.OnConnectionFailedListener,
        GoogleApiClient.ConnectionCallbacks {

    private static final String TAG = "RecyclerFragment";
    RecyclerView recyclerView;
    RunDbHelper runDbHelper;
    RecyclerViewAdapter recyclerViewAdapter;
    private OnOkButtonListener mCallback;

    private GoogleApiClient mGoogleApiClient;
    private PlaceArrayAdapter mPlaceArrayAdapter;

    private static final int GOOGLE_API_CLIENT_ID = 0;

    private static final LatLngBounds BOUNDS_MOUNTAIN_VIEW = new LatLngBounds(
            new LatLng(37.398160, -122.180831), new LatLng(37.430610, -121.972090));
    private static LatLngBounds BOUNDS_AUTOCOMPLETE;

    public RecyclerFragment() {
        this.mCallback = null;
    }

    public void setAutocompleteBounds(LatLng centerLatLng){
        if (centerLatLng!= null && !centerLatLng.toString().isEmpty()){
            Double latSW, lngSW, lngNE, latNE;
            latSW = centerLatLng.latitude-.5;
            lngSW = centerLatLng.latitude-.5;
            lngNE = centerLatLng.latitude+.5;
            latNE = centerLatLng.latitude+.5;
            BOUNDS_AUTOCOMPLETE = new LatLngBounds(
                    new LatLng(latSW, lngSW), new LatLng(latNE, lngNE));
        } else {
            BOUNDS_AUTOCOMPLETE = new LatLngBounds(
                    new LatLng(37.398160, -122.180831), new LatLng(37.430610, -121.972090));
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_recycler, container, false);
        try {
            mGoogleApiClient = new GoogleApiClient.Builder(getContext())
                    .addApi(Places.GEO_DATA_API)
                    .enableAutoManage(getActivity(), GOOGLE_API_CLIENT_ID, this)
                    .addConnectionCallbacks(this)
                    .build();
        } catch ( Exception e) {
            Log.i(TAG, "onCreateView: " + e);
        }

        mPlaceArrayAdapter = new PlaceArrayAdapter(getContext(), android.R.layout.simple_list_item_1,
                BOUNDS_AUTOCOMPLETE, null);

        runDbHelper = RunDbHelper.getInstance(getContext());
        List<RunData> mList = runDbHelper.getAllRuns();
        recyclerViewAdapter = new RecyclerViewAdapter(getContext(), mList);
        recyclerView = (RecyclerView) view.findViewById(R.id.rvRunList);
        recyclerView.setHasFixedSize(true);
        recyclerView.setAdapter(recyclerViewAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fabAdd);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Data entry dialog to add runs
                dialogInsertRun();
            }
        });     
        return view;
    }

    public void dialogInsertRun() {

        // Get the Activity for layout inflater as this dialog runs inside a fragment
        LayoutInflater inflater = LayoutInflater.from(getActivity());
        final View view = inflater.inflate(R.layout.dialog_new_run, null);

        // Dialog Builder
        AlertDialog.Builder addRunDialog = new AlertDialog.Builder(getActivity());
        addRunDialog.setTitle(R.string.dialog_insert_run_title)
                .setView(view);

        // Data entry field objects
        final AutoCompleteTextView collectAddressACTV = (AutoCompleteTextView) view.findViewById(R.id.actv_new_collect_address);
        final EditText collectPersonEditText = (EditText) view.findViewById(R.id.new_collect_person);

        collectAddressACTV.setThreshold(3);
        collectAddressACTV.setOnItemClickListener(mAutocompleteClickListener);
        collectAddressACTV.setAdapter(mPlaceArrayAdapter);

        addRunDialog.setPositiveButton(R.string.button_positive, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int id) {
                RunData runData = new RunData();
                runData.collect_person = getStringOrEmpty(collectPersonEditText);
                runData.collect_address = getStringOrEmpty(collectAddressACTV);

                if (!(runData.collect_address.isEmpty() && runData.delivery_address.isEmpty())) {

                    runData = runDbHelper.insertRun(runData, getActivity());
                    if (runData != null) {                          
                        recyclerViewAdapter = new RecyclerViewAdapter(getActivity(), runDbHelper.getAllRuns());
                        recyclerView.setAdapter(recyclerViewAdapter);
                        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
                        mCallback.addMarkersToMap(runData);
                    }
                } else {
                    Toast.makeText(getActivity(), R.string.dialog_insert_run_toast_nowhere, Toast.LENGTH_LONG).show();
                }
            }
        });

        addRunDialog.setNegativeButton(R.string.button_negative, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                dialog.cancel();
            }
        });

        addRunDialog.create();
        addRunDialog.show();
    }

    private String getStringOrEmpty(EditText editText) {
        String mString = editText.getText().toString();
        mString = (mString == null || mString.isEmpty() ? "" : mString);
        return mString;
    }


    @Override
    public void onConnected(@Nullable Bundle bundle) {
        mPlaceArrayAdapter.setGoogleApiClient(mGoogleApiClient);
        Log.i(TAG, "Google Places API connected.");
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.e(TAG, "Google Places API connection failed with error code: "
                + connectionResult.getErrorCode());

        Toast.makeText(getContext(),
                "Google Places API connection failed with error code:" +
                        connectionResult.getErrorCode(),
                Toast.LENGTH_LONG).show();
    }

    @Override
    public void onConnectionSuspended(int i) {
        mPlaceArrayAdapter.setGoogleApiClient(null);
        Log.e(TAG, "Google Places API connection suspended.");
    }

    private AdapterView.OnItemClickListener mAutocompleteClickListener
            = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            final PlaceArrayAdapter.PlaceAutocomplete item = mPlaceArrayAdapter.getItem(position);
            final String placeId = String.valueOf(item.placeId);
            Log.i(TAG, "Selected: " + item.description);
            PendingResult<PlaceBuffer> placeResult = Places.GeoDataApi
                    .getPlaceById(mGoogleApiClient, placeId);
            placeResult.setResultCallback(mUpdatePlaceDetailsCallback);
            Log.i(TAG, "Fetching details for ID: " + item.placeId);
        }
    };

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if(mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            mGoogleApiClient.stopAutoManage(getActivity());
            mGoogleApiClient.disconnect();
        }
    }   

    private ResultCallback<PlaceBuffer> mUpdatePlaceDetailsCallback
            = new ResultCallback<PlaceBuffer>() {
        @Override
        public void onResult(PlaceBuffer places) {
            if (!places.getStatus().isSuccess()) {
                Log.e(TAG, "Place query did not complete. Error: " +
                        places.getStatus().toString());
                return;
            }
            // Selecting the first object buffer.

        }
    };
}

After entering the information, they go to the database and to recyclerview, forming a list of cardviews.

Each cardview has an edit button. At the touch of a button, a dialog with the form. of editing is opened. At this time, I would like to use the same address suggestion feature.

All the editing part is ready. Only this Googleapiclient is missing to work...

The recyclerview adapter code is this:

class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder>
        implements AlertDialog.OnClickListener,
        GoogleApiClient.OnConnectionFailedListener,
        GoogleApiClient.ConnectionCallbacks{

    private static final String TAG = "RecyclerViewAdapter";
    private static String mCollect, mDelivery, mRunEnded, mUnknownDestiny, mIndeterminate;

    private GoogleApiClient mGoogleApiClient;
    private PlaceArrayAdapter mPlaceArrayAdapter;

    private static final int GOOGLE_API_CLIENT_ID = 1;
    private Context context;
    private List<RunData> dataList = new ArrayList<>();
    private LayoutInflater inflater;
    private RunDbHelper runDbHelper;

    private static final LatLngBounds BOUNDS_MOUNTAIN_VIEW = new LatLngBounds(
            new LatLng(37.398160, -122.180831), new LatLng(37.430610, -121.972090));
    private static LatLngBounds BOUNDS_AUTOCOMPLETE;

    RecyclerViewAdapter(Context context, List<RunData> dataList1) {

        mCollect = context.getString(R.string.str_collect).trim();
        mDelivery = context.getString(R.string.str_delivery).trim();
        mIndeterminate = context.getString(R.string.str_indeterminate);
        mRunEnded = context.getString(R.string.this_run_ended);
        mUnknownDestiny = context.getString(R.string.unknown_destiny);

        this.context = context;
        this.dataList = dataList1;
        this.runDbHelper = RunDbHelper.getInstance(this.context);
        inflater = LayoutInflater.from(context);
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.fragment_recycler_row, parent, false);
        try {
            mGoogleApiClient = new GoogleApiClient.Builder(context)
                    .addApi(Places.GEO_DATA_API)
                    .enableAutoManage(XXXXXXXXXXXXXXXXXX, GOOGLE_API_CLIENT_ID, this) // nada do que tentei colocar aqui no lugar do XXXXXXX funcionou!
                    .addConnectionCallbacks(this)
                    .build();
        } catch ( Exception e) {
            Log.i(TAG, "onCreateView: " + e);
        }

        mPlaceArrayAdapter = new PlaceArrayAdapter(context, android.R.layout.simple_list_item_1,
                BOUNDS_AUTOCOMPLETE, null);

        return new RecyclerViewHolder(view);
    }


    // Parse data from dataList to holder and setup all Views
    // Here is part of the magic
    @Override
    public void onBindViewHolder(final RecyclerViewHolder holder, final int position) {

        // holding regular views
        holder.runID.setText(dataList.get(position).run_id);

        holder.collectPerson.setText(dataList.get(position).collect_person);
        holder.collectAddress.setText(dataList.get(position).collect_address);

        // this booleans help set some views on/off accordingly
        Boolean collected = dataList.get(position).parcel_collected.equals("1");
        Boolean collectAddressIsEmpty = dataList.get(position).collect_address.isEmpty();

        holder.ivEdit.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                RunData runData = new RunData();
                runData.run_id = holder.runID.getText().toString();              
                runData.collect_person = holder.collectPerson.getText().toString();
                runData.collect_address = holder.collectAddress.getText().toString();       
                dialogEditRun(runData, position);
            }
        });    
    }

    String makeSureLatLng(String lat, String lng) {
        return (lat == null || lng == null || lat.isEmpty() || lng.isEmpty() ? null : lat + "," + lng);
    }

    boolean isUsable(TextView textView) {
        return (!(textView == null || textView.getText().toString().isEmpty()));
    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }

    public void dialogEditRun(RunData runData, int position) {

        // Get the Activity for layout inflater as this dialog runs inside a fragment
        LayoutInflater inflater = LayoutInflater.from(context);
        final View inflaterView = inflater.inflate(R.layout.dialog_edit_run, null);
        // Data entry field objects
        final String mRunID;

        final AutoCompleteTextView collectAddressACTV = (AutoCompleteTextView) inflaterView.findViewById(R.id.actv_edit_collect_address);
        final EditText collectPersonEditText = (EditText) inflaterView.findViewById(R.id.edit_collect_person);
        final TextView parcel_collected = (TextView) inflaterView.findViewById(R.id.editDelivered);         

        mRunID = runData.run_id;        

        parcel_collected.setText(runData.parcel_collected);
        collectAddressACTV.setText(runData.collect_address);
        collectPersonEditText.setText(runData.collect_person);


        // Set directions into recyclerViewAdapter for autocomplete
        collectAddressACTV.setThreshold(3);
        collectAddressACTV.setOnItemClickListener(mAutocompleteClickListener);
        collectAddressACTV.setAdapter(mPlaceArrayAdapter);

        // Dialog Builder
        AlertDialog.Builder editRunDialog = new AlertDialog.Builder(context);
        editRunDialog.setTitle(R.string.dialog_update_run_title).setView(inflaterView);
        editRunDialog.setPositiveButton(R.string.button_positive, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int id) {

                RunData runData = new RunData();

                int position = (int) run_date.getTag();
                runData.run_id = mRunID; 
                runData.collect_person = getStringOrEmpty(collectPersonEditText);
                runData.collect_address = getStringOrEmpty(collectAddressACTV);                              

                if (!runData.collect_address.isEmpty() ){
                    // try to update, if success update recycler.
                    if (runDbHelper.updateRun(runData, context)){

                        // atualiza o recyclerview
                        dataList.remove(position);
                        notifyItemRemoved(position);
                        dataList.add(position,runData);
                        notifyItemRangeChanged(position, dataList.size());
                        notifyItemInserted(position);

                    } else {
                        Toast.makeText(context, "Not updated record", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(context, R.string.dialog_insert_run_toast_nowhere, Toast.LENGTH_SHORT).show();
                }
            }

        });

        editRunDialog.setNegativeButton(R.string.button_negative, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                dialog.cancel();
            }
        });

        editRunDialog.create();
        editRunDialog.show();
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        mPlaceArrayAdapter.setGoogleApiClient(mGoogleApiClient);
        Log.i(TAG, "Google Places API connected.");
    }

    @Override
    public void onConnectionSuspended(int i) {
        mPlaceArrayAdapter.setGoogleApiClient(null);
        Log.e(TAG, "Google Places API connection suspended.");
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.e(TAG, "Google Places API connection failed with error code: "
                + connectionResult.getErrorCode());

        Toast.makeText(context,
                "Google Places API connection failed with error code:" +
                        connectionResult.getErrorCode(),
                Toast.LENGTH_LONG).show();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {

    }

    class RecyclerViewHolder extends RecyclerView.ViewHolder {
        TextView runID, collectPerson, collectAddress;
        TextView collectLat, collectLng;
        ImageView ivEdit;
        SwitchCompat swcCollect;

        RecyclerViewHolder(View rowView) {
            super(rowView);
            runID = (TextView) rowView.findViewById(R.id.runId);                
            ivEdit = (ImageView) rowView.findViewById(R.id.ivEdit);
            collectPerson = (TextView) rowView.findViewById(R.id.collectPerson);
            collectAddress = (TextView) rowView.findViewById(R.id.collectAddress);
        }
    }

    private AdapterView.OnItemClickListener mAutocompleteClickListener
            = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            final PlaceArrayAdapter.PlaceAutocomplete item = mPlaceArrayAdapter.getItem(position);
            final String placeId = String.valueOf(item.placeId);
            Log.i(TAG, "Selected: " + item.description);
            PendingResult<PlaceBuffer> placeResult = Places.GeoDataApi
                    .getPlaceById(mGoogleApiClient, placeId);
            placeResult.setResultCallback(mUpdatePlaceDetailsCallback);
            Log.i(TAG, "Fetching details for ID: " + item.placeId);
        }
    };

    private ResultCallback<PlaceBuffer> mUpdatePlaceDetailsCallback
            = new ResultCallback<PlaceBuffer>() {
        @Override
        public void onResult(PlaceBuffer places) {
            if (!places.getStatus().isSuccess()) {
                Log.e(TAG, "Place query did not complete. Error: " +
                        places.getStatus().toString());
                return;
            }
            // Selecting the first object buffer.
        }
    };
}

I tried to follow the model of RecyclerFragment, but there’s something wrong and I can’t instantiate the GoogleApiClient in the method onCreateView.

Note that you were using Google Places Webservice and this API works, but it should not be used on app in production, so I’m switching to Google Places API for Android.

I hope you can help me.

1 answer

1


After a lot of research, even in SOEN I found the answer in the documentation. As there was no attempt to reply and not even a comment, I think I will report what I found because it worked and you may find yourself in similar situation.

The problem is in this part:

mGoogleApiClient = new GoogleApiClient.Builder(getContext())
                .addApi(Places.GEO_DATA_API)
                .enableAutoManage(getActivity(), GOOGLE_API_CLIENT_ID, this)
                .addConnectionCallbacks(this)
                .build();

Specifically, in this method:

.enableAutoManage(getActivity(), GOOGLE_API_CLIENT_ID, this)

While it facilitates the lifecycle management of this API client as well as Highlander, there can only be one and so could not use the second time.

The solution was to use this variation:

    mGoogleApiClient = new GoogleApiClient.Builder(context)
            .addApi(Places.GEO_DATA_API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

In addition, you need to connect and disconnect the client. This is done by calling the methods connect() and disconnect() at appropriate locations and events onCreate() and onDestroy() of the activity or fragment.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.