Activity automatically refreshes after saving coordinates on Firebase? - android

In my code, I am getting the user's location using FusedLocationProviderClient. In the callback, I am saving the latitude and longitude of the user on Firebase real time database. Everything works fine even when the user moves from one place to another, the only problem is, every time it saves the coordinates on Firebase, the activity refreshes, how do I stop this automatic refreshing?
I am posting only the onCreate method and the call back method, if more code is needed, I will provide it.
Everything is working fine in my code except the activity refreshes every time new coordinates are saved on Firebase?
Note: My code is in a Fragment
private static final String TAG = "DriverMapFragment";
int LOCATION_REQUEST_CODE = 10001;
FusedLocationProviderClient fusedLocationProviderClient;
LocationRequest locationRequest;
double latitude,longitude;
DatabaseReference databaseReference;
String schoolName, driverPhone, vehicleNumberPlate;
TextView newLat,newLng;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_driver_map, container, false);
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity());
locationRequest = LocationRequest.create();
locationRequest.setInterval(4000);
locationRequest.setFastestInterval(2000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
databaseReference = FirebaseDatabase.getInstance().getReference();
Intent intent = getActivity().getIntent();
schoolName = intent.getStringExtra("SchoolName");
driverPhone = intent.getStringExtra("DriverPhone");
vehicleNumberPlate = intent.getStringExtra("VehicleNumberPlate");
newLat = view.findViewById(R.id.newLat);
newLng = view.findViewById(R.id.newLng);
return view;
}
LocationCallback locationCallback = new LocationCallback(){
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null){
return;
}
for (Location location : locationResult.getLocations()){
Log.d(TAG,"onLocationResult: " + location.toString());
latitude = location.getLatitude();
longitude = location.getLongitude();
Log.i("Lat",String.valueOf(latitude));
Log.i("Lng",String.valueOf(longitude));
LocationHelper helper = new LocationHelper(
location.getLongitude(),
location.getLatitude()
);
FirebaseDatabase.getInstance().getReference().child("Schools")
.child(schoolName)
.child("drivers")
.child(vehicleNumberPlate)
.child("driverLocation")
.setValue(helper).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Log.i("Success","Location Saved");
}
else{
Log.i("Failure","Location Not Saved");
}
}
});
}
}
};

Make sure you use addListenerForSingleValueEvent instead of addValueEventListener, otherwise when you update data to Firebase, addValueEventListener will be called again and run the Activity you called in.

Related

Android – java, send location-data from a class toward and activity-view

please help me with this, I´m working with android studio – java. I have an Activity(MainActivity) where I want to show the information about location; but I want this information come from other class(Location) toward this MainActivity, how can I make this location class send the location data automatically.
Well, I had try to call the method in MainActivity where I get the location data from class-location, but this methods has parameters “Location location”, so I can’t call it directly.
And I had try put a method inside the “location method” to send the information, but It doesn’t work
I declare the location variables global and put It in other method to send them but doesn’t’ work
I´m trying using the location information (latitude and longitude) from a class using extra, but how can get the data.
Anyway… please help me, the Idea is pass the location information: “getLatitude()”and “getLongitude()” for a class to my MainActivity automatically and to a DDBB later.
So much thank for any help
this is "the MainActivity" class
public class MainActivity extends AppCompatActivity {
TextView tvlatitud, tvlongitud;
Location location;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvlongitud = findViewById(R.id.tv_longitud);
tvlatitud = findViewById(R.id.tv_latitud);
location = new Location(this);
askLocation();
}
public void askLocation(){
location.updateGPS();
}
public void showData(String lat, String lon ){
tvlatitud.setText(lat);
tvlongitud.setText(lon);
}
and this is the Location class
public class Location extends AppCompatActivity {
private static final int PERMISSIONS_FINE_LOCATION = 99;
FusedLocationProviderClient fusedLocationProviderClient;
LocationRequest locationRequest;
String latitude1, longitude1;
private MainActivity mainActivity;
public Location(MainActivity mainActivity){
this.mainActivity = mainActivity;
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
locationRequest = new LocationRequest();
locationRequest.setInterval(1000 * 30);
locationRequest.setFastestInterval(1000 * 50);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
updateGPS();
}
public void updateGPS() {
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(Location.this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocationProviderClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<android.location.Location>() {
#Override
public void onSuccess(android.location.Location location) {
updateUIValues(location);
mainActivity.showData(latitude1, longitude1);
}
});
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,}, PERMISSIONS_FINE_LOCATION);
}
}
}
private void updateUIValues(android.location.Location location) {
latitude1 = String.valueOf(location.getLatitude());
longitude1 = String.valueOf(location.getLongitude());
}
}

Application crashes when loading a GeoFire query into RecyclerView

