Last active
April 17, 2022 19:36
-
-
Save juancoob/be7b831afb43973b5575129eaf66f46a to your computer and use it in GitHub Desktop.
ItemKeyedDataSource is not calling LoadAfter and my list is not filled. I think I have a race condition
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.juancoob.nanodegree.and.vegginner.ui.places; | |
import android.annotation.SuppressLint; | |
import android.app.AlertDialog; | |
import android.arch.lifecycle.ViewModelProviders; | |
import android.arch.paging.PagedList; | |
import android.content.Context; | |
import android.content.IntentSender; | |
import android.content.pm.PackageManager; | |
import android.location.Location; | |
import android.os.Bundle; | |
import android.os.Looper; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.Fragment; | |
import android.support.v4.content.ContextCompat; | |
import android.support.v7.widget.AppCompatSpinner; | |
import android.support.v7.widget.LinearLayoutManager; | |
import android.support.v7.widget.RecyclerView; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.Button; | |
import android.widget.ImageView; | |
import android.widget.ProgressBar; | |
import android.widget.TextView; | |
import com.google.android.gms.common.ConnectionResult; | |
import com.google.android.gms.common.api.GoogleApiClient; | |
import com.google.android.gms.location.FusedLocationProviderClient; | |
import com.google.android.gms.location.LocationCallback; | |
import com.google.android.gms.location.LocationListener; | |
import com.google.android.gms.location.LocationRequest; | |
import com.google.android.gms.location.LocationResult; | |
import com.google.android.gms.location.LocationServices; | |
import com.google.android.gms.maps.CameraUpdate; | |
import com.google.android.gms.maps.CameraUpdateFactory; | |
import com.google.android.gms.maps.GoogleMap; | |
import com.google.android.gms.maps.OnMapReadyCallback; | |
import com.google.android.gms.maps.SupportMapFragment; | |
import com.google.android.gms.maps.model.BitmapDescriptorFactory; | |
import com.google.android.gms.maps.model.LatLng; | |
import com.google.android.gms.maps.model.LatLngBounds; | |
import com.google.android.gms.maps.model.Marker; | |
import com.google.android.gms.maps.model.MarkerOptions; | |
import com.juancoob.nanodegree.and.vegginner.R; | |
import com.juancoob.nanodegree.and.vegginner.VegginnerApp; | |
import com.juancoob.nanodegree.and.vegginner.data.places.Place; | |
import com.juancoob.nanodegree.and.vegginner.data.places.PlaceRepository; | |
import com.juancoob.nanodegree.and.vegginner.util.Constants; | |
import com.juancoob.nanodegree.and.vegginner.viewmodel.PlacesViewModel; | |
import com.juancoob.nanodegree.and.vegginner.viewmodel.VegginnerViewModelFactory; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Objects; | |
import javax.inject.Inject; | |
import butterknife.BindView; | |
import butterknife.ButterKnife; | |
import butterknife.OnClick; | |
import butterknife.OnItemSelected; | |
import timber.log.Timber; | |
import static android.Manifest.permission.ACCESS_FINE_LOCATION; | |
/** | |
* This fragment shows a map, an spinner to select the place type to find and a list to read easily all results | |
* <p> | |
* Created by Juan Antonio Cobos Obrero on 6/08/18. | |
*/ | |
public class PlacesFrament extends Fragment implements OnMapReadyCallback, | |
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, | |
LocationListener, ISelectedPlaceCallback { | |
@BindView(R.id.tv_map_spinner_label) | |
public TextView mapSpinnerLabelTextView; | |
@BindView(R.id.acs_place_types) | |
public AppCompatSpinner placeTypesAppCompatSpinner; | |
@BindView(R.id.rv_places) | |
public RecyclerView placesRecyclerView; | |
@BindView(R.id.pb_loading_places) | |
public ProgressBar loadingPlacesProgressBar; | |
@BindView(R.id.iv_powered_by_google) | |
public ImageView poweredByGoogleImageView; | |
@BindView(R.id.tv_no_places) | |
public TextView noPlacesTextView; | |
@BindView(R.id.btn_retry) | |
public Button retryButton; | |
@BindView(R.id.btn_location) | |
public Button locationButton; | |
@Inject | |
public VegginnerViewModelFactory vegginnerViewModelFactory; | |
@Inject | |
public PlaceRepository mPlaceRepository; | |
private PlacesViewModel mPlacesViewModel; | |
private Context mCtx; | |
private GoogleMap mGoogleMap; | |
private GoogleApiClient mGoogleApiClient; | |
private FusedLocationProviderClient mFusedLocationProviderClient; | |
private LocationCallback mLocationCallback; | |
private Location mCurrentLocation; | |
private LocationRequest mLocationRequest; | |
private PlacesListAdapter mPlacesListAdapter; | |
private List<Marker> mMarkersRetrieved; | |
public PlacesFrament() { | |
// Required empty public constructor | |
} | |
public static PlacesFrament getInstance() { | |
return new PlacesFrament(); | |
} | |
@Override | |
public void onAttach(Context context) { | |
super.onAttach(context); | |
mCtx = context; | |
} | |
@Override | |
public void onCreate(@Nullable Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
((VegginnerApp) mCtx.getApplicationContext()).getVegginnerRoomComponent().injectPlacesSection(this); | |
mMarkersRetrieved = new ArrayList<>(); | |
} | |
@Nullable | |
@Override | |
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { | |
View view = inflater.inflate(R.layout.fragment_places, container, false); | |
ButterKnife.bind(this, view); | |
requestAccessFineLocationPermission(); | |
mPlacesViewModel = ViewModelProviders.of(Objects.requireNonNull(getActivity()), vegginnerViewModelFactory).get(PlacesViewModel.class); | |
return view; | |
} | |
private void requestAccessFineLocationPermission() { | |
if (ContextCompat.checkSelfPermission(mCtx, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { | |
if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) { | |
AlertDialog.Builder builder = new AlertDialog.Builder(mCtx); | |
builder.setTitle(R.string.location_dialog_title) | |
.setMessage(R.string.location_dialog_message) | |
.setCancelable(false) | |
.setPositiveButton(R.string.ok, (dialogInterface, i) -> { | |
dialogInterface.dismiss(); | |
requestPermissions(new String[]{ACCESS_FINE_LOCATION}, Constants.REQUEST_ACCESS_FINE_LOCATION); | |
}) | |
.show(); | |
} else { | |
requestPermissions(new String[]{ACCESS_FINE_LOCATION}, Constants.REQUEST_ACCESS_FINE_LOCATION); | |
} | |
} else { | |
initMaps(); | |
updateUi(); | |
initLocation(); | |
initPlacesRecyclerView(); | |
} | |
} | |
@Override | |
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | |
super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
switch (requestCode) { | |
case Constants.REQUEST_ACCESS_FINE_LOCATION: | |
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | |
initMaps(); | |
updateUi(); | |
initLocation(); | |
initPlacesRecyclerView(); | |
} | |
break; | |
} | |
} | |
private void initMaps() { | |
SupportMapFragment supportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.f_map); | |
supportMapFragment.getMapAsync(this); | |
mGoogleApiClient = new GoogleApiClient.Builder(mCtx) | |
.addConnectionCallbacks(this) | |
.addOnConnectionFailedListener(this) | |
.addApi(LocationServices.API) | |
.build(); | |
} | |
@SuppressLint("MissingPermission") | |
@Override | |
public void onMapReady(GoogleMap googleMap) { | |
googleMap.setMyLocationEnabled(true); | |
mGoogleMap = googleMap; | |
} | |
private void updateUi() { | |
mapSpinnerLabelTextView.setVisibility(View.VISIBLE); | |
placeTypesAppCompatSpinner.setVisibility(View.VISIBLE); | |
placesRecyclerView.setVisibility(View.VISIBLE); | |
showProgressBar(); | |
poweredByGoogleImageView.setVisibility(View.VISIBLE); | |
locationButton.setVisibility(View.GONE); | |
} | |
private void initLocation() { | |
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(mCtx); | |
mLocationRequest = LocationRequest.create() | |
.setInterval(Constants.UPDATE_LOCATION_INTERVAL) | |
.setFastestInterval(Constants.FASTEST_UPDATE_LOCATION_INTERVAL) | |
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); | |
mLocationCallback = new LocationCallback() { | |
@Override | |
public void onLocationResult(LocationResult locationResult) { | |
super.onLocationResult(locationResult); | |
setCurrentLocation(locationResult.getLastLocation()); | |
handleCurrentLocation(); | |
loadResultsBySelectedPlaceType(); | |
} | |
}; | |
} | |
private void initPlacesRecyclerView() { | |
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mCtx); | |
placesRecyclerView.setLayoutManager(linearLayoutManager); | |
mPlacesListAdapter = new PlacesListAdapter(mCtx, this); | |
placesRecyclerView.setAdapter(mPlacesListAdapter); | |
} | |
private void setCurrentLocation(Location newLocation) { | |
if (newLocation != mCurrentLocation) { | |
mCurrentLocation = newLocation; | |
mPlacesViewModel.setLocation(String.format(getString(R.string.location_format), | |
Double.toString(mCurrentLocation.getLatitude()), Double.toString(mCurrentLocation.getLongitude()))); | |
} | |
} | |
@Override | |
public void onResume() { | |
super.onResume(); | |
if (ContextCompat.checkSelfPermission(mCtx, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { | |
mGoogleApiClient.connect(); | |
} | |
} | |
@Override | |
public void onPause() { | |
super.onPause(); | |
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { | |
mGoogleApiClient.disconnect(); | |
mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback); | |
} | |
} | |
@OnClick(R.id.btn_location) | |
public void onLocationButtonClick() { | |
requestAccessFineLocationPermission(); | |
} | |
@SuppressLint("MissingPermission") | |
@Override | |
public void onConnected(@Nullable Bundle bundle) { | |
Timber.i("Location services connected"); | |
mFusedLocationProviderClient.getLastLocation().addOnSuccessListener(Objects.requireNonNull(getActivity()), location -> { | |
if (location != null) { | |
setCurrentLocation(location); | |
handleCurrentLocation(); | |
loadResultsBySelectedPlaceType(); | |
} else { | |
mFusedLocationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper()); | |
} | |
}); | |
} | |
@Override | |
public void onLocationChanged(Location location) { | |
setCurrentLocation(location); | |
handleCurrentLocation(); | |
loadResultsBySelectedPlaceType(); | |
} | |
@OnItemSelected(R.id.acs_place_types) | |
public void onPlaceTypeSelected() { | |
// Get selected item and set it to the repository | |
mPlaceRepository.setPlaceType(placeTypesAppCompatSpinner.getSelectedItem().toString()); | |
// Don't clear the map if it is the first time because the current location is loaded | |
if (!mMarkersRetrieved.isEmpty()) { | |
mGoogleMap.clear(); | |
mMarkersRetrieved.clear(); | |
hideNoElements(); | |
handleCurrentLocation(); | |
mPlacesViewModel.loadPlaceData(); | |
} | |
} | |
public void handleCurrentLocation() { | |
Timber.i("Location: %s", mCurrentLocation.toString()); | |
double latitude = mCurrentLocation.getLatitude(); | |
double longitude = mCurrentLocation.getLongitude(); | |
LatLng myLocation = new LatLng(latitude, longitude); | |
MarkerOptions markerOptions = new MarkerOptions().position(myLocation).title(getString(R.string.here)); | |
Marker marker = mGoogleMap.addMarker(markerOptions); | |
// If it is the first time, make the location animation | |
if (mMarkersRetrieved.isEmpty()) { | |
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(myLocation)); | |
} | |
marker.showInfoWindow(); | |
} | |
private void loadResultsBySelectedPlaceType() { | |
//String location = "-33.8670522,151.1957362"; | |
hideProgressBar(); | |
mPlacesViewModel.getPlacePagedList().observe(Objects.requireNonNull(getActivity()), places -> { | |
if(places != null && !places.isEmpty()) { | |
mPlacesListAdapter.submitList(places); | |
} | |
checkPlaces(places); | |
}); | |
mPlacesViewModel.getInitialLoading().observe(getActivity(), initialNetworkState -> { | |
mPlacesListAdapter.checkInitialLoading(initialNetworkState); | |
}); | |
mPlacesViewModel.getNetworkState().observe(getActivity(), networkState -> { | |
mPlacesListAdapter.setNetworkState(networkState); | |
}); | |
} | |
private void checkPlaces(PagedList<Place> places) { | |
if (places != null && places.size() > 0) { | |
showVegFriendlyPlaces(places); | |
hideNoElements(); | |
} else { | |
showNoElements(); | |
} | |
} | |
private void showVegFriendlyPlaces(PagedList<Place> places) { | |
LatLng newLocation; | |
MarkerOptions markerOptions; | |
Marker marker; | |
LatLngBounds.Builder builder = new LatLngBounds.Builder(); | |
for (Place place : places) { | |
newLocation = new LatLng(place.getGeometry().getLocation().getLatitude(), place.getGeometry().getLocation().getLongitude()); | |
markerOptions = new MarkerOptions().position(newLocation) | |
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)) | |
.title(place.getPlaceName()); | |
marker = mGoogleMap.addMarker(markerOptions); | |
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(newLocation)); | |
mMarkersRetrieved.add(marker); | |
builder.include(marker.getPosition()); | |
} | |
LatLngBounds latLngBounds = builder.build(); | |
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngBounds(latLngBounds, mCtx.getResources().getInteger(R.integer.zero)); | |
mGoogleMap.animateCamera(cameraUpdate); | |
} | |
@Override | |
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { | |
Timber.i("Location services failed!"); | |
if (connectionResult.hasResolution()) { | |
try { | |
connectionResult.startResolutionForResult(getActivity(), Constants.REQUEST_CONNECTION_FAILURE); | |
} catch (IntentSender.SendIntentException exception) { | |
Timber.e(exception); | |
} | |
} else { | |
Timber.i("Location services connection failed with code: %d", connectionResult.getErrorCode()); | |
} | |
} | |
@Override | |
public void onConnectionSuspended(int i) { | |
Timber.i("Location services suspended"); | |
} | |
@Override | |
public void onSaveInstanceState(@NonNull Bundle outState) { | |
super.onSaveInstanceState(outState); | |
outState.putInt(Constants.SPINNER_POSITION, placeTypesAppCompatSpinner.getSelectedItemPosition()); | |
} | |
@Override | |
public void onViewStateRestored(@Nullable Bundle savedInstanceState) { | |
super.onViewStateRestored(savedInstanceState); | |
if (savedInstanceState != null) { | |
placeTypesAppCompatSpinner.setSelection(savedInstanceState.getInt(Constants.SPINNER_POSITION)); | |
} | |
} | |
@Override | |
public void showSelectedPlaceOnMap(Place place) { | |
Marker marker = getMarker(place.getPlaceName()); | |
if (marker != null) { | |
marker.showInfoWindow(); | |
LatLng latLng = new LatLng(place.getGeometry().getLocation().getLatitude(), place.getGeometry().getLocation().getLongitude()); | |
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLng(latLng)); | |
} | |
} | |
@Nullable | |
private Marker getMarker(String placeName) { | |
for (Marker marker : mMarkersRetrieved) { | |
if (marker.getTitle().equals(placeName)) { | |
return marker; | |
} | |
} | |
return null; | |
} | |
@Override | |
public void showProgressBar() { | |
loadingPlacesProgressBar.setVisibility(View.VISIBLE); | |
} | |
@Override | |
public void hideProgressBar() { | |
loadingPlacesProgressBar.setVisibility(View.GONE); | |
} | |
@Override | |
public void loadPlacesAgain() { | |
mPlacesViewModel.loadPlaceData(); | |
/*mPlacesViewModel.getAgainSamePlacePagedList().observe(Objects.requireNonNull(getActivity()), places -> { | |
if (places != null && places.size() > 0) { | |
mPlacesListAdapter.submitList(places); | |
checkPlaces(places); | |
} | |
});*/ | |
} | |
@Override | |
public void showNoElements() { | |
noPlacesTextView.setVisibility(View.VISIBLE); | |
retryButton.setVisibility(View.VISIBLE); | |
placesRecyclerView.setVisibility(View.GONE); | |
poweredByGoogleImageView.setVisibility(View.GONE); | |
} | |
public void hideNoElements() { | |
noPlacesTextView.setVisibility(View.GONE); | |
retryButton.setVisibility(View.GONE); | |
placesRecyclerView.setVisibility(View.VISIBLE); | |
poweredByGoogleImageView.setVisibility(View.VISIBLE); | |
} | |
@OnClick(R.id.btn_retry) | |
public void onRetryButtonClick() { | |
hideNoElements(); | |
showProgressBar(); | |
loadPlacesAgain(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment