アプリの起動時に場所が必要です。LastLocation を取得するために、この tut を fusionlocationapi でフォローしています: https://developer.android.com/training/location/retrieve-current.html
アドレスを検索するための AsyncTask がボタンを介して実行されると完全に機能しますが、同じスニペットを oncreate または onstart に配置すると、おそらく場所の修正に時間がかかるため、NPE が発生します。
ボタンをクリックしなくても、アクティビティをロードして ProgressBar を表示し、場所を表示する必要があります。
回避策は、onstart で少し遅れてから AsyncTask を実行することですが、もっと効率的な方法があるはずだと推測しています。
public class MainActivity extends ActionBarActivity implements
ConnectionCallbacks, OnConnectionFailedListener{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAddress = (TextView) findViewById(R.id.address);
mActivityIndicator =
(ProgressBar) findViewById(R.id.address_progress);
buildGoogleApiClient();
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
@Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
@Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
public void onConnected(Bundle connectionHint) {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}
private class GetAddressTask extends AsyncTask<Location, Void, String>
{
Context mContext;
public GetAddressTask(Context context) {
super();
mContext = context;
}
@Override
protected String doInBackground(Location... params) {
Geocoder geocoder =
new Geocoder(mContext, Locale.getDefault());
// Get the current location from the input parameter list
Location loc = params[0];
// Create a list to contain the result address
List<Address> addresses = null;
try {
addresses = geocoder.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
} catch (IOException e1) {
Log.e("LocationSampleActivity",
"IO Exception in getFromLocation()");
e1.printStackTrace();
return ("IO Exception trying to get address");
} catch (IllegalArgumentException e2) {
// Error message to post in the log
String errorString = "Illegal arguments " +
Double.toString(loc.getLatitude()) +
" , " +
Double.toString(loc.getLongitude()) +
" passed to address service";
Log.e("LocationSampleActivity", errorString);
e2.printStackTrace();
return errorString;
}
// If the reverse geocode returned an address
if (addresses != null && addresses.size() > 0) {
// Get the first address
Address address = addresses.get(0);
/*
* Format the first line of address (if available),
* city, and country name.
*/
String addressText = String.format(
"%s, %s, %s",
// If there's a street address, add it
address.getMaxAddressLineIndex() > 0 ?
address.getAddressLine(0) : "",
// Locality is usually a city
address.getLocality(),
// The country of the address
address.getCountryName());
// Return the text
return addressText;
} else {
return "No address found";
}
}
@Override
protected void onPostExecute(String address) {
// Set activity indicator visibility to "gone"
mActivityIndicator.setVisibility(View.GONE);
// Display the results of the lookup.
mAddress.setText(address);
}
}
public void getAddress(View v) {
// Ensure that a Geocoder services is available
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.GINGERBREAD
&&
Geocoder.isPresent()) {
// Show the activity indicator
mActivityIndicator.setVisibility(View.VISIBLE);
/*
* Reverse geocoding is long-running and synchronous.
* Run it on a background thread.
* Pass the current location to the background task.
* When the task finishes,
* onPostExecute() displays the address.
*/
(new GetAddressTask(this)).execute(mLastLocation);
}
}