I am developing a location based chat application as a final assignment, but have one bug that I cannot figure out how to fix by myself. Currently, I intend to load all profiles within a certain radius into a recyclerview, and display only these profiles to the current user.
The recycler view is working fine and displays every user in my Firebase database, until I add the GeoFire query to limit the users that appear only to those within the 2km radius. All user latitudes and longitudes are being updated successfully to the database, so I don't think that this is where the problem originates.
When i run the app and it crashes, I get this exception in the LogCat:
"java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference"
This is confusing me, as none of the current users in my database have a null value stored for either their longitude or latitude.
So my main question is, how can I get only the users within 2km of the current user to populate my recyclerview, without the application crashing?
Database structure
The current source code:
public class FindChatters extends Fragment {
private RecyclerView mUsersList;
private View mMainView;
private DatabaseReference mUsersDatabase;
private FirebaseUser mCurrentUser;
private LatLng myCurrentLocation;
private String mUserFound;
private static final int RADIUS = 2;
Location mLastLocation;
public FindChatters() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
mMainView = inflater.inflate(R.layout.fragment_find_chatters, container, false);
mUsersDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
mCurrentUser = FirebaseAuth.getInstance().getCurrentUser();
mUsersList = (RecyclerView) mMainView.findViewById(R.id.users_list);
mUsersList.setHasFixedSize(true);
mUsersList.setLayoutManager(new LinearLayoutManager(getContext()));
return mMainView;
}
//RETRIEVE DATA IN REALTIME
#Override
public void onStart() {
super.onStart();
startListening();
}
public void startListening() {
Query query = FirebaseDatabase.getInstance().getReference().child("Users").limitToLast(50);
FirebaseRecyclerOptions<Users> options = new FirebaseRecyclerOptions.Builder<Users>().setQuery(query, Users.class).build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Users, UserViewHolder>(options) {
#Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// CREATE NEW INSTANCE OF VIEWHOLDER, USING CUSTOM LAYOUT (R.LAYOUT.MESSAGE)
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.users_single_layout, parent, false);
return new UserViewHolder(view);
}
#Override
protected void onBindViewHolder(final UserViewHolder holder, final int position, final Users model) {
// // //
//RETRIEVE CURRENT USERS LAT/LONG TO FIND USERS NEARBY
String userID = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference myLoc = FirebaseDatabase.getInstance().getReference().child("Geo");
final GeoFire geoFire = new GeoFire(myLoc);
geoFire.setLocation(userID, new GeoLocation(mLastLocation.getLatitude(), mLastLocation.getLongitude()));
myCurrentLocation = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());
//RETRIEVE USERS ONLY FROM WITHIN A SPECIFIED RADIUS TO THE CURRENT USER
DatabaseReference findNearby = FirebaseDatabase.getInstance().getReference().child("Geo");
GeoFire geoFire2 = new GeoFire(findNearby);
//QUERY ALL NEARBY USERS IN THE DATABASE WITHIN 2KM OF CURRENT USER LAT/LONG
final GeoQuery geoQuery = geoFire2.queryAtLocation(new GeoLocation(myCurrentLocation.latitude, myCurrentLocation.longitude), RADIUS);
//QUERY TO RETRIEVE CLOSET USERS
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
//IF ANY USERS FOUND WITHIN RADIUS - ON KEY ENTERED IS CALLED
#Override
public void onKeyEntered(String key, GeoLocation location) {
if (geoQuery != null) {
mUserFound = key;
//BIND CHAT OBJECT TO CHATHOLDER
holder.setName(model.name);
holder.setUserStatus(model.status);
holder.setUserOnline(model.online);
holder.setUserImage(getContext(), model.image);
//CLICK ON A USER PROFILE TO ACCESS THEIR INFORMATION OR INITIATE CHAT
final String user_id = getRef(position).getKey();
//RETRIEVE CURRENT USER ID
String current_uid = mCurrentUser.getUid();
//PREVENT USER FROM BEING ABLE TO INITIATE A CONVERSATION WITH THEMSELF
if (!user_id.equals(current_uid)) {
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent profileIntent = new Intent(getActivity(), ProfileActivity.class);
profileIntent.putExtra("user_id", user_id);
startActivity(profileIntent);
}
});
} else {
holder.setName("You");
holder.setUserStatus("Tap someone to say hello!");
}
} else {
//CREATE TEXTVIEW TO INFORM USER THAT NO NEARBY USERS ARE PRESENT
}
}
#Override
public void onKeyExited(String key) {
}
#Override
public void onKeyMoved(String key, GeoLocation location) {
}
#Override
public void onGeoQueryReady() {
}
#Override
public void onGeoQueryError(DatabaseError error) {
}
});
// // //
}
};
mUsersList.setAdapter(adapter);
adapter.startListening();
}
I am still pretty new to coding, so I really appreciate any replies or help. Thanks!
Android Studio v3.1.3
Make sure you initialise mLastLocation. I can see that you are retrieving lat and lng from it but was never initialised

Android application modular design

This is more of a android design question. I am building an application that is going to consist of features such as P2P Connection, Location Receiving/Updates and a few others.
My applications current design is an activity consisting of two fragments in a viewpager and under a toolbar.
My first approach was to write different features all in separate classes (E.g Location receiver in its own class, a Google map generator in another) and then instantiate these objects where I needed them. I started to realize that that method wasn't working.
An idea I had was to implement everything I need in my fragments "onCreateView()" method but that just seems disorderly.
My question is where exactly do we implement certain features?
Here is an example of the fragment consisting of a map.
public class MapFragment extends Fragment implements OnMapReadyCallback{
SupportMapFragment mSupportMapFragment;
int radius = 20;
double mLatitude;
double mLongitude;
public double getLatitude() {
return mLatitude;
}
public double getLongitude() {
return mLongitude;
}
private GoogleMap maps;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mSupportMapFragment = SupportMapFragment.newInstance();
android.support.v4.app.FragmentManager sfm = getFragmentManager();
mSupportMapFragment.getMapAsync(this);
if(!mSupportMapFragment.isAdded())
sfm.beginTransaction().add(R.id.map_frag,mSupportMapFragment).commit();
else if(mSupportMapFragment.isAdded())
sfm.beginTransaction().hide(mSupportMapFragment).commit();
else
sfm.beginTransaction().show(mSupportMapFragment).commit();
LocationManager mLocationManager;
LocationListener mLocationListener;
mLocationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
if (location != null) {
/*
Updates to our map may need to be taken place here. Need to listen to other devices in the area.
*/
Log.e("Latitude: ", "" + location.getLatitude());
Log.e("Longitude: ", "" + location.getLongitude());
maps.clear(); //Clear the map of any existing markers
mLatitude = location.getLatitude();//Get coordinates stored into local variables
mLongitude = location.getLongitude();
LatLng latLng = new LatLng(mLatitude,mLongitude);//Create a "LatLng" object consisting of these coordinates
MarkerOptions mp1 = new MarkerOptions();//Instantiate a new "MarkerOptions" where we will be able to define a...
//...marker
mp1.position(new LatLng(location.getLatitude(),//Customizing marker...
location.getLongitude()));
mp1.title("You");
maps.addMarker(mp1);//Finally add the marker to the map
maps.moveCamera(CameraUpdateFactory.newLatLng(latLng));//Move camera to markers location using our "latLng" variable
maps.animateCamera(CameraUpdateFactory.zoomTo(20));// Zoom, (between 2.0 - 21.0) the higher, the more zoomed in
}
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
};
mLocationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,120000,radius,mLocationListener);
return inflater.inflate(R.layout.fragment_map, container, false);
}
#Override
public void onMapReady(GoogleMap map) {
maps = map;
}
}
In this fragment alone I have established location updates and a google map API. Everything seems to be working so far.
My only concern is the design.
Is cramming all these features (and more to come) in a single fragment considered bad practice?

In fragment dont get the Latitude and longitude

i have a problem with my code, in a fragment i have this code:
public class Logo extends Fragment implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {
LocationManager lm;
Location mLastLocation;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private Location mCurrentLocation;
private TextView Lat;
private TextView Long;
String provider;
public Logo() {
}
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static Logo newInstance() {
Logo fragment = new Logo();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
lm = (LocationManager)getActivity().getSystemService(Context.LOCATION_SERVICE);
View view = inflater.inflate(R.layout.fragment_main, container, false);
Lat = (TextView) view.findViewById(R.id.Latitude);
Long = (TextView) view.findViewById(R.id.Longitude);
TextView Morad = (TextView) view.findViewById(R.id.Morada);
Criteria c=new Criteria();
provider=lm.getBestProvider(c, false);
mLastLocation=lm.getLastKnownLocation(provider);
Lat.setText("A obter");
Long.setText(" dados");
Morad.setText("Aguarde...");
if(mLastLocation!=null)
{
Lat.setText(String.valueOf(mLastLocation.getLatitude()));
Long.setText(String.valueOf(mLastLocation.getLongitude()));
}
else
{
Lat.setText("No connection");
Long.setText(" wait");
}
return view;
}
#Override
public void onConnected(Bundle bundle) {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
Lat.setText(String.valueOf(mLastLocation.getLatitude()));
Long.setText(String.valueOf(mLastLocation.getLongitude()));
}
}
But never get the Lat and Longitude values, what i missed up.
I only want to return the Latitude and Longitude values and put in the 2 filds.
you need to decide if you are going to use the built in LocationManager or google play services Location APi because you are trying to use both and that will not work.
if you are trying to use the built in one then you never get a location because you dont have a last location and you never request location updates.
if you are trying to use the google play services location API well you need to do more work because you didnt really even implement it. I guess really in both cases you still have more work because you really didnt implement either correctly

