Search code examples
javaandroidandroid-studiogeolocation

Get the user's current city


Hi I posted a question concerning the same topic a while ago, after following your advices I can feel that I'm getting closed to solving my problem. The App does is now crashing as I click on the button with the following error message in the monitor:

FATAL EXCEPTION: main

Process: com.example.apple.myapp1, PID: 10081
                                       java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
                                           at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
                                           at java.util.ArrayList.get(ArrayList.java:308)
                                           at com.example.apple.myapp1.MainActivity$1.onClick(MainActivity.java:62)

MainActivity.java

package com.example.apple.myapp1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Locale;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;

import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class MainActivity extends Activity {
double lats, lons;
Geocoder geocoder;
double lat = lats;
double lon = lons;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button btnGetLocation = (Button) findViewById(R.id.button1);
    btnGetLocation.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            ProgressDialog mProgressDialog = new         ProgressDialog(MainActivity.this);
            mProgressDialog.setMessage("Fetching location...");
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            mProgressDialog.show();
            geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
            List<Address> addresses = null;
            try {
                addresses = geocoder.getFromLocation(lat, lon, 1);
            } catch (IOException e) {

                e.printStackTrace();
            }

            if (addresses != null) {
                String address = addresses.get(0).getAddressLine(0);
                String city = addresses.get(0).getLocality();
                String state = addresses.get(0).getAdminArea();
                String country = addresses.get(0).getCountryName();
                String postalCode = addresses.get(0).getPostalCode();
                String knownName = addresses.get(0).getFeatureName();

                mProgressDialog.dismiss();
                TextView cellText = (TextView)     findViewById(R.id.cellText);
                cellText.setText(address);

            } else {
                mProgressDialog.dismiss();
                TextView cellText = (TextView) findViewById(R.id.cellText);
                cellText.setText("Error");
            }
        }
    });
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Please click the button below to get your location" />

<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click Me" />

<TextView
    android:id="@+id/cellText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="" />

<TextView
    android:id="@+id/lacationText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="" />


</LinearLayout>

Solution

  • in the condition if (addresses != null) { } you should also check for the length of the addresses, since there might be 0.

    if (addresses != null && addresses.size() > 0) {
        String address = addresses.get(0).getAddressLine(0);
        String city = addresses.get(0).getLocality();
        String state = addresses.get(0).getAdminArea();
        String country = addresses.get(0).getCountryName();
        String postalCode = addresses.get(0).getPostalCode();
        String knownName = addresses.get(0).getFeatureName();
    
        mProgressDialog.dismiss();
        TextView cellText = (TextView) findViewById(R.id.cellText);
        cellText.setText(address);
    
    } else {
        mProgressDialog.dismiss();
        TextView cellText = (TextView) findViewById(R.id.cellText);
        cellText.setText("Error");
    }
    

    if it wasn't able to find at least one address you should consider showing the user an empty state.

    It also seems like you forgot to initialize your latitude and longitude before calling addresses = geocoder.getFromLocation(lat, lon, 1);

    To properly initialize this, do the following:

    Location location = intent.getParcelableExtra(__YOUR_PACKAGE_NAME__ + ".LOCATION_DATA_EXTRA");
    lat = location.getLatitude();
    lon = location.getLongitude();
    

    If you need any more help check out this page from android. It should hold all information you need.

    EDIT:

    I kind of assumed you we're further in the process, but it seems you have only tried to get the location of a latLong position, which you have never obtained. To achieve obtaining the address you will have to have the user's lcoation first.

    Again, the page mentioned above should explain everything you need to obtain the location, but make sure of the following:

    1. Have the permission to access the user's location (for Android 6+ use Runtime permissions)

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.google.android.gms.location.sample.locationupdates" >
    
      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    </manifest>
    

    2. Get an instance of the GoogleApi and ave your activity implement some callbacks

    For the Callbacks

    public class YourActivity extends AppCompatActivity implements
            ConnectionCallbacks, OnConnectionFailedListener
    

    Then in your OnCreate() create an instance of GoogleApiClient.

    protected GoogleApiClient mGoogleApiClient;
    
    public void onCreate(Bundle savedInstanceState) {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }
    

    3. Obtain the location from the GoogleApiClient Do this by implementing the callbacks properly.

    /**
     * Represents a geographical location.
     */
    protected Location mLastLocation;
    
    @Override
    public void onConnected(Bundle connectionHint) {
         // Gets the best and most recent location currently available, which may be null
         // in rare cases when a location is not available.
         mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
         if (mLastLocation != null) {
             // Determine whether a Geocoder is available.
             if (!Geocoder.isPresent()) {
                 Toast.makeText(this, "no geocoder available", Toast.LENGTH_LONG).show();
                 return;
             }
         }
     }
    

    4. Now obtain the lat long and try to obtain the address as attempted before.

    lat = mLastLocation.getLatitude();
    lon = mLastLocation.getLongitude();
    
    geocoder = new Geocoder(MainActivity.this, Locale.getDefault());
    List<Address> addresses = null;
    try {
        addresses = geocoder.getFromLocation(lat, lon, 1);
    } catch (IOException e) {
        e.printStackTrace();
    }
    

    This should be enough to obtain the actual adress of the device and ask the geocoder for the addresses. I altered the example a bit to simplify for this question. Google's example handles fetching the address a bit more clean. Note that you will also have to disconnect the GoogleApi when stopping your activity and such. Again I recommend reading the entire Tutorial page. You can find en example of their implementation on this page on GitHub