I've a class "MainActivity" which calls the different fragments in particular a fragment which display a GoogleMap called MapsFragment.
When this fragment is called for the first time, I had some markers (which are refresh every timeToRefresh. The method startDrawingBomb() is called from the MainActivity class) and everything works perfectly when the user do not change to another fragment.
When a user ask to move to an other fragment I save the the MapsFragment created before in the backStack of the MainActivity (to retrieve it later)
The problem happens when I call this MapsFragment a second time, the fragment is displaying the map but not all the markers I've added before.
I imagine it's because the MapView, and the GoogleMap created by the MapsFragment are not the same as before.
My question is : How can I retrieve the map that I draw before easily ? Or I had to stop all my threads (in onPause() for example), create a new MapsFragment, obtain a new MapView, a new GoogleMap object and apply again all the previous threads ?
This is a part of my MapsFragment :
public class MapsFragment extends Fragment implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener, LocationListener {
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private OnMessageListener mCallback;
private GoogleMap _googleMap;
private MapView mMapView;
private ArrayList<Marker> markerArrayListScout = new ArrayList<>();
private ArrayList<Circle> markerArrayListBomb= new ArrayList<>();
private ArrayList<String> idToCircleId = new ArrayList<>();
private ArrayList<Integer> idArray = new ArrayList<>();
private boolean isfirstLocation = true;
boolean mustBeScoutLocationEnabled;
boolean mustDrawCircle;
public MapsFragment(){
super();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("MAPS_FRAGMENT","onCreate() called");
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.v("MAPS_FRAGMENT","onCreateView() called");
View rootView = inflater.inflate(R.layout.map, container, false);
mMapView = (MapView) rootView.findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.onResume(); // needed to get the map to display immediately
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mMapView.getMapAsync(this);
return rootView;
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
#Override
public void onMapReady(GoogleMap googleMap) {
Log.v("MAPS_FRAGMENT","onMapReady() called");
_googleMap = googleMap;
_googleMap.setMyLocationEnabled(true);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.v("Location","onConnected");
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(1000); // Update location every second
//Execute location service call if user has explicitly granted ACCESS_FINE_LOCATION..
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
Log.v("Location","onConnectionSuspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.v("Location","onConnectionFailed");
}
#Override
public void onLocationChanged(Location location) {
Log.v("Location","location : " + location.toString());
// Add a marker and move the camera
if(isfirstLocation) {
LatLng currentLat = new LatLng(location.getLatitude(), location.getLongitude());
_googleMap.moveCamera(CameraUpdateFactory.newLatLng(currentLat));
_googleMap.moveCamera(CameraUpdateFactory.zoomTo(19));
isfirstLocation = false;
}
//if(mCallback != null)
mCallback.onUpdateLocation(location.getLatitude(),location.getLongitude());
}
/**
* Draw Bomb and update its view all the timeToRefresh milliseconds.
* #param timeToRefresh the time in milliseconds which the marker needs to refresh
* #param id the id of the current bomb we need to work with
*/
public void startDrawingBomb(final int timeToRefresh,final int id){
mustDrawCircle = true;
Log.v("JOSE","passe1");
final Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
while (mustDrawCircle) {
Log.v("JOSE","update bomb");
mCallback.updateBombs();
//Log.v("JOSE","bomb updated ?");
Thread.sleep(timeToRefresh);
// This method is called from the MainActivity
final CircleOptions circleOptions = mCallback.drawBombCircle(id);
final String idToCompare = getIdCircle(id);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
boolean isCenterSet = false;
if (circleOptions != null) {
Log.v("JOSE","size marker : " +markerArrayListBomb.size());
for(int i=0;i<markerArrayListBomb.size();i++){
Log.v("JOSE","Id to compare : " +idToCompare);
Log.v("JOSE","Id markearray : " +markerArrayListBomb.get(i).getId());
if((markerArrayListBomb.get(i).getId()).equals(idToCompare)){
// si c'est la même chose, il suffit de updater
markerArrayListBomb.get(i).setCenter(circleOptions.getCenter());
markerArrayListBomb.get(i).setVisible(true);
isCenterSet = true;
}
}
// il faut creer une nouvelle bombe
if(!isCenterSet) {
Circle newCircle = _googleMap.addCircle(circleOptions);
markerArrayListBomb.add(newCircle);
newIdCircle(id, newCircle.getId());
//Log.v("JOSE", "New bomb drawn id : " + newCircle.getId());
}
}
}
});
}
String idToCompare = getIdCircle(id);
for(int i=0;i<markerArrayListBomb.size();i++){
if((markerArrayListBomb.get(i).getId()).equals(idToCompare)){
final int index = i;
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
markerArrayListBomb.get(index).setVisible(false);
}
});
}
}
}
catch (InterruptedException e){
e.printStackTrace();
}
}
});
thread.start();
}
public void cancelDrawingBomb(){mustDrawCircle = false;}
// Container Activity must implement this interface
public interface OnMessageListener {
public void onUpdateLocation(double lat,double lon);
public void getAllOtherScoutsLocation();
public void updateBombs();
public CircleOptions drawBombCircle(int id);
}
/**
*
* #param id de la bombe dans la classe Bomb
* #return le cercle créé associé. Sinon, return null
*/
private String getIdCircle(int id){
if(idArray.size() == 0)
return null;
for(int i=0 ; i<idArray.size();i++){
if(idArray.get(i) == id)
return idToCircleId.get(i);
}
return null;
}
/**
* Si une bombe est supprimée, il faut appeler cette méthode
* #param id
*/
private void removeIdCircle(int id){
for(int i=0 ; i<idArray.size();i++){
if(idArray.get(i) == id) {
idToCircleId.remove(i);
idArray.remove(i);
}
}
}
/**
* A appeler à chaque fois u'une bombe est créée
* #param id l'id de la classe BOMB
* #param ids l'id créé grâce à la classe Circle de google
*/
private void newIdCircle(int id,String ids){
idToCircleId.add(ids);
idArray.add(id);
}
}
And this how I called the second time my MapsFragment :
if (id == R.id.map) {
if(fragmentManager.findFragmentByTag(MAPS_FRAGMENT) != null){
MapsFragment fragment = (MapsFragment)fragmentManager.findFragmentByTag(MAPS_FRAGMENT);
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment,MAPS_FRAGMENT).addToBackStack(MAPS_FRAGMENT).commit();
}
}
Thanks a lot everyone, and sorry for my bad English.
If you want more information, or a better explanation, don't hesitate to tell me !
Implement save to bundle functionality at Onpause() for your MapFragment. Then in onCreateView() always check your bundle.
If the bundle is empty then it's a new fragment. If the bundle is not empty this means it was previously created.
Hope this helps :
For saving and restoring to bundle : Saving Android Activity state using Save Instance State
Related
I'm using google map in my application ,when I click the marker info-window is opened again I want to click the info-window layout but its not working for layouts.If I give click listener for button means its working.Please help me to fix this issue.
Activity:
public class SampleFragment1 extends Fragment implements OnMapReadyCallback,GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener, LocationListener {
private ViewGroup infoWindow;
private TextView infoTitle;
private TextView infoSnippet,userNameTV,loggedLabel,userLastNameTV,time,distance,tasks;
private Button infoButton, infoButton2;
private OnInfoWindowElemTouchListener infoButtonListener;
LinearLayout markerlay;
GoogleMap mMap;
public void createLocationRequest() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
}
private MapView mapView;
private MarkerOptions mMarker;
MapWrapperLayout mapWrapperLayout;
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.con_fragment_google, container, false);
mapWrapperLayout = (MapWrapperLayout)view.findViewById(R.id.map_relative_layout);
mapView = (MapView)view. findViewById(R.id.mapView);
// getContext().startService(new Intent(getContext(),GPSTracker.class));
mapView.onCreate(savedInstanceState);
buildGoogleApiClient();
createLocationRequest();
mapView.getMapAsync(this);
return view;
}
private synchronized void buildGoogleApiClient() {
try {
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
// to get current latitude and longitude
// storing the updated latitde and longitude when user moving and reach destination
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mapWrapperLayout.init(mMap, getPixelsFromDp(getContext(), 39 + 20));
// We want to reuse the info window for all the markers,
// so let's create only one class member instance
this.infoWindow = (ViewGroup)getActivity().getLayoutInflater().inflate(R.layout.info_widow_layout, null);
this.infoTitle = (TextView)infoWindow.findViewById(R.id.nametv);
this.infoSnippet = (TextView)infoWindow.findViewById(R.id.addressTv);
this.infoButton = (Button)infoWindow.findViewById(R.id.clinicType);
// Setting custom OnTouchListener which deals with the pressed state
// so it shows up
this.infoButtonListener = new OnInfoWindowElemTouchListener(infoTitle
) //btn_default_pressed_holo_light
{
#Override
protected void onClickConfirmed(View v, Marker marker) {
// Here we can perform some action triggered after clicking the button
Toast.makeText(getContext(), marker.getTitle() + "'s button clicked!", Toast.LENGTH_SHORT).show();
}
};
this.infoTitle.setOnTouchListener(infoButtonListener);
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
// Setting up the infoWindow with current's marker info
infoTitle.setText(marker.getTitle());
infoSnippet.setText(marker.getSnippet());
infoButtonListener.setMarker(marker);
// We must call this to set the current marker and infoWindow references
// to the MapWrapperLayout
mapWrapperLayout.setMarkerWithInfoWindow(marker, infoWindow);
return infoWindow;
}
});
// Let's add a couple of markers
}
public static int getPixelsFromDp(Context context, float dp) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
}
Note:Here I give click listener for textview ,the textview present inside the layout.
I try to learn Android by myself. And in my app, I want to use fragment to show google map and when user open my app, I want to get current location by using GoogleApiClient
My fragment code:
public class HomeFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public interface comuticateParent {
public void sendMess(String text);
}
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public HomeFragment() {
// Required empty public constructor
}
public static HomeFragment newInstance(String param1, String param2) {
HomeFragment fragment = new HomeFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
comuticateParent callback;
Button btn1;
TextView textView;
MapView mMapView;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
LocationRequest mLocationRequest;
private GoogleMap googleMap;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
mMapView = (MapView) rootView.findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.onResume(); // needed to get the map to display immediately
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap mMap) {
googleMap = mMap;
googleMap.setMyLocationEnabled(true);
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Log.d("onCreateView", Boolean.toString(mGoogleApiClient.isConnected()));
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mylocation, 13));
}
});
return rootView;
}
#Override
public void onStart() {
mGoogleApiClient.connect();
Log.d("ConnectonStart", "Connected ");
Log.d("ONstart", Boolean.toString(mGoogleApiClient.isConnected()));
super.onStart();
}
#Override
public void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
#Override
public void onResume() {
mGoogleApiClient.connect();
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
#Override
public void onConnected(Bundle bundle) {
Log.d("Connect", "Connected ");
Log.d("onConnected", Boolean.toString(mGoogleApiClient.isConnected()));
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d("Connect", "failed ");
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
Activity activity;
if (context instanceof Activity) {
activity = (Activity) context;
callback = (comuticateParent) getActivity();
}
}
}
And problem here:
-Log in method onCreateView appears before log in method onconnected, so I can't get getLastLocation() because The googleAPIClient is not connect yet.
I have search in google but I don't know how to fix it.
Please help me!
Sorry about my best English.
First problem Log in method onCreateView appears before log in method onconnected, because GoogleApiClient will accessing Google APIs, verify app configuration, verify certificate fingerprint, etc. It take too long to process. To avoid blocking the UI thread, it'll execute in another thread and use asynchronous callback.
Second problem I can't get getLastLocation() because The googleAPIClient is not connect yet, because FusedLocationApi will only maintain background, so you need to get GoogleMap in background.
See my sample here: https://gist.github.com/quydm/a458d908c4da2496672f83372304f417
You will have to wait until the GoogleApiClient has connected before you can request location updates. In order to do so, you would move this block of code (currently found in your onCreateView() method):
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
Log.d("onCreateView", Boolean.toString(mGoogleApiClient.isConnected()));
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mylocation, 13));
to the body of the overridden method onConnected().
You cannot have this code directly in onCreateView() because of the very problem you had. The connection must be established first before any location requests are sent. The connection can establish quickly or take longer than normal. It depends on many things outside of your control.
For that reason, I would suggest showing some sort of progress bar to indicate that location services is connecting and then remove the progress bar when onConnected() is called. Of course this depends entirely on your app. If location services is critical for the user to have then this is a must, if not, then you may not need to add it.
I'm trying to pass current location of the device to my asynctask class to be used to filter out a list based on their distance before it is populated in my recyclerview. Anytime I run this code I get an empty list and my current location is null. Am I doing something wrong? It works only when I manually enter location co-ordinates.
This are the permissions in my manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.example.kwao.roninsnradars.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
This contains my Fragment and My AsyncTask Class:
public class MyListFragment extends Fragment implements SearchView.OnQueryTextListener,GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener{
// TODO: Rename parameter arguments, choose names that match
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private static final String ARG_PARAM3 = "param3";
private int mParam1;
private List<Data> totalData = new ArrayList<>();
private BackendlessCollection<Data> Data;
private MyRecyclerAdapter adapter;
private View view;
public RecyclerView recyclerView;
RecyclerView.LayoutManager gridLayoutManager, linearLayoutManager;
private ProgressDialog progressDialog;
private SwipeRefreshLayout swipeRefreshLayout;
private MyRecyclerAdapter.OnListFragmentInteractionListener mListener;
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationRequest locationRequest;
private Double mLatitude;
private Double mLongitude;
public MyListFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #return A new instance of fragment MyListFragment.
*/
// TODO: Rename and change types and number of parameters
public static MyListFragment newInstance(int param1) {
MyListFragment fragment = new MyListFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
//args.putDouble(ARG_PARAM2, param2);
//args.putDouble(ARG_PARAM3, param3);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null)
parent.removeView(view);
}
// Defining Linear Layout Manager
linearLayoutManager = new LinearLayoutManager(getContext());
view = inflater.inflate(R.layout.Data_fragment_list_view, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(linearLayoutManager);
try {
Data = new FindDataAndPopulate(mLatitude,mLongitude).execute().get(30, TimeUnit.SECONDS);
} catch ( CancellationException | ExecutionException | InterruptedException | TimeoutException e ){
Toast.makeText( getActivity(), "Failed to load Data: " + e.getMessage(), Toast.LENGTH_LONG ).show();
}
swipeRefreshLayout = (SwipeRefreshLayout)view.findViewById(R.id.refresh_layout);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
clear();
try {
Data = new FindDataAndPopulate(mLatitude,mLongitude).execute().get(30, TimeUnit.SECONDS);
} catch (CancellationException | ExecutionException | InterruptedException | TimeoutException e) {
Toast.makeText(getActivity(), "Failed to load Data: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
refreshItems();
}
});
mGoogleApiClient = new GoogleApiClient.Builder(getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
return view;
}
public void clear() {
totalData.clear();
adapter.notifyDataSetChanged();
}
private void addMore(BackendlessCollection<Data> next) {
totalData.addAll(next.getCurrentPage());
adapter.notifyDataSetChanged();
}
private void refreshItems() {
onItemsLoadComplete();
}
void onItemsLoadComplete() {
adapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
inflater.inflate(R.menu.main_page, menu);
final MenuItem item = menu.findItem(R.id.search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setQueryHint("Search Data Around You");
searchView.setOnQueryTextListener(this);
MenuItemCompat.setOnActionExpandListener(item,new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
adapter.setFilter(totalData);
return true;
}
});
}
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
final List<Data> filteredRoninList = filter(totalData, newText);
adapter.setFilter(filteredRoninList);
return true;
}
private List<Data> filter(List<Data> areaData, String query) {
query = query.toLowerCase();
final List<Data> filteredDataList = new ArrayList<>();
for (Data ronin : areaData) {
final String text = ronin.getRoninName().toLowerCase();
if (text.contains(query)) {
filteredDataList.add(ronin);
}
}
return filteredDataList;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof MyRecyclerAdapter.OnListFragmentInteractionListener) {
mListener = (MyRecyclerAdapter.OnListFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
#Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
public void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(getContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLocation != null) {
mLatitude = mLocation.getLatitude();
mLongitude = mLocation.getLongitude();
} else {
Toast.makeText(getContext(), "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i("Pius", "Connection Suspended");
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i("Pius", "Connection failed. Error: " + connectionResult.getErrorCode());
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public class FindDataAndPopulate extends AsyncTask<Void, Void,BackendlessCollection<Data>>
{
Double myLatitude;
Double myLongitude;
public FindDataAndPopulate(Double myLatitude,Double myLongitude){
this.myLatitude = myLatitude;
this.myLongitude = myLongitude;
}
private Context context ;
#Override
protected BackendlessCollection<Data> doInBackground(Void... params) {
String query = "distance( %f, %f, location.latitude, location.longitude ) < mi(5) = true";
String whereClause = String.format( query, mLatitude, mLongitude );
BackendlessDataQuery dataQuery = new BackendlessDataQuery( whereClause );
QueryOptions queryOptions = new QueryOptions();
queryOptions.addRelated( "location" );
dataQuery.setQueryOptions( queryOptions );
Data = Backendless.Data.of(Data.class ).find(dataQuery);
return Data;
}
#Override
protected void onPreExecute() {
// progressDialog = ProgressDialog.show(context, "", "Loading...", true);
}
#Override
protected void onPostExecute(BackendlessCollection<Data> DataBackendlessCollection) {
Data = DataBackendlessCollection;
adapter = new MyRecyclerAdapter(getContext(),totalData, mListener);
recyclerView.setAdapter(adapter);
addMore(Data);
}
};
}
The problem is here :
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
getLastLocation() will not return any result immediately if location was not enabled in settings. That's why you should never rely on getLastKnownLocation() for getting recent location.
What you can do is : If location returns null - you need to create a LocationRequest and check for location settings. If location is enabled in settings, you need to call requestLocationUpdates with some interval. once you get the latest location in onLocationUpdated, stop the location updates and do whatever you want with that location.
Another thing to notice : Do not use nested classes for Asynctask as they can easily create memory leaks.
I have the following class:
...
public class FragmentMapa extends Fragment {
/*
* Atributos
*/
private static String LOG_TAG = "FragmentMapa";
private HomeActivity homeActivity;
private GoogleMap mMapa;
private DrawerLayout mDrawer;
private ActionBarDrawerToggle mDrawerToggle;
private ListView mDrawerList;
private ListView mDrawerRightList;
private RelativeLayout mDrawerRelativeLayout;
private String[] mRightDrawerMenuTitles;
private ImageView mDiputacionLogo;
private IncidenciasFetchAsyncTask mFetchIncidenciasTask;
private Incidencias mIs;
private CamarasFetchAsyncTask mFetchCamarasTask;
private Camaras mCams;
private ViabilidadesInvernalesFetchAsyncTask mFetchViabilidadesInvernalesTask;
private ViabilidadesInvernales mVis;
private static LatLng POS_CENTRAL = new LatLng(43.243968,-2.896957);
private static LatLng limiteSurOesteBizkaia = new LatLng(42.895853,-3.594589);
private static LatLng limiteNorEsteBizkaia = new LatLng(43.540351,-2.180099);
private static final LatLngBounds BOUNDS = new LatLngBounds(limiteSurOesteBizkaia, limiteNorEsteBizkaia);
private ArrayList<Marker> markersIncidencias = new ArrayList<Marker>();
private ArrayList<Marker> markersObras = new ArrayList<Marker>();
private ArrayList<Marker> markersCamaras = new ArrayList<Marker>();
private ArrayList<Marker> markersViabilidadInvernal = new ArrayList<Marker>();
/*
* Métodos
*/
public FragmentMapa() {
}
#Override
public void onAttach (Activity activity) {
super.onAttach(activity);
homeActivity = (HomeActivity) activity;
mRightDrawerMenuTitles = getResources().getStringArray(R.array.mapa_submenu_options);
mDrawer = homeActivity.getmDrawer();
mDrawerRightList = homeActivity.getmDrawerRightList();
mDrawerRightList.setAdapter(new ArrayAdapter<String>(
homeActivity.getSupportActionBar().getThemedContext(),
R.layout.rightdrawer_map_list_item,
mRightDrawerMenuTitles
));
mDrawerRightList.setOnItemClickListener(new DrawerItemClickListener());
}
#Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.mapa, container, false);
setupMapIfNeeded();
return rootView;
}
private void setupMapIfNeeded() {
if( mMapa == null ){
SupportMapFragment smf = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mapaPrincipal);
if( smf != null ){
//Toast.makeText(getActivity(), "VAAAMOOSS", Toast.LENGTH_SHORT).show();
mMapa = smf.getMap();
}/*else{
Toast.makeText(getActivity(), "smf es null...", Toast.LENGTH_SHORT).show();
}*/
if( mMapa != null ){
setupMap();
}
}
}
private void setupMap() {
//Toast.makeText(getActivity(), "A configurar el mapa!!", Toast.LENGTH_SHORT).show();
CameraPosition camPos;
camPos = new CameraPosition.Builder()
.target(POS_CENTRAL)
.zoom((float) 9.5)
.build();
final CameraUpdate camUpd =
CameraUpdateFactory.newCameraPosition(camPos);
mMapa.animateCamera(camUpd);
mMapa.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition newPos) {
float maxZoom = 17.0f;
if( !BOUNDS.contains(newPos.target) ){
//Mover la cámara al centro si se
//va más allá de los límites
mMapa.animateCamera(camUpd);
}
if(newPos.zoom > maxZoom){
mMapa.animateCamera(CameraUpdateFactory.zoomTo(maxZoom));
}
}
});
mMapa.setOnInfoWindowClickListener( new OnInfoWindowClickListener(){
public void onInfoWindowClick(Marker aMarker) {
Toast.makeText(getActivity(), "info window pulsado", Toast.LENGTH_SHORT).show();
if( markersCamaras.contains(aMarker) ){
Camara c = mCams.getCamaraByCoord(aMarker.getPosition());
homeActivity.showCameraFragment(c);
}
}
});
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onViewStateRestored (Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
}
#Override
public void onStart () {
super.onStart();
}
#Override
public void onResume () {
super.onResume();
}
#Override
public void onPause () {
super.onPause();
}
#Override
public void onStop () {
super.onStop();
}
#Override
public void onDestroyView () {
super.onDestroyView();
}
#Override
public void onDestroy () {
super.onDestroy();
}
#Override
public void onDetach () {
super.onDetach();
}
/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final int thePos = position;
mDrawer.setDrawerListener( new DrawerLayout.SimpleDrawerListener(){
#Override
public void onDrawerClosed(View drawerView) {
boolean wasChecked = !mDrawerRightList.isItemChecked(thePos);
//Toast.makeText(homeActivity, "Item pulsado: " + wasChecked, Toast.LENGTH_SHORT).show();
mDrawerRightList.setItemChecked(thePos, !wasChecked);
switch (thePos) {
case 0:
//Incidencias
//Toast.makeText(homeActivity, "Incidencias", Toast.LENGTH_SHORT).show();
if(!wasChecked){
//Toast.makeText(homeActivity, "Incidencias estaba sin pulsar", Toast.LENGTH_SHORT).show();
getIncidenciasObras();
introducirIncidencias();
}else{
//Toast.makeText(homeActivity, "Incidencias estaba pulsado", Toast.LENGTH_SHORT).show();
removeIncidenciasMarkers();
}
break;
case 1:
//Obras
//Toast.makeText(homeActivity, "Obras", Toast.LENGTH_SHORT).show();
if(!wasChecked){
//Toast.makeText(homeActivity, "Obras estaba sin pulsar", Toast.LENGTH_SHORT).show();
getIncidenciasObras();
introducirObras();
}else{
//Toast.makeText(homeActivity, "Obras estaba pulsado", Toast.LENGTH_SHORT).show();
removeObrasMarkers();
}
break;
case 2:
//Cámaras
//Toast.makeText(homeActivity, "Cámaras", Toast.LENGTH_SHORT).show();
if(!wasChecked) {
getCamaras();
introducirCamaras();
}else
removeCamarasMarkers();
break;
case 3:
//Viabilidad invernal
//Toast.makeText(homeActivity, "Viabilidad invernal", Toast.LENGTH_SHORT).show();
if(!wasChecked){
getViabilidadesInvernales();
introducirViabilidadInvernal();
}else
removeViabilidadInvernalMarkers();
break;
default:
//Toast.makeText(homeActivity, "Default", Toast.LENGTH_SHORT).show();
break;
}
}
});
if(mDrawer.isDrawerOpen(Gravity.END))
mDrawer.closeDrawer(mDrawerRightList);
}
}
private void getViabilidadesInvernales(){
mVis = ViabilidadesInvernales.getInstance();
if(mVis.isEmptyViabilidadesInvernales()){
mFetchViabilidadesInvernalesTask = new ViabilidadesInvernalesFetchAsyncTask(homeActivity);
try {
mVis = mFetchViabilidadesInvernalesTask.execute("es").get();
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Error InterruptedException: " + e.getMessage());
e.printStackTrace();
} catch (ExecutionException e) {
Log.e(LOG_TAG, "Error ExecutionException: " + e.getMessage());
e.printStackTrace();
}
}
}
...
private void introducirViabilidadInvernal() {
if(markersViabilidadInvernal.isEmpty()){
Marker aMarker;
for (ViabilidadInvernal vi : mVis.getViabilidades()) {
String estado = "";
BitmapDescriptor icon;
if(vi.getEstado() == PuertoEstado.ABIERTO){
estado = getResources().getString(R.string.mapa_puerto_abierto);
icon = BitmapDescriptorFactory.fromResource(R.drawable.marker_puertoabierto);
}else{
//vi.getEstado() == PuertoEstado.CERRADO
estado = getResources().getString(R.string.mapa_puerto_cerrado);
icon = BitmapDescriptorFactory.fromResource(R.drawable.marker_puertocerrado);
}
aMarker = mMapa.addMarker(new MarkerOptions()
.position(vi.getCoord())
.title(vi.getT())
.snippet(estado)
.icon(icon));
markersViabilidadInvernal.add(aMarker);
}
}
}
private void removeViabilidadInvernalMarkers() {
for(Marker aMarker : markersViabilidadInvernal){
aMarker.remove();
}
}
...
private class ViabilidadesInvernalesFetchAsyncTask extends AsyncTask<String, Void, ViabilidadesInvernales>{
private ProgressDialog mPd;
private HomeActivity ownerActivity;
private Context context;
private Exception exceptionToBeThrown;
public ViabilidadesInvernalesFetchAsyncTask(Activity activity){
this.ownerActivity = (HomeActivity) activity;
context = activity;
this.exceptionToBeThrown = null;
mPd = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mPd.setTitle("cargando");
mPd.setMessage("miralo");
//mPd.setTitle(getResources().getString(R.string.mapa_cargando_titulo));
//mPd.setMessage(getResources().getString(R.string.mapa_cargando, getResources().getString(R.string.mapa_cargando_elemento_viabilidad)));
mPd.setCancelable(false);
mPd.setIndeterminate(true);
mPd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mPd.show();
}
#Override
protected ViabilidadesInvernales doInBackground(String... params) {
String idioma = params[0];
if(!idioma.equalsIgnoreCase("es") && !idioma.equalsIgnoreCase("eu")){
idioma = "es";
}
SystemClock.sleep(5000);
ViabilidadesInvernalesParser vip = new ViabilidadesInvernalesParser();
ViabilidadesInvernales lasViabilidades = vip.parse(idioma);
Log.d(LOG_TAG, lasViabilidades.toString());
ViabilidadesInvernales vis = ViabilidadesInvernales.getInstance();
return vis;
}
#Override
protected void onPostExecute(ViabilidadesInvernales vis) {
super.onPostExecute(vis);
mVis = vis;
if(mPd != null){
mPd.dismiss();
}
// Check if exception exists.
//if (exceptionToBeThrown != null) {
//TODO
//ownerActivity.handleXXX();
//throw exceptionToBeThrown;
//}
}
}
....
}
The aim is to show a Dialog (ProgressDialog) when an AsyncTask is executed, so that the Dialog remains in front of the UI for a moment and then, the map (which was being shown previously) returns to the front. More exactly, you launch the application (home activity), you open the left drawer, press Mapa and go to the current fragment. An empty map is shown. You open the right drawer and press a button. Just afterwards, the process of launching AsyncTask is executed (and my desired ProgressDialog).
I don't know why, but the ProgressDialog is not being shown, but I have realised that the "sleep" process is ok (and the AsyncTask is executed properly every time).
Can anybody lend me a hand?
PS: My main activity (HomeActivity) launches fragments. The main activity has two drawers: left drawer is always visible, and right drawer is only visible when launching the FragmentMapa (the fragment I'm showing you right now). Might this issue be due to the Drawer behaviour?
THANK YOU SO MUCH
SOLVED. Anyone who faces this problem, check the following post: https://stackoverflow.com/a/3291713/828551.
You must create an interface, create an instance of it within the AsyncTask and implement the interface the main class where you launch the AsyncTask.
I have a strange problem with a com.google.android.gms.maps.MapView.
To check if my App crashes after the garbage collector is doing his job i force my HTC One (4.2.2) to allow only 1 running app in background. If I leave my app(home button) while showing a MapView, start any other app and resume to my app, my MapView is still showing up...but I can not move or zoom the map, it's not responding at all. Other activities are working fine. I really have no clue where the problem might be.
Hope that someone can help me out?
Here is the sourcecode of my fragment that shows the MapView
public class FragmentAdvertlistMap extends Fragment {
com.google.android.gms.maps.MapView m;
GoogleMap mMap;
ArrayList<Advert> ads;
HashMap<Marker, String> myMarker;
public final LatLngBounds.Builder builder= new LatLngBounds.Builder();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
try {
MapsInitializer.initialize(getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
// TODO handle this situation
}
View inflatedView = inflater.inflate(R.layout.activity_advert_tab2, container, false);
m = (com.google.android.gms.maps.MapView)inflatedView.findViewById(R.id.map_tab);
m.onCreate(savedInstanceState);
myMarker = new HashMap<Marker, String>();
ads= AdvertListActivity.getAdverts();
setUpMapIfNeeded(inflatedView);
mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker arg0) {
Intent myIntent = new Intent(getActivity(), AdvertLocationActivity.class);
Advert putadvert = DefaultApplication.dbc.getAdvertForAdvertID(Integer.parseInt(myMarker.get(arg0)));
myIntent.putExtra("advert", putadvert);
startActivity(myIntent);
}
});
return inflatedView;
}
private void setUpMapIfNeeded(View inflatedView) {
if (mMap == null) {
mMap = ((com.google.android.gms.maps.MapView) inflatedView.findViewById(R.id.map_tab)).getMap();
if (mMap != null) {
this.initMarker();
}
}
}
public void initMarker(){
for(int i=0;i<ads.size();i++){
Advert tempAd = ads.get(i);
LatLng tlalo = new LatLng(tempAd.mainLocation.latitude,tempAd.mainLocation.longitude);
builder.include(tlalo);
String address = "";
if(tempAd.mainLocation.contact_street != null){
address = address + tempAd.mainLocation.contact_street;
}
if(tempAd.mainLocation.contact_street_number != null){
address = address + " " + tempAd.mainLocation.contact_street_number;
}
Marker marker = mMap.addMarker(new MarkerOptions()
.position(tlalo)
.anchor(0.5f, 0.5f)
.title(tempAd.name)
.snippet(address)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.androidpin)));
myMarker.put(marker,String.valueOf(tempAd.myid));
}
mMap.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition arg0) {
mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 100));
mMap.setOnCameraChangeListener(null);
}
});
}
#Override
public void onResume() {
super.onResume();
m.onResume();
}
#Override
public void onPause() {
super.onPause();
m.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
m.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
m.onLowMemory();
}
}
try add this in onCreateView()
container.removeAllViews();
I found it in another similar question to yours but I lost the original link of the answer...