How to supply location services to diffent activities on Android

I am currently working on an Android app and I am new to the field.
I want to do the following:
Create a class that encapsulates the required features to let an activity know the users location and deliver a map to the activity
This should accomplish the following:
I have a class that connects to the location services to get information and other activities can use this class to get a map (fragment) along with other information (lat long etc) for programmatic use.
I cannot figure it out...I do not want my stuff to an Activity itself
But it seems as if the whole Google Location API of the Play services relies on it being a FragmentActivity (whatever that is)
Any ideas?
PS: I need to maintain support for 2.3.3
UPDATE
I made it to implement a class extending SupportMapFragment (shortened), but I am having trouble with the error handling for the GMS. Works fine on my Galaxy Note 3 but the emulator has an older version of GMS which (due to currently crappy errorhandling) eventually leads to a NullPointer Exception:
public class LocationFragment extends SupportMapFragment implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
view = inflater.inflate(R.layout.map_fragment, container, false);
initilizeMap();
configureLocationClient();
locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
// Start with updates turned off
updatesRequested = false;
map.getUiSettings().setMyLocationButtonEnabled(true);
locationClient = new LocationClient(activity.getBaseContext(), this, this);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = getActivity();
checkGooglePlayServices();
}
private boolean checkGooglePlayServices() {
// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity.getBaseContext());
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
Log.d(TAG + ".servicesConnected()", "Google Play services is available.");
// Continue
return true;
// Google Play services was not available for some reason
} else {
Log.d(TAG + ".servicesConnected()", "Google Play services is unavailable or outdated: " + resultCode);
// Get the error dialog from Google Play services
try {
GooglePlayServicesUtil.getErrorDialog(resultCode, activity, CONNECTION_FAILURE_RESOLUTION_REQUEST).show();
} catch (Exception e) {
Log.e("Error: GooglePlayServiceUtil: ", "" + e);
}
/**
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(resultCode, activity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
// If Google Play services can provide an error dialog
if (errorDialog != null) {
// Create a new DialogFragment for the error dialog
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(activity.getSupportFragmentManager(),"Location Updates");
}*/
return false;
}
}
The corresponding Activity is:
public class LocationTest extends FragmentActivity implements LocationListener {
private static final String TAG = LocationTest.class.getSimpleName();
private int count = 0;
private TextView lat;
private TextView lng;
private TextView quality;
private TextView conState;
private TextView refreshCount;
private TextView distance;
private LocationFragment locFrag;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.locationtest);
FragmentManager fManager = getSupportFragmentManager();
locFrag = new LocationFragment();
FragmentTransaction ft = fManager.beginTransaction();
ft.replace(R.id.map, locFrag);
ft.addToBackStack(null);
ft.commit();
locFrag.setGoal(Double.valueOf(8.83749747285), Double.valueOf(53.0663656578));
lat = (TextView) findViewById(R.id.curLat);
lng = (TextView) findViewById(R.id.curLng);
quality = (TextView) findViewById(R.id.curQuality);
conState = (TextView) findViewById(R.id.conState);
refreshCount = (TextView) findViewById(R.id.count);
distance = (TextView) findViewById(R.id.distance);
}
public void refreshLocation(View v) {
locFrag.refreshLocation(v);
}
public void toggleUpdates(View v) {
locFrag.toggleUpdates(v);
}
public void onLocationChanged(Location location) {
// Let the location parent know about the location change
// super.onLocationChanged(location);
count++;
lat.setText(Double.toString(locFrag.getCurrentLatitude()));
lng.setText(Double.toString(locFrag.getCurrentLongitude()));
quality.setText(Float.toString(locFrag.getAccuracy()));
conState.setText(Boolean.toString(locFrag.isConnected()));
refreshCount.setText(Integer.toString(count));
distance.setText(Float.toString(locFrag.getDistance()));
}
#Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart()");
}
#Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause()");
}
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop()");
}
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume()");
}
}
I wonder if it is possible to get the ErrorDialog suggested by google to work from that SupportMapFragment to be able to handle the error or else stop the inflation of the fragment and return to the previous activity
any help appreciated :)
Use this code in present class which is capturing the location
currentLocation is the location Object
Intent intent = new Intent(this,target.class)
Bundle b = new Bundle();
b.putParcelable("Location", currentLocation);
i.putExtra("Location", b);
startActivity(i);
Receive Activity code:
b = getArguments();
Location location = b.getParcelable("Location");
By this way you can pass the location.I think it may be useful to you.

Categories

Resources