access the inner class variable to another method - java

Kindly help. I am not a regular java writer, so I can't solve this:
The getLastLocation() in onCreate method is returning 0.0 for Lat and Lang, while the value is correct withing getLastLocation() method itself. Also, in getLastLocation, AndroidStudio says, the argument Lat and Lang is never used.
Kindly help me correct this puzzle.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = new Bundle();
bundle.putDouble ("loclat", 25.4358);
bundle.putDouble("loclang", 81.8463);
Fragment SunFragment = new SunFragment();
SunFragment.setArguments(bundle);
setContentView(R.layout.activity_main);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
getLastLocation(Lat, Long);
//Value is 0 here
Toast.makeText(getApplicationContext(),Double.toString(Lat), Toast.LENGTH_LONG).show();
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this,
getSupportFragmentManager(), Lat, Long);
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
}
#SuppressLint("MissingPermission")
public void getLastLocation(double Lat, double Long){
if (checkPermissions()) {
if (isLocationEnabled()) {
mFusedLocationClient.getLastLocation().addOnCompleteListener(
new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
Location location = task.getResult();
if (location == null) {
requestNewLocationData();
} else {
final double Lat = location.getLatitude();
final double Long = location.getLongitude();
// Giving the value here
Toast.makeText(getApplicationContext(),"Long"+ Long, Toast.LENGTH_LONG).show();
}
}
}
);
} else {
Toast.makeText(this, "Turn on location", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
} else {
requestPermissions();
}
}

Try to setup ViewPager with Tab after getting data for Lat and Long
private Double Lat;
private Double Long;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
getLastLocation();
}
private void setupViewPager() {
Toast.makeText(getApplicationContext(),Double.toString(Lat), Toast.LENGTH_LONG).show();
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this,
getSupportFragmentManager(), Lat, Long);
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
}
#SuppressLint("MissingPermission")
public void getLastLocation(){
if (checkPermissions()) {
if (isLocationEnabled()) {
mFusedLocationClient.getLastLocation().addOnCompleteListener(
new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
Location location = task.getResult();
if (location == null) {
requestNewLocationData();
} else {
Lat = location.getLatitude();
Long = location.getLongitude();
// Giving the value here
Toast.makeText(getApplicationContext(),"Long"+ Long, Toast.LENGTH_LONG).show();
setupViewPager();
}
}
}
);
} else {
Toast.makeText(this, "Turn on location", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
} else {
requestPermissions();
}
}
Suggestions: Instead of passing data to fragment you can use callback to communicate between Activity and Fragment. Check this to learn how to communicate between Activity and Fragment

You have a lot of issues here. You cannot do what you're trying to do with things the way they are right now. I'm a bit surprised this actually compiles. Long is a class name. I'd suggest sticking to convention, and use lowercase. So longitude and latitude. Your code is confusing to read.
First, the line:
getLastLocation(Lat, Long);
You're passing a double which is pass by value. You are not modifying the values you passed in. You cannot do this with primitive types. You would need to encapsulate primitives inside an object and pass that object. e.g.
public class Coordinates {
private double longitude;
private double latitude;
// getters and setters
}
I'm not really familiar with Android, but it seems that a similar object already exists, and it's in your code. That's Location. You should use that instead of passing around double.
Second, even if you could pass around primitives like that, you're creating and assigning new variables with these two lines:
final double Lat = location.getLatitude();
final double Long = location.getLongitude();
Finally, you're dealing with an asynchronous call. So assuming you solve the above problems, you're still going to have issues:
mFusedLocationClient.getLastLocation().addOnCompleteListener(
new OnCompleteListener<Location>() { ... });
There is no guarantee that this action will be completed by the time getLastLocation returns, so when you call Toast.makeText in onCreate you're still likely to get 0.
So what can you do?
Well, it seems like you need to retrieve location data before this onCreate method is called and cache it. Then, in this onCreate, you can just assume that it's set.
Alternately, as Mike M. suggests, there's another method you can take advantage of: onComplete

Related

How to return the value given by the gps within a function

