I'm using google maps, and adding markers and clusters. What i want to happen is, when the user clicks either an single item or a cluster the information contained inside the mapItem object should be shown in a viewpager at the buttom of the screen. I can get the infomation down there but only on the second click of the map icon. Is there a way to make this update happen at the first click?
I have been looking at Textview is null on first click but updates on second click, but that solution didn't help me since the info is static from the fragment itself.
here is the code for my main activity:
package com.example.cpj.maptesting;
import android.Manifest;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.ui.PlaceAutocompleteFragment;
import com.google.android.gms.location.places.ui.PlaceSelectionListener;
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.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterManager;
import java.util.ArrayList;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, LocationListener{
private GoogleMap mMap;
private static ClusterManager<MapItem> itemClusterManager;
private static ArrayList<MapItem> listOfMarkers = new ArrayList<>();
private ArrayList<MapItem> listForFragments = new ArrayList<>();
private LocationManager locationManager;
PlaceAutocompleteFragment placeAutocompleteFragment;
Marker marker;
private Context context;
Location location;
ViewPager mViewpager;
InfoPageAdapter mPagerAdapter;
int counter = 0;
SparseArray<Fragment> fragments = new SparseArray<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
gpsPermission();
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
placeAutocompleteFragment = (PlaceAutocompleteFragment) getFragmentManager().findFragmentById(R.id.place_autocomplete);
context = getApplicationContext();
setUpPagers();
if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
alertBuilder();
}
placeAutocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
@Override
public void onPlaceSelected(Place place) {
if(marker != null){
marker.remove();
}
moveCamera(place.getLatLng());
marker = mMap.addMarker(new MarkerOptions()
.position(place.getLatLng())
.title("" + place.getAddress())
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
}
@Override
public void onError(Status status) {
Log.d("Error status: " , status.toString());
}
});
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(final GoogleMap googleMap) {
mMap = googleMap;
setUpMap();
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
mMap.setMyLocationEnabled(true);
location = locationManager.getLastKnownLocation(locationManager.getBestProvider(new Criteria(), false));
if(location != null){
moveCamera(new LatLng(location.getLatitude(), location.getLongitude()));
}
}
mMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
new dynamicallyAddMarkersTask().execute(mMap.getProjection().getVisibleRegion().latLngBounds);
}
});
mMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener() {
@Override
public boolean onMyLocationButtonClick() {
if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
alertBuilder();
}
return false;
}
});
setUpClusters();
}
@Override
public void onBackPressed() {
if (mViewpager.getCurrentItem() == 0) {
// If the user is currently looking at the first step, allow the system to handle the
// Back button. This calls finish() on this activity and pops the back stack.
super.onBackPressed();
} else {
// Otherwise, select the previous step.
mViewpager.setCurrentItem(mViewpager.getCurrentItem() - 1);
}
}
private void setUpClusters(){
itemClusterManager = new ClusterManager<>(this, getMap());
itemClusterManager.setAnimation(false);
itemClusterManager.clearItems();
listOfMarkers.clear();
getMap().setOnCameraIdleListener(itemClusterManager);
getMap().setOnMarkerClickListener(itemClusterManager);
itemClusterManager.setOnClusterClickListener(new ClusterManager.OnClusterClickListener<MapItem>() {
@Override
public boolean onClusterClick(Cluster<MapItem> cluster) {
setupClusterClicked(cluster);
listForFragments.addAll(cluster.getItems());
mViewpager.setCurrentItem(0);
infoPageFragment ipf = (infoPageFragment) mPagerAdapter.getFragments(0);
if(ipf != null){
ipf.setAdresse("Adresse: " + cluster.getItems().iterator().next().getTitle());
ipf.setNummer(1 + "/" + listForFragments.size());
}
return false;
}
});
itemClusterManager.setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<MapItem>() {
@Override
public boolean onClusterItemClick(MapItem mapItem) {
setupClusterItem();
mViewpager.setCurrentItem(0);
int position = mViewpager.getCurrentItem();
infoPageFragment ipf = (infoPageFragment) mPagerAdapter.getFragments(position);
if(ipf != null){
ipf.setAdresse("Adresse: " + mapItem.getTitle());
ipf.setNummer("");
}
return false;
}
});
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
mViewpager.setVisibility(View.GONE);
}
});
itemClusterManager.setRenderer(new CustomIcon(this, mMap, itemClusterManager));
addMapItem(new MapItem(56.162939, 10.203727, "Nabo", "Holde"));
addMapItem(new MapItem(56.162939, 10.203921, "Harald", "Plads"));
addMapItem(new MapItem(56.162939, 10.203921, "Jensen", "Plads1"));
addMapItem(new MapItem(56.162939, 10.203921, "Mogens", "Plads2"));
addMapItem(new MapItem(56.162939, 10.203921, "Jørgensen", "Plads3"));
addMapItem(new MapItem(56.162939, 10.203921, "Hansen", "Plads4"));
mViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
@Override
public void onPageSelected(int position) {
infoPageFragment ipf;
for(MapItem mapItem : listForFragments){
ipf = (infoPageFragment) mPagerAdapter.getFragments(position);
mapItem = listForFragments.get(position);
int increment = position+1;
if(ipf != null){
String text = increment + "/" + listForFragments.size();
ipf.setAdresse("Adresse: " + mapItem.getTitle());
ipf.setNummer(text);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {}
});
mPagerAdapter.notifyDataSetChanged();
}
@Override
public void onLocationChanged(Location location) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
moveCamera(latLng);
locationManager.removeUpdates(this);
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {}
@Override
public void onProviderEnabled(String s) {}
@Override
public void onProviderDisabled(String s) {}
private GoogleMap getMap() {
return mMap;
}
private void setUpMap(){
mMap.getUiSettings().setTiltGesturesEnabled(false);
mMap.getUiSettings().setRotateGesturesEnabled(false);
mMap.getUiSettings().setMapToolbarEnabled(false);
}
private void gpsPermission(){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
private void alertBuilder(){
final AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setTitle("GPS setting");
alertDialog.setMessage("This app needs gps, to find the closet parking spots! \nGo to settings?");
alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
context.startActivity(intent);
}
});
alertDialog.setNegativeButton("Not now", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {}
});
AlertDialog alert = alertDialog.create();
alert.show();
}
private void moveCamera(LatLng latLng){
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 16);
mMap.animateCamera(cameraUpdate);
}
private void addMapItem(MapItem item){
listOfMarkers.add(item);
itemClusterManager.addItem(item);
}
private void setupClusterItem(){
counter = 1;
mViewpager.setVisibility(View.VISIBLE);
mPagerAdapter.notifyDataSetChanged();
}
private void setupClusterClicked(Cluster<MapItem> cluster){
listForFragments.clear();
mViewpager.setVisibility(View.VISIBLE);
counter = cluster.getSize();
mPagerAdapter.notifyDataSetChanged();
}
private void setUpPagers(){
mViewpager = findViewById(R.id.viewPager);
mPagerAdapter = new InfoPageAdapter(getSupportFragmentManager());
mViewpager.setAdapter(mPagerAdapter);
}
private static class dynamicallyAddMarkersTask extends AsyncTask<LatLngBounds, Void, Void> {
@Override
protected Void doInBackground(LatLngBounds... bounds) {
itemClusterManager.clearItems();
for(MapItem mapItem: listOfMarkers){
if(bounds[0].contains(mapItem.getPosition())){
itemClusterManager.addItem(mapItem);
}
}
return null;
}
@Override
protected void onPostExecute(Void result){
itemClusterManager.cluster();
}
}
private class InfoPageAdapter extends FragmentStatePagerAdapter{
public InfoPageAdapter(android.support.v4.app.FragmentManager fm){
super(fm);
}
@Override
public Fragment getItem(int position) {
return new infoPageFragment();
}
@Override
public int getItemPosition(Object obj){
return POSITION_NONE;
}
@Override
public Object instantiateItem(ViewGroup viewGroup, int position){
Fragment fragment = (Fragment) super.instantiateItem(viewGroup, position);
fragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup viewGroup, int position, Object object){
fragments.remove(position);
super.destroyItem(viewGroup, position, object);
}
public Fragment getFragments(int position){
return fragments.get(position);
}
@Override
public int getCount() {
return counter;
}
}
}
This is the fragment
package com.example.cpj.maptesting;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class infoPageFragment extends Fragment {
TextView adresse, nummer;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.info_page, container, false);
adresse = rootView.findViewById(R.id.adresse);
nummer = rootView.findViewById(R.id.nummer);
return rootView;
}
public void setAdresse(String value){
adresse.setText(value);
}
public void setNummer(String value){
nummer.setText(value);
}
}
activity_maps.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="10"
tools:context=".MapsActivity">
<fragment
android:id="@+id/place_autocomplete"
android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="633dp" />
<LinearLayout
android:id="@+id/pagerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="visible"
android:weightSum="1"
>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
and the info_page.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/info_page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView style="?android:textAppearanceMedium"
android:padding="16dp"
android:id="@+id/adresse"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Adresse: "/>
<TextView style="?android:textAppearanceMedium"
android:id="@+id/nummer"
android:padding="16dp"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
/>
</LinearLayout>
I realise this has something to do with fragment lifecycle but I just can't seem to figure out what the last bit I'm missing is.
Thanks for the answers.
ps. Please bear with me on the sloppy code I'm still quite the rookie when it comes to android development :).