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.
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 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.
This might be more of a question about class structure but I am trying to add a simple on click listener to the following piece of code. Once clicked it will change the "SENSOR_DELAY_FASTEST" value to "SENSOR_DELAY_NORMAL". So I can toggle on the fly. But as I am in MainActivity i cannot implement onClickListener. Could anyone give me any pointers as to how I could handle this?
As I said. It might just be my lack of Java knowledge hindering me here. Perhaps it is better to setup another class to handle the clicks?
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private TextView xText, yText, zText;
private Sensor accelerometerSensor;
private SensorManager sensorManager;
#Override
public void onSensorChanged(SensorEvent event) {
// display the sensor values in the x,y and z text views
xText.setText("X: " + event.values[0]);
yText.setText("Y: " + event.values[1]);
zText.setText("Z: " + event.values[2]);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// create sensor manager
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// create accelerometer sensor
accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// register listener
sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_FASTEST);
// assign text views
xText = (TextView)findViewById(R.id.xText);
yText = (TextView)findViewById(R.id.yText);
zText = (TextView)findViewById(R.id.zText);
}
}
Option #1:
Of course you can do it in your MainActivity. All you have to do is find the UI element that you want to listen to a click event. For example if your UI element is a simple Button, you can do the following:
// find button with id "myButtonId" in the XML layout
Button b = (Button) findViewById(R.id.myButtonId);
// set a listener on that button
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { // gets called when clicked
// button has been clicked,
// your code here
}
});
Option #2:
But you can also define in your XML layout, that your method onClick_Button() shall be called after the button click.
Inside your XML layout:
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/myButtonId"
android:text="Click Me"
android:onClick="onClick_Button">
</Button>
Inside your MainActivity:
public void onClick_Button(View v) {
// your code here
}
In Java, a single class can be derived only from one class but can have multiple interfaces.
As per as I can interpret, you are facing problem in implementing
OnclickListener interface as you think that you have already
implemented SensorEventListener.
You can easily implement multiple interfaces by seperating with comma. For example:
public class MainActivity extends AppCompatActivity implements SensorEventListener, View.OnClickListener {
private Button button;
private TextView xText, yText, zText;
private Sensor accelerometerSensor;
private SensorManager sensorManager;
#Override
public void onSensorChanged(SensorEvent event) {
// display the sensor values in the x,y and z text views
xText.setText("X: " + event.values[0]);
yText.setText("Y: " + event.values[1]);
zText.setText("Z: " + event.values[2]);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// create sensor manager
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// create accelerometer sensor
accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// register listener
sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_FASTEST);
// assign text views
xText = (TextView)findViewById(R.id.xText);
yText = (TextView)findViewById(R.id.yText);
zText = (TextView)findViewById(R.id.zText);
//Declare button in activity_main.xml
button=(Button)findViewById(R.id.button);
button.setOnClickListener(this);
}
#Override
public void onClick(View v){
changeSensorDelay();
}
public void changeSensorDelay(){
//Your own implementation
}
}
sometimes when android studio does not found some classes its due problems in the installation or paths where resources are.
if you are sure its well installed, try to implement the interface directly anonymoue for example:
...setOnclickListener( new ClickListener( View v)
{
...//more code here
}
)
butif you are implementing the interface in your activity must not compile, because you have to implement the methods of that interface, check that if don't work, please give me more information
Is there any code that lets you show your active coordinates in a self-made app? I am having troubles with my google maps and want to see what my active coordinates are. I prefer to show it as I am looking at the google maps in my app ie like a second layer of information. Thanks all !
You can set up a LocationListener.
In the onLocationChanged callback, you will receive a Location. You can then .getLatitude() and .getLongitude() from the location, and apply it to your layout.
public class MyActivity extends MapActivity implements LocationListener {
private LocationManager locationManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
requestFineAccuracyLocationUpdates();
}
private void requestFineAccuracyLocationUpdates() {
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
List<String> providers = locationManager.getProviders(true);
for (String provider : providers) {
locationManager.requestLocationUpdates(provider, 5000, 1000, this);
}
}
#Override
public void onLocationChanged(Location location) {
/* You can get your latitude and longitude here, and do whatever. */
}
}
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.