0

item_place_picker.xml -- activity_explore.xml--activity_maps

There is a lot of similar questions, but I couldn't get answers. My problem is that when I am trying to use FusedLocationProviderClient to get users location, nothing show up on the recyclerView and logical says "RecyclerView: No adapter attached; skipping layout". I guess I am calling the adapter in wrong place/method so it can search for the adapter, which is declared in another class.

I know the problem is with the fusedLocationProviderClient and the onSucess method, because when I first built the app I used the old android framework location API, and everything worked perfectly. So the problem is in some way related to the on success method, but I can't figure out how.(The most important parts of the code are in the onConnected method).

  public class ExploreActivity extends Activity implements       GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener {
// The client object for connecting to the Google API
private FusedLocationProviderClient mFusedLocationClient;


List<FoursquareResults> frs;

// The TextView for displaying the current location
private TextView snapToPlace;

// The RecyclerView and associated objects for displaying the nearby coffee spots
private RecyclerView placePicker;
LinearLayoutManager placePickerManager;
private RecyclerView.Adapter placePickerAdapter;

// The base URL for the Foursquare API
String foursquareBaseURL = "https://api.foursquare.com/v2/";

// The client ID and client secret for authenticating with the Foursquare API
private String clientID;
private String clientSecret;

String categoryId = "4cce455aebf7b749d5e191f5";


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_explore);



    // The visible TextView and RecyclerView objects
    snapToPlace = findViewById(R.id.snapToPlace);
    placePicker = findViewById(R.id.fieldsList);

    // Sets the dimensions, LayoutManager, and dividers for the RecyclerView
    placePicker.setHasFixedSize(true);
    placePickerManager = new LinearLayoutManager(this);
    placePicker.setLayoutManager(placePickerManager);
    placePicker.addItemDecoration(new DividerItemDecoration(placePicker.getContext(), placePickerManager.getOrientation()));

    // Creates a connection to the Google API for location services
    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);


    // Gets the stored Foursquare API client ID and client secret from XML
    clientID = getResources().getString(R.string.foursquare_api_client_id);
    clientSecret = getResources().getString(R.string.foursquare_client_secret);


}

@Override
public void onConnected(Bundle connectionHint) {

    // Checks for location permissions at runtime (required for API >= 23)
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

        // Makes a Google API request for the user's last known location
        mFusedLocationClient.getLastLocation()
                .addOnSuccessListener(this, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        // Got last known location. In some rare situations this can be null.
                        if (location != null) {
                            // Logic to handle location object

                            // The user's current latitude, longitude, and location accuracy
                            String ll = location.getLatitude() + "," + location.getLongitude();
                            double llAcc = location.getAccuracy();

                            // Builds Retrofit and FoursquareService objects for calling the Foursquare API and parsing with GSON
                            Retrofit retrofit = new Retrofit.Builder()
                                    .baseUrl(foursquareBaseURL)
                                    .addConverterFactory(GsonConverterFactory.create())
                                    .build();
                            FoursquareService foursquare = retrofit.create(FoursquareService.class);

                            // Calls the Foursquare API to snap the user's location to a Foursquare venue
                            Call<FoursquareJSON> stpCall = foursquare.snapToPlace(
                                    clientID,
                                    clientSecret,
                                    ll,
                                    llAcc,
                                    categoryId);

                            stpCall.enqueue(new Callback<FoursquareJSON>() {
                                @Override
                                public void onResponse(Call<FoursquareJSON> call, Response<FoursquareJSON> response) {

                                    placePickerAdapter = new PlacePickerAdapter(getApplicationContext(), frs);
                                    placePicker.setAdapter(placePickerAdapter);

                                    // Gets the venue object from the JSON response
                                    FoursquareJSON fjson = response.body();
                                    FoursquareResponse fr = fjson.response;
                                    List<FoursquareVenue> frs = fr.venues;
                                    FoursquareVenue fv = frs.get(0);

                                    // Notifies the user of their current location
                                    snapToPlace.setText("You're at " + fv.name + ". Here's some fields nearby.");
                                }

                                @Override
                                public void onFailure(Call<FoursquareJSON> call, Throwable t) {
                                    Toast.makeText(getApplicationContext(), "Can't connect to Foursquare's servers!", Toast.LENGTH_LONG).show();
                                    finish();
                                }
                            });

                            // Calls the Foursquare API to explore nearby fields
                            Call<FoursquareJSON> fieldsCall = foursquare.searchCoffee(
                                    clientID,
                                    clientSecret,
                                    ll,
                                    llAcc,
                                    categoryId);


                            fieldsCall.enqueue(new Callback<FoursquareJSON>() {
                                @Override
                                public void onResponse(Call<FoursquareJSON> call, Response<FoursquareJSON> response) {

                                    // Gets the venue object from the JSON response
                                    FoursquareJSON fjson = response.body();
                                    FoursquareResponse fr = fjson.response;
                                    FoursquareGroup fg = fr.group;
                                    List<FoursquareResults> frs = fg.results;

                                    // Displays the results in the RecyclerView

                                }

                                @Override
                                public void onFailure(Call<FoursquareJSON> call, Throwable t) {
                                    Toast.makeText(getApplicationContext(), "Can't connect to Foursquare's servers!", Toast.LENGTH_LONG).show();
                                    finish();
                                }
                            });
                        } else {
                            Toast.makeText(getApplicationContext(), "Can't determine your current location!", Toast.LENGTH_LONG).show();
                            finish();

                        }
                    }
                });
    }



}

