0

I have a question about android programming. I have a MainActivity class and class that implements LocationListner. I want to change some UI elements from onLocationChanged method from this second class but I have no idea how things like this should be done.

Here is my mainActivity:

public class MainActivity extends AppCompatActivity {

private LocationGPS gps;
private TextView text;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    enableGPS();
    initGuiElements();
}

private void enableGPS()
{
    gps = new LocationGPS(this);
}

private void initGuiElements()
{
    text = (TextView) findViewById(R.id.textTop);
    text.setText("nothing yet");
}

}

Here is my class for location.

public class LocationGPS implements LocationListener {

private Activity mainActivity;
private LocationManager locationManager;

public LocationGPS(Activity activity)
{
    this.mainActivity = activity;
    locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}

@Override
public void onLocationChanged(Location location) {
    //here I want to set text for TextView element
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onProviderDisabled(String provider) {

}

}

boringBob
  • 3
  • 2

5 Answers5

1

You have bunch of ways to do this, I will give 2 of them:

  1. Change your activity to implement the LocationListener and when you call for locationManager.requestLocationUpdates pass the activity as the listener, that way you will get the callbacks called in the Activity and not in the LocationGPS class, the MainActivity will look like:

    public class MainActivity extends AppCompatActivity
        implements LocationListener {
    
    private LocationGPS gps;
    
    private TextView text;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        enableGPS();
        initGuiElements();
    }
    
    private void enableGPS() {
        gps = new LocationGPS(this);
    }
    
    private void initGuiElements() {
        text = (TextView) findViewById(R.id.textTop);
        text.setText("nothing yet");
    }
    
    @Override
    public void onLocationChanged(Location location) {
    
    }
    
    @Override
    public void onStatusChanged(String provider, int status,          
    Bundle extras) {
    
    }
    
    @Override
    public void onProviderEnabled(String provider) {
    
    }
    
    @Override
    public void onProviderDisabled(String provider) {
    
    }
    }
    

    And the LocationGPS class:

    public class LocationGPS {
    
    private Activity mainActivity;
    
    private LocationManager locationManager;
    
    public LocationGPS(Activity activity) {
        this.mainActivity = activity;
        locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mainActivity);
    }
    }
    
  2. The second way you can create a communication interface in MainActivty which you need to pass to LocationGPS class and once you want to update the UI in activity you call this interface method in next way:

    public class MainActivity extends AppCompatActivity implements
        MainActivity.MainActivityInteractionInterface{
    
    private LocationGPS gps;
    
    private TextView text;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        enableGPS();
        initGuiElements();
    }
    
    private void enableGPS() {
        gps = new LocationGPS(this, getApplicationContext());
    }
    
    private void initGuiElements() {
        text = (TextView) findViewById(R.id.textTop);
        text.setText("nothing yet");
    }
    
    @Override
    public void updateUI() {
       text.setText("Some new text");
    }
    
    public interface MainActivityInteractionInterface {
        void updateUI();
    }
    }
    

And the LocationGPS will look now like:

    public class LocationGPS implements LocationListener{

    private MainActivity.MainActivityInteractionInterface interactionInterface;

    private LocationManager locationManager;

    private Context applicationContext;

    public LocationGPS(MainActivity.MainActivityInteractionInterface interactionInterface, Context applicationContext) {
        this.interactionInterface = interactionInterface;
        this.applicationContext = applicationContext;
        locationManager = (LocationManager) applicationContext.getSystemService(Context.LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        interactionInterface.updateUI(); // Or call this method whenever you need 
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
    }
Artyom Okun
  • 939
  • 1
  • 8
  • 14
  • I like your second idea, its look better. But now in LocationGPS ctor I do not have a activity so how I can call getSystemService? – boringBob Jan 17 '17 at 21:00
  • @boringBob Please see my updated answer. Just for the record it is always better to pass Application context instead of Activity context in terms of preventing memory leaks as it has single instance. if this answer matches your requirements please mark it as accepted. – Artyom Okun Jan 17 '17 at 22:33
1

I found Artyom Okun's second code suggestion to be most helpful, however it did require some debugging. I had to move the interface to a file of its own. This was due to "Cyclical inheritance" where you try to inherit an object that you want to create within your activity.

See this stackoverflow page explaining the issue

MainActivity.java

public class MainActivity extends AppCompatActivity implements
    MainActivityInteractionInterface{

private LocationGPS gps;

private TextView text;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    enableGPS();
    initGuiElements();
}

private void enableGPS() {
    gps = new LocationGPS(this, getApplicationContext());
}

private void initGuiElements() {
    text = (TextView) findViewById(R.id.textTop);
    text.setText("nothing yet");
}

@Override
public void updateUI() {
   text.setText("Some new text");
}


}

LocationGPS.java

public class LocationGPS implements LocationListener{

    private MainActivityInteractionInterface interactionInterface;

    private LocationManager locationManager;

    private Context applicationContext;

    public LocationGPS(MainActivityInteractionInterface interactionInterface, Context applicationContext) {
        this.interactionInterface = interactionInterface;
        this.applicationContext = applicationContext;
        locationManager = (LocationManager) applicationContext.getSystemService(Context.LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        interactionInterface.updateUI(); // Or call this method whenever you need 
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
    }

Then the new file MainActivityInteractionInterface.java

public interface MainActivityInteractionInterface {
    void updateUI();
}

To update the UI i update a global variable in the onLocationChanged() method of the LocationGPS class. then in updateUI() i use the global variable to write to text view.

note to write to the global in MainActivity its something like this:

MainActivity.bestLat = Lat;

Ben
  • 185
  • 1
  • 2
  • 8
0

Create a method in your MainActivity

public void updateText(String updatedText){
 text.setText(updatedText);
}

In you LocationGPS class, you already have the context of MainActivity, so in onLocationChanged, call this method

mainActivity.updateText(updatedText);

There is another way which recommend personally. Create an interface and call it in the onLocationChanged method. Implement in your MainActivity and in the implemented interface update your text. I prefer this method as you will not need to share context or rootview of your Activity which prevents possible memory leaks.

Malwinder Singh
  • 6,644
  • 14
  • 65
  • 103
0

Just put the LocationGps class inside the MainActivity class. Done. Sorry not able to comment so posting as answer.

0

This is help you

public class LocationGPS implements LocationListener {

private Activity mainActivity;
private LocationManager locationManager;

public interface OnChangeListener{
 public void onChangeListener();

}

OnChangeListener mOnChangeListener;

public LocationGPS(Activity activity,OnChangeListener onChangeListener)
{
    this.mainActivity = activity;
  mOnChangeListener = onChangeListener;
  locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}

@Override
public void onLocationChanged(Location location) {

//here I want to set text for TextView element
 mOnChangeListener.onChangeListener();   

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onProviderDisabled(String provider) {

}

Activity must implement interface OnChangeListener

public class MainActivity extends AppCompatActivity implements OnChangeListener {

private LocationGPS gps;
private TextView text;

@Override
 public void onChangeListener(){
//For example you may edit TextView
text.setText("data recieved:onLocationChanged")
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    enableGPS();
    initGuiElements();
}

private void enableGPS()
{

//You transfer interface
  gps = new LocationGPS(this,this);
}

private void initGuiElements()
{
    text = (TextView) findViewById(R.id.textTop);
    text.setText("nothing yet");
}
Nanoid
  • 21
  • 2