I am trying to return the result value that gives me the sum of latitude and longitude, but the function is giving me back the default value
Double result = 0.1;
public Double codeQR(final Context context, final Activity activity){
client2 = LocationServices.getFusedLocationProviderClient(context);
client2.getLastLocation().addOnSuccessListener(activity, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
latitude = location.getLatitude();
longitude = location.getLongitude();
result = (latitude +longitude);
}
});
return result;
}
I expected the result of the sum of latitude and longitude, but it is returning 0.1
Like Andy said, the OnSuccessListener is asynchronous, so it will runs on a different Thread while your return value is on the main Thread.
You have different workaround :
Workaround 1) Declare in your scope a global result variable, that you can reuse anywhere in your class after you set it with your OnSuccessListener :
private Double result;
Workaround 2) Pass it to a method directly in its parameter :
public void codeQR(final Context context, final Activity activity){
client2 = LocationServices.getFusedLocationProviderClient(context);
client2.getLastLocation().addOnSuccessListener(activity, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
latitude = location.getLatitude();
longitude = location.getLongitude();
result = (latitude +longitude);
anotherMethod(result);
}
});
}
Workaround 3) Create a callback Interface, put this callback in your method parameter, and then call your method wherever you need to access the "result" value :
//A) Create a callback Interface
public interface MyCallback {
void onCallback(Double result);
}
//B) Put this callback in your method parameter
public void codeQR(final Context context, final Activity activity, MyCallback myCallback){
client2 = LocationServices.getFusedLocationProviderClient(context);
client2.getLastLocation().addOnSuccessListener(activity, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
latitude = location.getLatitude();
longitude = location.getLongitude();
result = (latitude +longitude);
myCallback.onCallback(result);
}
});
}
//C) Call your method wherever you need to access the "result" value
//For example, if you want to get the result value in the nextStep() method
private void nextStep(){
codeQR(this, this, new MyCallback() {
#Override
public void onCallback(Double result) {
Log.i("TestOfResult", "onCallback: " + result);
}
});
}
You can find more explanations about this interface on this link.
I hope this will help you, let us know if this worked or if you have questions !

How to create proper "this" object as argument? [duplicate]