@Override
protected void onResume() {
    super.onResume();
    mFusedLocationClient.getLastLocation();
}

@Override
protected void onPause() {
    super.onPause();
    mFusedLocationClient.flushLocations();
}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    Toast.makeText(getApplicationContext(), "Mr. Jitters can't connect to Google's servers!", Toast.LENGTH_LONG).show();
    finish();
}
   }

Adapter code:

//PlacePickerAdapter represents the adapter for attaching venue data to the RecyclerView within
//PlacePickerActivity.  This adapter will handle a list of incoming FoursquareResults and parse them
// into the view.

public class PlacePickerAdapter extends RecyclerView.Adapter<PlacePickerAdapter.ViewHolder> {

// The application context for getting resources
private Context context;

// The list of results from the Foursquare API
private List<FoursquareResults> results;

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    // The venue fields to display
    TextView name;
    TextView address;
    TextView rating;
    TextView distance;
    String id;
    double latitude;
    double longitude;

    public ViewHolder(View v) {
        super(v);
        v.setOnClickListener(this);

        // Gets the appropriate view for each venue detail
        name = (TextView)v.findViewById(R.id.placePickerItemName);
        address = (TextView)v.findViewById(R.id.placePickerItemAddress);
        rating = (TextView)v.findViewById(R.id.placePickerItemRating);
        distance = (TextView)v.findViewById(R.id.placePickerItemDistance);
    }

    @Override
    public void onClick(View v) {

        // Creates an intent to direct the user to a map view
        Context context = name.getContext();
        Intent i = new Intent(context, DetailFieldActivity.class);

        // Passes the crucial venue details onto the map view
        i.putExtra("name", name.getText());
        i.putExtra("ID", id);
        i.putExtra("latitude", latitude);
        i.putExtra("longitude", longitude);

        // Transitions to the map view.
        context.startActivity(i);
    }
}

public PlacePickerAdapter(Context context, List<FoursquareResults> results) {
    this.context = context;
    this.results = results;
}

@Override
public PlacePickerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_place_picker, parent, false);
    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

    // Sets the proper rating colour, referenced from the Foursquare Brand Guide
    double ratingRaw = results.get(position).venue.rating;
    if (ratingRaw >= 9.0) {
        holder.rating.setBackgroundColor(ContextCompat.getColor(context, R.color.FSQKale));
    } else if (ratingRaw >= 8.0) {
        holder.rating.setBackgroundColor(ContextCompat.getColor(context, R.color.FSQGuacamole));
    } else if (ratingRaw >= 7.0) {
        holder.rating.setBackgroundColor(ContextCompat.getColor(context, R.color.FSQLime));
    } else if (ratingRaw >= 6.0) {
        holder.rating.setBackgroundColor(ContextCompat.getColor(context, R.color.FSQBanana));
    } else if (ratingRaw >= 5.0) {
        holder.rating.setBackgroundColor(ContextCompat.getColor(context, R.color.FSQOrange));
    } else if (ratingRaw >= 4.0) {
        holder.rating.setBackgroundColor(ContextCompat.getColor(context, R.color.FSQMacCheese));
    } else {
        holder.rating.setBackgroundColor(ContextCompat.getColor(context, R.color.FSQStrawberry));
    }

    // Sets each view with the appropriate venue details
    holder.name.setText(results.get(position).venue.name);
    holder.address.setText(results.get(position).venue.location.address);
    holder.rating.setText(Double.toString(ratingRaw));
    holder.distance.setText(Integer.toString(results.get(position).venue.location.distance) + "m");

    // Stores additional venue details for the map view
    holder.id = results.get(position).venue.id;
    holder.latitude = results.get(position).venue.location.lat;
    holder.longitude = results.get(position).venue.location.lng;
}

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

DetailActivityCode, which gets called when item from recyclerView item is clicked:

  public class DetailFieldActivity extends FragmentActivity
    implements OnMapReadyCallback, GoogleMap.OnInfoWindowClickListener   {

// The Google Maps object.
private GoogleMap mMap;

// The details of the venue that is being displayed.
private String venueID;
private String venueName;
private double venueLatitude;
private double venueLongitude;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    getActionBar().setHomeButtonEnabled(true);
    getActionBar().setDisplayHomeAsUpEnabled(true);

    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);

    // Retrieves venues details from the intent sent from PlacePickerActivity
    Bundle venue = getIntent().getExtras();
    venueID = venue.getString("ID");
    venueName = venue.getString("name");
    venueLatitude = venue.getDouble("latitude");
    venueLongitude = venue.getDouble("longitude");
    setTitle(venueName);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpFromSameTask(this);
            return true;
    }
    return super.onOptionsItemSelected(item);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    // Centers and zooms the map into the selected venue
    LatLng venue = new LatLng(venueLatitude, venueLongitude);
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(venue, 16));

    // Creates and displays marker and info window for the venue
    Marker marker = mMap.addMarker(new MarkerOptions()
            .position(venue)
            .title(venueName)
            .snippet("View on Foursquare"));
    marker.showInfoWindow();
    mMap.setOnInfoWindowClickListener(this);

    // Checks for location permissions at runtime (required for API >= 23)
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {

        // Shows the user's current location
        mMap.setMyLocationEnabled(true);
    }
}

@Override
public void onInfoWindowClick(Marker marker) {

    // Opens the Foursquare venue page when a user clicks on the info window of the venue
    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://foursquare.com/v/" + venueID));
    startActivity(browserIntent);
}
 }

FoursquareGroup:

//FoursquareGroup describes a group object from the Foursquare API.
public class FoursquareGroup {

// A results list within the group.
List<FoursquareResults> results = new ArrayList<FoursquareResults>();
  }

foursquareJSON:

//FoursquareJSON describes a JSON response from the Foursquare API.
 public class FoursquareJSON {

// A response object within the JSON.
FoursquareResponse response;

   }

FoursquareLocation:

 //FoursquareLocation describes a location object from the Foursquare    API.
  public class FoursquareLocation {

// The address of the location.
String address;

// The latitude of the location.
double lat;

// The longitude of the location.
double lng;

// The distance of the location, calculated from the specified   location.
int distance;
    }

FoursquareResponse:

//FoursquareResponse describes a response object from the Foursquare API.
  public class FoursquareResponse {

// A group object within the response.
FoursquareGroup group;
List<FoursquareVenue> venues = new ArrayList<>();
    }

FoursquareResults:

//FoursquareResults describes a results object from the Foursquare API.
 public class FoursquareResults {

// A venue object within the results.
FoursquareVenue venue;
   }

FoursquareService:

//FoursquareService provides a Retrofit interface for the Foursquare   API.

 public interface FoursquareService {

// A request to snap the current user to a place via the Foursquare API.
@GET("venues/search?v=20161101&limit=1") //search endpoint
Call<FoursquareJSON> snapToPlace(@Query("client_id") String clientID,
                                 @Query("client_secret") String   clientSecret,
                                 @Query("ll") String ll,
                                 @Query("llAcc") double llAcc,
                                 @Query("categoryId") String categoryId);


// A request to search for nearby coffee shop recommendations via the   Foursquare API.
@GET("search/recommendations?v=20161101&intent=soccer")
Call<FoursquareJSON> searchCoffee(@Query("client_id") String clientID,
                                  @Query("client_secret") String  clientSecret,
                                  @Query("ll") String ll,
                                  @Query("llAcc") double llAcc,
                                  @Query("categoryId") String categoryId);

    }

FoursquareVenue:

 public class FoursquareVenue {
// The ID of the venue.
String id;

// The name of the venue.
String name;

// The rating of the venue, if available.
double rating;

// A location object within the venue.
FoursquareLocation location;
     }
Olli Toivanen
  • 103
  • 1
  • 8

0 Answers0