public class Page3 extends Activity {
double latitude;
double longitude;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page3);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
/* Use the LocationManager class to obtain GPS locations */
LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
LocationListener mlocListener = new MyLocationListener();
try {
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
} catch (SecurityException e) {
e.printStackTrace();
}
}
/* Class My Location Listener */
public class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
double a = loc.getLatitude();
latitude=a;
double b = loc.getLongitude();
longitude=b;
String Text = "My current location is: " +
"Latitud = " + loc.getLatitude() +
"Longitud = " + loc.getLongitude();
String x = getCompleteAddressString(a, b);
TextView text = (TextView) findViewById(R.id.tv_address);
text.setText(x);
}
Now,I want to access the variables latitude and longitude in another class.Here is the class,where I need to access these variables.Please note:The values of latitiude and longitude are set properly in this function since I get my current location(I dint paste the entire code here,since it is meaningless to do so)
Here is the code I wrote in the class where I want to access these variables
public class Page2 extends Activity {
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page2);
Button btn = (Button) findViewById(R.id.help);
Page3 a=new Page3();
final double lati=a.latitude;
double longi=a.longitude;
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendSMS("9740641023", "Help"+lati+"");
}
});
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
Again I haven't copy pasted the entire code.This code was working fine on its own,but now on modification it sends the message "Help0.0" although according to me the latitude value should have changed to my current location.Please do help me out.
Your problem is basically that the one instance is created within a method:
LocationListener mLocListener = new MyLocationListener();
Instead, you should make it a field of that class.
And, if you make that a public static field, then other classes can directly access it using
LocationListener theListner = Classname.mLocListener;
But that is just a very "brute force way" of doing things. So, you can use that to see if you can make progress from there; but thing is: directly accessing static fields from other classes is bad practice; and you should avoid it.
As the real lesson is: this is very basic "java knowledge". You should step back from "android" for now; and study those basic Java things (like: "what are reasonable ways to access information in other objects"). Otherwise, you will hit one wall after the other!
And then, when you understand those basics; than you look into good books/tutorials about Android that explain to you how the "Android world" works. Because Android is sometimes using very special ways to get things done.
Declare that variavle as public static double lattitiue in First.java class
and now you can get value of this variable in any class by using First.lattitude
Good Data Abstraction and Encapsulation allows clients of a class to only see what the class allows the client(s) to see. Your data members like your variables latitude and longitude in the class Page3 should not be accessed directly by the other class. You should have public getter (accessor) and setter (mutator) methods that restrict "access" to your data members that should be declared as private.
You can only inherit one class in Java but you can implement as many interfaces as you like. Thus you do not need the inner public class MyLocationListener in the Page3 class. Just use the implement keyword and override the methods of the interface.
public class Page3 extends Activity implements LocationListener { // implement the interface instead of creating an inner class
private double latitude; // hide your data members from the client
private double longitude;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page3);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
/* Use the LocationManager class to obtain GPS locations */
LocationManager mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try {
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); // pass in this referring to the current class since implementing the interface LocationListener
} catch (SecurityException e) {
e.printStackTrace();
}
#Override
public void onLocationChanged(Location loc) {
setMyLatitude(loc.getLatitude()); // use mutator method to change value of your private data member
setMyLongitude(loc.getLongitude()); // use mutator method to change value of your private data member
String Text = "My current location is: " +
"Latitud = " + loc.getLatitude() +
"Longitud = " + loc.getLongitude();
String x = getCompleteAddressString(a, b);
TextView text = (TextView) findViewById(R.id.tv_address);
text.setText(x);
}
public void setMyLatitude(double a) {
this.latitude = a;
}
public void setMyLongitude(double b) {
this.longitude = b;
}
public double getMyLatitude() {
return latitude;
}
public double getMyLongitude() {
return longitude;
}
}
Now use your public methods to access your data members in the second activity.
public class Page2 extends Activity {
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page2);
Button btn = (Button) findViewById(R.id.help);
Page3 a=new Page3();
final double lati=a.getMyLatitude();
double longi=a.getMyLongitude();
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendSMS("9740641023", "Help"+lati+"");
}
});
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
That is for good programming practice. A listener to communicate between to the two activities is probably what you will need to not get the initialized double value of 0.0. The listener should be implemented in class Page2 with a data member that is set to the listener in Page2 in class Page3. The listener will have some method(s) to either pass the data you want or tell the class Page2 that information has been modified in some way.
public class Page2 extends Activity implements DataListener {
.......
#Override
public void someMethod() {
// do something with the data longitude and latitude as their values have changed
}
private GoogleApiClient client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page2);
Button btn = (Button) findViewById(R.id.help);
Page3 a=new Page3();
a.setDataListener(this); // pass listener to the other class
/* code in Page2 */
}
public class Page3 extends Activity implements LocationListener {
private DataListener myListener;
/* code in Page3 */
#Override
public void onLocationChanged(Location loc) {
setMyLatitude(loc.getLatitude()); // use mutator method to change value of your private data member
setMyLongitude(loc.getLongitude()); // use mutator method to change value of your private data member
myListener.someMethod(); // call this method to inform the other class that information has changed
String Text = "My current location is: " +
"Latitud = " + loc.getLatitude() +
"Longitud = " + loc.getLongitude();
String x = getCompleteAddressString(a, b);
TextView text = (TextView) findViewById(R.id.tv_address);
text.setText(x);
}
public void setDataListener(DataListener listener) {
this.myListener = listener;
}
You can also pass in the the longitude and latitude directly into the "DataListener" method "someMethod" in the Page3 and not even need the getters and setters and private data members of the Page3 class.
Related
In my Android application (Wheather app), I have a main activity (displaying the wheater on the screen) and a class (getting the current location of the phone).
The "Position" class gets the latitude and longitude, which I would like to send in my main activity to use them. To do that, I tried to use getters but that does not seem to work. Here is the code for both classes :
Location class: (just pay attention to the getters at the end)
public class Position extends AppCompatActivity implements LocationListener {
private double longitude;
private double latitude;
private LocationManager locationManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
Location location = locationManager.getLastKnownLocation(locationManager.NETWORK_PROVIDER);
onLocationChanged(location);
}
#Override
public void onLocationChanged(Location location) {
longitude=location.getLongitude();
latitude=location.getLatitude();
}
public double getLongitude1() {
return this.longitude;
}
public double getLatitude1() {
return this.latitude;
}
Main_Activity: (again just pay attention to the last four lines where I i'm trying to use latitude and longitude)
public class MainActivity extends AppCompatActivity {
TextView cityField, detailsField, currentTemperatureField, humidity_field, pressure_field, weatherIcon, updatedField;
Typeface weatherFont;
Position position = new Position();
private double latitude1;
private double longitude1;
private String latitude2;
private String longitude2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_main);
weatherFont = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/weathericons-regular-webfont.ttf");
cityField = (TextView)findViewById(R.id.city_field);
updatedField = (TextView)findViewById(R.id.updated_field);
detailsField = (TextView)findViewById(R.id.details_field);
currentTemperatureField = (TextView)findViewById(R.id.current_temperature_field);
humidity_field = (TextView)findViewById(R.id.humidity_field);
pressure_field = (TextView)findViewById(R.id.pressure_field);
weatherIcon = (TextView)findViewById(R.id.weather_icon);
weatherIcon.setTypeface(weatherFont);
Function.placeIdTask asyncTask =new Function.placeIdTask(new Function.AsyncResponse() {
public void processFinish(String weather_city, String weather_description, String weather_temperature, String weather_humidity, String weather_pressure, String weather_updatedOn, String weather_iconText, String sun_rise) {
cityField.setText(weather_city);
updatedField.setText(weather_updatedOn);
detailsField.setText(weather_description);
currentTemperatureField.setText(weather_temperature);
humidity_field.setText("Humidity: "+weather_humidity);
pressure_field.setText("Pressure: "+weather_pressure);
weatherIcon.setText(Html.fromHtml(weather_iconText));
}
});
latitude1 = position.getLatitude1();
longitude1 = position.getLongitude1();
latitude2 = String.valueOf(latitude1);
longitude2 = String.valueOf(longitude1);
asyncTask.execute(latitude2, longitude2); // asyncTask.execute("Latitude", "Longitude")
}
Why do I always get latitude2 = 0.0 and longitude2 = 0.0 in my android monitor ?
You have two different activities. Not an activity and a background service. There is only a single UI thread that runs the Activities. So when MainActivity is running, the Position activity is in the background and not running. And you can't create an object of an Activity using Position position = new Position();.
Why is your Position class an Activity? The onCreate method will never be called there unless you start the class as an Activity. Remove the AppCompatActivity from it and move the onCreate method in a separate method e.g. getLocation.
You also want to pass the Context to the Position class. Create a constructor for that
public Position(Context context) {
this.context = context;
}
and use that for the system calls.
Private variables can't be shared. Change it to.
public double longitude1;
public double latitude1;
You don't really need Position extend from an Activity. I can understand what you are trying to do, you just want to get the location from LocationManager, and send the result to the MainActivity. It should be fine if you just make a LocationManager instance in your MainActivity and pass the result of the location to whatever you want inside MainActivity.
public class MainActivity extends AppCompatActivity {
TextView cityField, detailsField, currentTemperatureField, humidity_field, pressure_field, weatherIcon, updatedField;
Typeface weatherFont;
Position position = new Position();
private double latitude1;
private double longitude1;
private String latitude2;
private String longitude2;
private LocationManager mLocationManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_main);
weatherFont = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/weathericons-regular-webfont.ttf");
cityField = (TextView)findViewById(R.id.city_field);
updatedField = (TextView)findViewById(R.id.updated_field);
detailsField = (TextView)findViewById(R.id.details_field);
currentTemperatureField = (TextView)findViewById(R.id.current_temperature_field);
humidity_field = (TextView)findViewById(R.id.humidity_field);
pressure_field = (TextView)findViewById(R.id.pressure_field);
weatherIcon = (TextView)findViewById(R.id.weather_icon);
weatherIcon.setTypeface(weatherFont);
mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// do check permission staff as you post before
Location location = locationManager.getLastKnownLocation(locationManager.NETWORK_PROVIDER);
// do what you want with the location now.
Basically I think you don't have to make a Position class. You can get location directly and just use it then.
I suggest you to add following reforms to your code.
You need to create object of Position class inside onCreate() method of MainActivity. As onCreate() runs before everything else, it's necessary to have the definition of Position class inside this method.
Make your variables for longitude and latitude public to make them accessible in other class.
Position class need not to extend AppCompatActivity. Instead of using this and OnCreate() method, you can use Constructor and define all your stuff there.
public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
startActivity(i);
}
}
public class ShareData {
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
public class klasaB extends Activity{
ShareData sd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int i =sd.get_numb();
System.out.println("Saved numb:" + i);
}
}
My question is, if i declare object in 1st class, and set its parameter number to 5, how to acces this number from other class because now my apk crashes when reading " int i =sd.get_numb(); " in class "klasaB".
Any suggestion how to make this work?
ps: i dont want to use static variables, or putExtra with Intents.
If data is simple/primitive then use Intent to pass data from one activity to another. That is what Intent is for.
If it is not (some sort of complex data structure or object), I would extend Application, by making a custom sub class. Application class (as the name implies) is accessible to all Activities, even when app transitions from one to another. Below is a very simple example, just to show you the idea. You can modify/adjust that to your needs.
public class MyApplication extends Application {
private X x;
public static void setX(X x) { ... }
public static X getX() { ... }
}
public class ActivityA extends Activity {
...
MyApplication.setX(x);
}
public class ActivityB extends Activity {
...
X x = MyApplication.getX();
}
You may have mixed up Activity/MainActivity/AppCombatActivity inheritance... I suspect that the reason you are seeing the error -- by the way, please look into "how to ask" and include a bit more information next time -- is that sd in klasaB is never initialized.
MainActivity.SD will hold that 5 after its onCreate(), whereas klasaB.sd is never set to anything.
You never reference or instantiate SD in class B. To get the data to ClassB you will need to set the data as an extra in the intent. Most classes cannot be sent in the intent, so for your case you should pass the primitive types of the object, then create the object.
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtra("TAG", SD.get_num());
startActivity(i);
And then in Class B
ShareData SD = new ShareData();
SD.set_num(getIntent.getIntExtra("TAG", 0);
You can access your class object either using implements Serializable or Parcelable
1.Implement serializable into your ShareData class
public class ShareData implements Serializable{
private int number;
public ShareData(){
this.number=0;
}
public void set_numb(int num){
number = num;
}
public int get_numb(){
return number;
}
}
2.create object of SharedData and share with intent to classB
public class MainActivity extends AppCompatActivity {
public ShareData SD = new ShareData();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SD.set_numb(5);
}
// when button clicked
public void noviEkran(View view){
Intent i = new Intent(this,klasaB.class);
i.putExtras("key", SD)
startActivity(i);
}
}
3.Access in classB
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ShareData sd = (ShareData)getIntent().getSerializableExtra("key").
System.out.println("Saved numb:" + sd.get_num());
}
Use a singleton class
Declare an instance in ShareData class:
public class ShareData {
private static ShareData sdInstance = null;
...}
add this method in ShareData class:
public static ShareData getInstance(){
if(sdInstance == null){
sdInstance = new ShareData();
}
return sdInstance;
}
To get same object in other classes , use this
ShareData sd = ShareData.getInstance();
now you will receive same sd.get_numb()
I am working on android application in which i need to start the location service. All i need to make it sure that the service should work, whether it will be on any activity, if i press the back button/home button or even if i sweep the application by pressing home button. My location service stops working after sometime like i put the timing of 1 minute but it will call it after 2-3 minutes.
private static final LocationRequest REQUEST = LocationRequest.create()
.setInterval(1000 * 60 * 1) // 30 minutes seconds
.setFastestInterval(1000 * 60 * 1) // 16ms = 60fps
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
My code is given below for calling location service class and main class where i am running calling that service. Please help me out in the above described scenario where i want to run that service in background: When press the back button, home button, removing application by pressing home button.
public class GPSLoggerService extends Service {
private LocationManager lm;
private static long minTimeMillis = 2000;
private static long minDistanceMeters = 0;
private static float minAccuracyMeters = 35;
private static boolean showingDebugToast = false;
MyLocationTracker locationTracker;
private static final String tag = "MUrgency GPS Logger";
/** Called when the activity is first created. */
private void startLoggerService() {
if (locationTracker != null)
return;
locationTracker = new MyLocationTracker(this) {
#Override
public void onLocationFound(Location location) {
Constants.sMY_LOCATION = location;
float a = (float) location.getLatitude();
float b = (float) location.getLongitude();
SharedPreferences prefs = getSharedPreferences("locationPref", 0);
SharedPreferences.Editor editor = prefs.edit();
editor.putFloat("latitudeFloat", a);
editor.putFloat("longitudeFloat", b);
editor.commit();
if (minutes > 5){
shouldSync = true;
}
}
};
}
private void shutdownLoggerService() {
}
}
#Override
public void onCreate() {
super.onCreate();
startLoggerService();
}
#Override
public void onDestroy() {
super.onDestroy();
shutdownLoggerService();
}
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example.
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**
* Class for clients to access. Because we know this service always runs in
* the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
GPSLoggerService getService() {
return GPSLoggerService.this;
}
}
}
Main class where i am calling service at onCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mainlanding);
startService(new Intent(this, GPSLoggerService.class));
}
#Override
protected void onDestroy() {
sActivityMain = null;
super.onDestroy();
stopLocationService();
}
From my view I can see this is a normal process, when the app enters OnPause method, this starts to works in background then you need a background process to execute your class and functions that you want.
If this is your first time using parallel programming I think you need to dedicate a little bit of your time to search information about this. It's amazing form to work with background processes. Really it's the difference between a normal android programmer and professional android programmer (among other things) because with the background processes can use all potency of your device.
Tell me if I helped you, good programming!
I'm trying to set a textview text when the user location changes. All the code for the GPS portion works. I have been testing using Log();
Now instead of using Log, I wish to display the same information on the main layout, but the LocationChanged event is in a different class so I don't have access to the layout.
public class mylocationlistener implements LocationListener
{
#Override
public void onLocationChanged(Location location)
{
if (location != null)
{
Log.v("kjdv", location.getLatitude() + ", " + location.getLongitude());
//I would like to set a textview here, but don't have access to the object
}
}
This class gets created here:
public class gps extends ListActivity implements View.OnClickListener
{
#Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
SetupLocationListener();
}
public void SetupLocationListener()
{
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
LocationListener ll = new mylocationlistener(this);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, ll);
}
So how, from the myLocationListener class can I set text in the onLocationChanged event?
Thanks!
We have 2 options.
one is just like as MisterSquonk said. keeping the Location listener as the inner class and the other one is to pass the object of the textView to the constructor of the mylocationlistener. Dont forget to handle null clause in second step.
I'm working on a simple Android app, with a GPS listener and a webview.
I can get the latitude and longitude with no issue. The problem is, I want to put the latitude and longitude into a URL (like myurl.com/mypage.php?lat=57&lon=21)... but the variable the data is stored in is confined to its class. I can't figure out how to declare or create a variable that I can use throughout the entire main class. Here's my code:
public class WTest2Activity extends Activity {
public String txt;
public class MyLocationListener implements LocationListener {
public void onLocationChanged(Location loc) {
loc.getLatitude();
loc.getLongitude();
txt = "Latitude: " + loc.getLatitude() + "Longitude: " + loc.getLongitude();
Toast.makeText( getApplicationContext(),txt,Toast.LENGTH_SHORT).show();
}
public void onProviderDisabled(String provider) {
Toast.makeText( getApplicationContext(),"Gps Disabled",Toast.LENGTH_SHORT ).show();
}
public void onProviderEnabled(String provider) {
Toast.makeText( getApplicationContext(),"Gps Enabled",Toast.LENGTH_SHORT).show();
}
public void onStatusChanged(String provider, int status, Bundle extras) {} /* do nothing */
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* Use the LocationManager class to obtain GPS locations */
LocationManager mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationListener mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
WebView webview;
webview = (WebView) findViewById(R.id.webview);
webview.getSettings().setJavaScriptEnabled(true);
webview.loadUrl("http://www.myurl.com/page.php?this=" + txt);
}
}
Your OnCreate method is the method called at start of Activity. At that time, txt is null. That's why it doens't show in your url. Then, onLocationChanged sets the value of txt but where are you using this afterwards? nowhere!.
you should move what you do in onCreate to onLocationChanged:
public void onLocationChanged(Location loc) {
loc.getLatitude();
loc.getLongitude();
txt = "Latitude: " + loc.getLatitude() + "Longitude: " + loc.getLongitude();
Toast.makeText( getApplicationContext(),txt,Toast.LENGTH_SHORT).show();
webview.loadUrl("http://www.myurl.com/page.php?this=" + txt);
}
add a new line here:
public class WTest2Activity extends Activity {
public String txt;
public Location location;
then, in your public void onLocationChanged(Location loc), try setting location.setLatitude(loc.getLatitide); and location.setLongitude(loc.getLongitude);
then, you can access your location anywhere with your global variable location
Buddy its just small logical mistake in your code. Let me explain. You are requesting location updates then right after that you are loading URL. Now location listening is different thread which is updating value of txt variable. And updating location takes time. And taken time can be different every time. That is why you need to move your loadUrl code to onLocationChanged method.