This question already has answers here:
What is the meaning of "this" in Java?
(22 answers)
Closed 4 years ago.
I'm trying to write a function where I have to pass an Activity object to a method that requires such an argument. Usually in such case I'm supposed to just type "this" and it automatically recognizes which type of object it's supposed to create. But sometimes this doesn't work and it for whatever reason reassings a different type of object than the one that is required. For example, I actually use the exact same method in both of these cases:
if (checkLocationPermission(this)){
In this first one, the program automatically recognizes "this" as an Activity object. Here's the second one:
#Override
public void onSuccess(Location location) {
if (location == null || !checkLocationPermission(this)){
In this case the exact same method recognizes "this" as an OnSuccessListener instead of an Activity.
Another example I have in the same program is one where "this" object is supposed to be a Looper but instead it again gets recognized as an OnSuccessListener:
fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),this);
I don't know how to actually select the proper type of object for "this" argument since I can only type the same damn word.
EDIT:
Here's the full code. I used Looper.this just so you can find it easier. I also tried with MapsActivity.this and it doesn't work:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleMap mMap;
private GoogleApiClient googleApiClient;
public static final String TAG = MapsActivity.class.getSimpleName();
private FusedLocationProviderClient fusedLocationClient;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; //Request code to send to Google Play Services
private LocationRequest locationRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
locationRequest = LocationRequest.create().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(10*1000).setFastestInterval(1*1000);
}
private void setUpMapIfNeeded(){
if (mMap==null){
SupportMapFragment mapFragment = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
mapFragment.getMapAsync(this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
//setUpMap();
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG,"Location Services Connected");
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (checkLocationPermission(this)){
fusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location == null || !checkLocationPermission(MapsActivity.this)){
fusedLocationClient.requestLocationUpdates(locationRequest,new LocationCallback(),Looper.this);
}
else{
handleNewLocation(location);
}
}
});
}
}
public static boolean checkLocationPermission(Activity activity){
if(ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION},0);
return false;
}
return true;
}
private void handleNewLocation(Location location){
Log.d(TAG,location.toString());
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG,"Location Services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()){
//Starts an Activity that tries to resolve the error
try {
connectionResult.startResolutionForResult(this,CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
else{
Log.i(TAG,"Location services connection failed code: " + connectionResult.getErrorCode());
}
}
#Override
protected void onResume(){
super.onResume();
setUpMapIfNeeded();
googleApiClient.connect();
}
#Override
protected void onPause(){
super.onPause();
if (googleApiClient.isConnected()){
googleApiClient.disconnect();
}
}
#Override
public void onLocationChanged(Location location) {
handleNewLocation(location);
}
}
this corresponds to the object in which it is used. onSuccess is a method of OnSuccessListener class and hence this refers to OnSuccessListener. You need to use ActivityName.this. For example if you activity name is MainActivity, then
#Override
public void onSuccess(Location location) {
if (location == null || !checkLocationPermission(MainActivity.this)){
When you use an anonymous inner class, such as a listener, and use this, it refers to the anonymous inner class, because that's your current location.
For instance, with an OnClickListener:
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//"this" here will refer to the OnClickListener instance you create
}
}
Nothing is being "created" with a this argument. It's a direct reference to the current enclosing class. If you need to reference the Activity, you can use:
ActivityClassName.this
as long as you're in an inner class and not a static class.
If you use a lambda (only available for API 24+):
view.setOnClickListener((v) -> {
//"this" will reference your Activity because there's no inner class anymore
}
the this refers to the object of the immediate enclosing class. So, if you have some interface or class as an argument to a function, we usually do like this :
functionThatTakesInterfaceOrClassAsArgument( new TheInterfaceOrClass {
#Override
public void someMethod () {
// if you use `this` here, it refers to the object of `TheInterfaceOrClass`
}
});
If you want to use the object corresponding to an enclosing class (yet not the immediate enclosing class) using <className>.this
So, if the name of the enclosing Activity is MyActivity, one would need to use MyActivity.this.

How to put in one activity in one javafile when you call a function instead of many, Android

So I have this fab menu and each button have different activity what I want is to put the functions into one java file instead of creating a lot of java file to call different functions in the button
Here's the one of the java file - SVAuditorium.class.
public class SVAuditorium extends AppCompatActivity {
private static final LatLng Auditorium = new LatLng(10.294335, 123.880809);
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.street_view);
SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
(SupportStreetViewPanoramaFragment)
getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(
new OnStreetViewPanoramaReadyCallback() {
#Override
public void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
if (savedInstanceState == null) {
panorama.setPosition(Auditorium);
}
}
});
}
}
This is what I did to call the activities from the SVAuditorium and the rest.
case R.id.fab_auditorium:
startActivity(new Intent(this, SVSAuditorium.class));
break;
case R.id.fab_library:
startActivity(new Intent(this, SVLibrary.class));
break;
case R.id.fab_main:
startActivity(new Intent(this, SVMainBuilding.class));
break;
As you have stated that you only have changes in lat-long in each of your Activity, I would suggest keeping a single activity like you want and pass the lat-long through intent. Here's a sample code showing how you can achieve the behaviour.
Intent intent = new Intent(MainActivity.this, SVActivity.class);
Bundle longLat = new Bundle();
longLat.putDouble("LONGITUDE", longitude);
longLat.putDouble("LATITUDE", latitude);
intent.putExtras(longLat);
startActivity(intent);
Get the latitude and longitude in your SVActivity like this.
Bundle longLat = getIntent().getExtras();
double longitude = longLat.getDouble("LONGITUDE");
double latitude = longLat.getDouble("LATITUDE");
Initialize your views based on the value found in your SVActivity.
the Latlng is only different
Since LatLng implements Parcelable
You need only need one Java file and you can pass the LatLng through an Intent using Intent.putExtra("latlng", latlng), where you define that variable per clicked item
See answer - Android: How to pass Parcelable object to intent and use getParcelable method of bundle?
Then in that one Activity's onCreate method, you can LatLng latlng = getIntent().getParcelableExtra("latlng")

