Outsource GPS functionality in android app to a separate class - java

I followed http://developer.android.com/guide/topics/location/obtaining-user-location.html and this worked fine when being in the activity in the onCreate-method.
Then I wanted to outsource this functionality in a separate class called LocationHelper.
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class LocationHelper {
public Context mContext;
public Location loc;
public LocationHelper (Context mContext){
this.mContext = mContext;
// Acquire a reference to the system Location Manager
LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
setLocation(location);
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
public void setLocation(Location location) {
this.loc = location;
}
public Location getLocation() {
return this.loc;
}
}
In the activity I do this; basically I want to pull (for testing purposes!) the GPS coordinates from my helper class and display it. Problem being, the location always is null.
public class GraffitiWall extends Activity {
private TextView tv;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = new TextView(this);
LocationHelper gpsie = new LocationHelper(this);
while (true){
makeUseOfNewLocation(gpsie.getLocation());
}
}
public void makeUseOfNewLocation(Location loc){
if (loc == null){return;}
tv.setText("" + loc.getLatitude());
setContentView(tv);
}
}
What am I missing and doing wrong?

Putting an infinite loop in your onCreate method is a bad idea. Your problem is most likely being caused because onCreate is never completing and passing control back to the OS. I wouldn't be surprised if this caused Force Close errors.
Maybe what you need to do is create a service which will do your location monitoring and update your activity from there.

Related

Google Play Services: can't connect to server

(Background: all I want is a unique and persistent Google Play identifier for the user. (even after uninstalls, or on different devices) This is the only reason I am doing this.)
I am using Cordova. This is my main activity.
Problem: the onConnected function never runs. I am able to sign in fine, however. (I can see the sign in window, the sign in circle, and everything else) but it just never runs.
NOTE: onConnectionFailed runs once, with a SIGN_IN_REQUIRED statusCode.
package com.myapp;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.games.Players;
import com.google.android.gms.games.Games;
import android.os.Bundle;
import org.apache.cordova.*;
import android.util.Log;
public class MyApp extends CordovaActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String LOGTAG = "GooglePlayServices";
// Client used to interact with Google APIs.
private GoogleApiClient mGoogleApiClient;
private CordovaActivity activity;
boolean mResolvingError;
#Override public void onCreate (Bundle savedInstanceState) {
activity = this;
super.onCreate (savedInstanceState);
super.init ();
mGoogleApiClient = new GoogleApiClient.Builder (this)
.addConnectionCallbacks (this)
.addOnConnectionFailedListener (this)
.addApi (Games.API)
.addScope(Games.SCOPE_GAMES)
.build ();
mGoogleApiClient.connect ();
super.loadUrl(Config.getStartUrl());
}
#Override public void onConnectionFailed (ConnectionResult result) {
if (mResolvingError) return;
if (!result.hasResolution()) {mResolvingError = true; return;}
Log.d (LOGTAG, result.toString());
try {
mResolvingError = true;
result.startResolutionForResult (this, result.getErrorCode());
} catch (SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect ();
}
}
#Override public void onConnected (Bundle connectionHint) {
// This never runs... this is the most critical part. I need the player ID!
String playerId = Games.Players.getCurrentPlayerId (mGoogleApiClient);
Log.w (LOGTAG, playerId);
}
// I saw this one with an #Override in others' code, but it won't compile if I add that.
public void onDisconnected () {}
protected void onStart () {super.onStart (); mGoogleApiClient.connect ();}
protected void onStop () {
super.onStop ();
if (mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect ();
}
protected void onActivityResult (int requestCode, int responseCode, Intent intent) {
if (!mGoogleApiClient.isConnecting()) mGoogleApiClient.connect ();
}
public void onConnectionSuspended (int cause) {mGoogleApiClient.connect ();}
}
"Your Oauth2 client CAN NOT be created from Google APIs Console, it MUST be created from the Google Play UI."

Android Activity Flow - From Base Superclass to Subclass to Baseclass again