Sending double from one activity to another Android Studio

Hi,
I am trying to send data from one activity to another activity using this method: how to retrieve a Double value from one activity to another?
Yet every time I open up my application it crashes as its because my code is in the onCreate:
double lat, longi;
Intent getLocation;
Bundle extras;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getLocation = this.getIntent();
extras = getLocation.getExtras();
lat = extras.getDouble("lat");
longi = extras.getDouble("longi");
but when I put it in a button instead It can't resolve this.getIntent();
public void getCoordinates(View view){
Button coordinates = (Button) findViewById(R.id.getCoordinates);
coordinates.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
getLocation = this.getIntent();
extras = getLocation.getExtras();
lat = extras.getDouble("lat");
longi = extras.getDouble("longi");
}
});
}
I would like to receive data either automatically or using a button.
I am quite new in mobile computing so please don't roast me.
this meant isView.OnClickListener() in your code .
And we need YourActivity.this as Context
You should use
public void getCoordinates(View view){
Button coordinates = (Button) findViewById(R.id.getCoordinates);
coordinates.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
getLocation = YourActivity.this.getIntent();
extras = getLocation.getExtras();
lat = extras.getDouble("lat");
longi = extras.getDouble("longi");
}
});
}

How to pass information to a string outside a method?

I'm new to the Java language and have become a little stuck, I'm trying to pass a location to the String Bob. I need to pass a string from onLocationChanged method, to the String url which outside of the method. I have created a global variable, but the String bob does not hold any data.
Any help would be much appreciated.
public class MainActivity extends AppCompatActivity {
String bob = "";
LocationManager locationManager;
LocationListener locationListener;
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);}
}
}
TextView tempTextView;
TextView dateTextView;
TextView weatherDescTextView;
TextView cityTextView;
ImageView weatherImageView;
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tempTextView = (TextView) findViewById(R.id.tempTextView);
dateTextView = (TextView) findViewById(R.id.dateTextView);
weatherDescTextView = (TextView) findViewById(R.id.weatherDescTextView);
cityTextView = (TextView) findViewById(R.id.cityTextView);
weatherImageView = (ImageView) findViewById(R.id.weatherImageView);
dateTextView.setText(getCurrentDate());
// location
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
// Log.i("Location", location.toString());
Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
try {
List<Address> listAddresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
if (listAddresses != null && listAddresses.size() > 0) {
//Log.i("PlaceInfo", listAddresses.get(0).toString());
if (listAddresses.get(0).getLocality() != null)
{
bob += listAddresses.get(0).getLocality() + " ";
}
Log.i("hello", bob.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider ) {
}
#Override
public void onProviderDisabled(String provider) {
}
};
String url = "http://api.openweathermap.org/data/2.5/weather?q=" +bob+ "&units=metric&appid=xxxx";
i'm new to the Java language
My best piece of advice to you right now is to stop, put Android down, and go learn Java (or hell, get started with Kotlin) before trying to learn Android as well as you go. Android is complicated enough as is without trying to learn the language as well.
Anyway, as to your actual problem:
I'm trying to pass a location to the String 'Bob'. I need to pass a string from 'onLocationChanged' method, to the String 'url' which outside of the method... I have created a 'global' variable, but the String 'bob' does not hold any data.
You're problem is that that onLocationChanged method is a callback that actually doesn't get invoked until much later than the point at which you are trying to set the URL variable (assuming you actually register the callback, which your code does not show).
In other words, you are providing a hook in to the system that says, "when you have the location, let me know", meanwhile your code continues. When system lets you know the location is back (your callback is invoked) it's up to you to use the new value do something with it (in your case, I assume, make a network request).
So you would move your logic to right after the line where you update bob.
Hope that helps.
onLocationChanged is evaluated after you compute String url.
Once you have an understanding of multithreading, you will understand this.
At the moment, your code would be no different if you move String url to the very top of onCreate.
If you want the URL to be properly assigned, move it after Log.i("hello", and even check your logs to make sure it's correct
Personally, I don't suggest Android as the platform from which you learn Java

Categories

Resources