As a N00bie to android, I'm trying to build a simple map-app. I started out doing everything in the same class, but for obvious reasons that got out of hand, fast. So I wanted to split the class, with the base class as the main flow for the activity, and the subclass as the 'utility' class.
So I instantiate an Subclass object, and in the subclass's onCreate I start calling methods. These methods never run though. What am I doing wrong? As soon as I create the subclass object, the sub's onCreate should fire, no? And, is it even the smart way of doing this in a subclass, instead of a whole other class?
Thanks in advance!
Base class:
package com.example.TestMap;
import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
public class MyActivity extends Activity {
private GoogleMap mMap;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LocationClass locationClass = new LocationClass();
}
public void setMap(){
Log.i("TestMap", "setMap");
mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
mMap.setMyLocationEnabled(true);
}
public void setCamera(Location location) {
Log.i("TestMap", "setCamera");
final LatLng locationLatLng = new LatLng( (location.getLatitude() ), location.getLongitude() );
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(locationLatLng) // Sets the center of the map to Mountain View
.zoom(17) // Sets the zoom
.bearing(90) // Sets the orientation of the camera to east
.tilt(30) // Sets the tilt of the camera to 30 degrees
.build(); // Creates a CameraPosition from the builder
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}
Subclass
package com.example.TestMap;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import java.util.List;
public class LocationClass extends MyActivity implements LocationListener {
private LocationManager locationManager;
private String provider;
private List<String> providers;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("TestMap", "LocationClass OnCreate");
GetProivder();
}
public void GetProivder (){
Log.i("TestMap", "LocationClass GetProivder");
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(2);
provider = locationManager.getBestProvider(criteria, false);
providers = locationManager.getProviders(true);
Location location = locationManager.getLastKnownLocation(provider);
Log.i("TestMap", "providerlist = " + providers);
Log.i("TestMap", "getBestProvider = " + provider);
Log.i("TestMap", "Location = " + location);
if (location != null) {
Log.i("TestMap", "Provider " + provider + " has been selected.");
super.setCamera(location);
super.setMap();
} else {
Log.i("TestMap", "location is null.");
}
}
#Override
public void onLocationChanged(Location location) {
Log.i("TestMap", "onLocationChanged");
}
#Override
protected void onResume() {
super.onResume();
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
#Override
protected void onPause() {
super.onPause();
locationManager.removeUpdates(this);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.i("TestMap", "onStatusChanged");
}
#Override
public void onProviderEnabled(String provider) {
Toast.makeText(this, "Enabled new provider " + provider,
Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderDisabled(String provider) {
Log.i("TestMap", "onProviderDisabled");
Toast.makeText(this, "Disabled provider " + provider,
Toast.LENGTH_SHORT).show();
}
}
Your code
LocationClass locationClass = new LocationClass(); does not create it. It just makes an object of it, but it does not tie to the lifecycle and call the methods.
You need to start it with an intent to make it appear (and take the entire screen based on skimming your code). Android will fire the appropriate method calls when you do so.
Like this:
Intent intent = new Intent(this, LocationClass.class);
startActivity(intent);
More information can be found here: http://developer.android.com/training/basics/firstapp/starting-activity.html#StartActivity
It must be defined in your manifest too or it will crash. There are other noticeable oddities things in your code, do you want LocationClass to extend MyActivity and not Activity? Your LocationClass also does not call setContentView() in onCreate, so you're not going to see a UI (as far as I can tell), unless you wanted it through the extends part.
EDIT :
If you extend subclass and put this intent code in onCreate, you're probably going to crash, as it will call super() in MyActivity (calling onCreate() again as it's the superclass), and will keep making more intents to start the activity. You should not subclass MyActivity if that's what the 'parent' class is.
You should only subclass Activity or a global parent activity (e.g. in my project right now, I extend SpiceActivity, as they all use common components related to Spice).
The subclass' onCreate method should be called when it is created by Android (see Understanding the Lifecycle Callbacks), which for example happens when an Intent to that Activity is issued.
Edit: I just saw #Mgamerz answer and realised that line in your superclass Activity was where you were trying to make Android create the subclass Activity. This next paragraph is somewhat irrelevant now, but note that you do still need to add the subclass activity to the manifest file.
Are you sure you're application is actually starting the subclass Activity, or is it still starting the superclass Activity? You might have to have a look at your project's "AndroidManifest.xml" file and check that there's an <activity /> element corresponding to the subclass Activity.
I think splitting the class into a superclass and a subclass is sensible if the superclass has functionality which can/will be re-used by multiple subclass Activities. For example you might have subclass activities like DirectionsActivity and SearchActivity which have some common map-related activity provided by their superclass MapActivity. Even if you have only one subclass Acitivty now, it may still make sense to have a superclass and a subclass if you think you're likely to write additional map-related activities later on. I my opinion it's not sensible to split the class into a superclass and a subclass just because the single class was getting too long. If you do just want a helper class and you don't expect to have more MapActivity subclasses in the future, you could make a MapUtils class in the same package as the Activity class, which would define some static helper methods. For example, you could put your GetProvider method into such a helper class. Sketch example (note the package-private access of MapHelper):
class MapHelper {
static Location getProvider() {
// ...
return location;
}
// Other helper methods here
}
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
// ...
setCamera(MapHelper.getProvider());
setMap();
}
// Other activity methods here
}

Android proximityalert app is crashing on button press

I am trying to write a simple app that takes the users current location and notifies them when they come near this location later. In my code I have it set up so that when the app starts it starts requesting location updates. Then when the button is pressed it takes the last known location and creates a proximity alert around that. my problem however is that when i press the button on both the emulator and the real phone it quickly crashes and i cant seem to find a reason why. is there an infinite loop i am some how missing? if there is a way to see the error messages from my phone that would also be very helpful.
Here is my code:
MainActivity.java
package com.YdidApplications.shotgun;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.Toast;
public class MainActivity extends Activity implements LocationListener
{
private ImageButton flagButton;
LocationManager lm;
double lat=0,long1=0; //Defining Latitude & Longitude
float radius=5; //Defining Radius
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lm=(LocationManager) getSystemService(LOCATION_SERVICE);
lm.requestLocationUpdates(lm.GPS_PROVIDER,
10000, //Update every 10 sec
10, (LocationListener) this);
flagButton = (ImageButton) findViewById(R.id.FLAG);
onFlagPress();
}
public void onFlagPress()
{
flagButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
location();
}
});
}
public void location()
{
lm=(LocationManager) getSystemService(LOCATION_SERVICE);
lm.getLastKnownLocation(LOCATION_SERVICE);
Intent i= new Intent("com.adnan.proximityalert"); //Custom Action
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), -1, i, 0);
lm.addProximityAlert(lat, long1, radius, -1, pi);
}
#Override
public void onLocationChanged(Location location) {
lat= location.getLatitude();
long1 = location.getLongitude();
Toast.makeText(null, lat+", "+long1, 0);
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
ProximityReciever.java
package ProximityReciever;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.widget.Toast;
/*This is the Reciever for the Brodcast sent, here our app will be notified if the User is
* in the region specified by our proximity alert.You will have to register the reciever
* with the same Intent you broadcasted in the previous Java file
*
* #Author: Adnan A M
*/
public class ProximityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
// The reciever gets the Context & the Intent that fired the broadcast as arg0 & agr1
String k=LocationManager.KEY_PROXIMITY_ENTERING;
// Key for determining whether user is leaving or entering
boolean state=arg1.getBooleanExtra(k, false);
//Gives whether the user is entering or leaving in boolean form
if(state){
// Call the Notification Service or anything else that you would like to do here
Toast.makeText(arg0, "Welcome to my Area", 600).show();
}else{
//Other custom Notification
Toast.makeText(arg0, "Thank you for visiting my Area,come back again !!", 600).show();
}
}
}
Any advise would be greatly appreciated.
Thanks,
Logan

Android - requestLocationUpdates causes identifier expected error

EDIT: Please note that while I received an answer, I don't understand what's wrong or why the solution fixes it. I'm still looking for a debunk...
I am receiving the error:
error: (identifier) expected
on the line
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
where the identifier expected points to the "(".
[Note: I actually get four of these errors pointing to the "(", "0", "0", and the ")".]
I always get this error when I slip up with syntax - but I cannot find it this time. My code is relatively short so I pase it, but please know that the code works completely fine when I comment out the offending line above.
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.view.View.*;
import android.view.View;
import android.content.Context;
import java.lang.CharSequence;
import android.widget.Toast;
import android.location.*;
public class Entrance extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button bGPS = (Button)findViewById(R.id.button_gps);
bGPS.setOnClickListener(bGPSListener);
}
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener()
{
public void onLocationChanged(Location location)
{
Context context = getApplicationContext();
CharSequence text = "Location found.";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
private OnClickListener bGPSListener = new OnClickListener()
{
public void onClick(View v)
{
Context context = getApplicationContext();
CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
};
}
The code line is "outside" of any method in the class. You can assign its return value to a member variable which would allow it to be on that line, but that is considered "bad form" in programming.
Move the call into a method that your class will call.
you can't just envoke method any there inside class atleast put it is seperate section like this
{
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}

When Getting GPS Location, load another URL

I have a little problem... I have made an Android application which extends the webview. The webview Html page with a map on like this: Map example, it was also here I got my inspiration. My onCreate method looks like this:
super.onCreate(savedInstanceState);
//Removes the title bar in the application
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
//Creation of the Webview found in the XML Layout file
browserView = (WebView)findViewById(R.id.webkit);
//Removes both vertical and horizontal scroll bars
browserView.setVerticalScrollBarEnabled(false);
browserView.setHorizontalScrollBarEnabled(false);
myLocationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);
//Enable Javascripts
url = "http://www.my-homepage.dk/map_example.html";
browserView.getSettings().setJavaScriptEnabled(true);
//The website which is wrapped to the webview
browserView.loadUrl(url);
So when My application gets a GPS location, it invokes this method:
LocationListener onLocationChange=new LocationListener() {
public void onLocationChanged(Location location) {
StringBuilder buf=new StringBuilder(url);
buf.append("?");
buf.append("lon=");
buf.append(String.valueOf(location.getLongitude()));
buf.append("&");
buf.append("lat=");
buf.append(String.valueOf(location.getLatitude()));
browserView.loadUrl(buf.toString());
}
So it basically just loads another URL.... But, my problem is, 1. it keeps the orignal website "map image", i imagined it would "unload" the page, and 2. When the second url is loaded, it takes quite a long time before it is finished, and when i am testing on my HTC Desire, it sometimes doesnt show the second loaded page (the map with location) before it turns the screen off and lock, or if i go out and in the application, that sometimes helps too...
Hope you can help :)
A suggestion - in onLocationChanged, make locationFound(); the first statement instead of the last.
It would be good to stop the listener immediately, as the loadUrl statement could take some time to complete, while the provider could be sending more updates.
Here is the solution... The GPS listener apparently broadcast more than once ;) so, when the GPS finds a location it loads the url and then stops broadcasting.
So the problem before was, that it sent loads of URL's to the html page, and therefore never just loaded 1 single url. And i just simplified the onLocationChanged a bit.
public void locationFound(){
myLocationManager.removeUpdates(this);
}
#Override
public void onLocationChanged(Location location) {
String lon = "lon="+String.valueOf(location.getLongitude());
String lat = "lat="+String.valueOf(location.getLatitude());
browserView.loadUrl(url+"?"+lon+"&"+lat);
locationFound();
}
Here is the SourceCode for the application:
package com.webview;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class WebViewTest extends Activity implements LocationListener{
private WebView browserView;
private static String PROVIDER="gps";
private LocationManager myLocationManager=null;
private String url;
private boolean LocFound = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Removes the title bar in the application
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
//Creation of the Webview found in the XML Layout file
browserView = (WebView)findViewById(R.id.webkit);
//Removes both vertical and horizontal scroll bars
browserView.setVerticalScrollBarEnabled(false);
browserView.setHorizontalScrollBarEnabled(false);
myLocationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);
//Enable Javascripts
url = "http://www.test.dk/test.html";
browserView.getSettings().setJavaScriptEnabled(true);
//The website which is wrapped to the webview
browserView.loadUrl(url);
}
#Override
public void onResume() {
super.onResume();
myLocationManager.requestLocationUpdates(PROVIDER, 0,
0,
this);
}
#Override
public void onPause() {
super.onPause();
myLocationManager.removeUpdates(this);
}
public void locationFound(){
myLocationManager.removeUpdates(this);
}
#Override
public void onLocationChanged(Location location) {
String lon = "lon="+String.valueOf(location.getLongitude());
String lat = "lat="+String.valueOf(location.getLatitude());
browserView.loadUrl(url+"?"+lon+"&"+lat);
locationFound();
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}

Categories