我有一个选项菜单项,允许用户使用意图在 Google地图上查看其当前位置(基于邮政编码)。由于Google地图仅接受Lat / Lng,因此我使用地理编码API 以 JSON 格式返回Lat / Lng。以下是用户选择菜单项后执行的代码:
MainActivity.java
@Override public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
Intent in = new Intent(this, SettingsActivity.class);
startActivity(in);
return true;
}
if (id == R.id.action_map) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String location = prefs.getString(getString(R.string.pref_location_key),
getString(R.string.pref_location_default));
FetchZipTask fzt = new FetchZipTask();
fzt.execute(location);
loc = fzt.locale;
Uri geoLocation = Uri.parse("geo:"+ loc);
Log.d("Debug", geoLocation.toString());
Intent in = new Intent(Intent.ACTION_VIEW);
in.setData(geoLocation);
if (in.resolveActivity(getPackageManager()) != null) {
startActivity(in);
}
}
return super.onOptionsItemSelected(item);
}
我目前正在尝试使用 AsyncTask 类中的公共字符串字段,当onPostExecute()
方法解析 JSON 并格式化检索到的Lat时,该字段会更新/ Lng字符串。然后,只要用户选择菜单项,我就会从 MainActivity 类访问此公共字段,但该字段始终为null。我做错了什么,是否是利用 AsyncTask 的最有效方式?我认为必须有一个更好的方法来返回价值。
FetchZipTask.java
public class FetchZipTask extends AsyncTask<String, Void, String> {
public String locale = null;
@Override protected void onPostExecute(String result) {
locale = result;
}
@Override protected String doInBackground(String... params) {
if (params.length == 0) {
return null;
}
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
//raw JSON response as a string
String locationJsonStr = null;
try {
final String BASE_LOCATION_URL =
"https://maps.googleapis.com/maps/api/geocode/json?";
final String ADDRESS_PARAM = "address";
final String APPID_PARAM = "key";
// URI.path vs URI.parse vs. URI Scheme
Uri builtUri = Uri.parse(BASE_LOCATION_URL)
.buildUpon()
.appendQueryParameter(ADDRESS_PARAM, params[0])
.appendQueryParameter(APPID_PARAM, BuildConfig.GOOGLE_GEOCODE_API_KEY)
.build();
//Log.d("Debug", builtUri.toString());
URL url = new URL(builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// buffer for debugging.
line.concat(" Hello ");
line.concat("\n");
buffer.append(line);
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
locationJsonStr = buffer.toString();
Log.v("debug", "Location string: " + locationJsonStr);
} catch (IOException e) {
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("ForecastFragment", "Error closing stream", e);
}
}
}
try {
return getLocationDataFromJson(locationJsonStr);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private String getLocationDataFromJson(String forecastJsonStr) throws
JSONException {
// These are the names of the JSON objects that need to be extracted.
final String GEO_LIST = "results";
final String GEO_OBJ = "geometry";
final String GEO_LOC = "location";
final String GEO_LAT = "lat";
final String GEO_LNG = "lng";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray resultsArray = forecastJson.getJSONArray(GEO_LIST);
JSONObject resultsObj = resultsArray.getJSONObject(0);
JSONObject geoObj = resultsObj.getJSONObject(GEO_OBJ);
JSONObject latLng = geoObj.getJSONObject(GEO_LOC);
String lat = latLng.getString(GEO_LAT);
String lng = latLng.getString(GEO_LNG);
Log.d("location", "Lat:" + lat + "\n Lng:" + lng);
return lat + "," + lng;
}
}
答案 0 :(得分:2)
AsyncTask
被称为异步。
在以下代码中,您执行AsyncTask
,然后立即尝试访问其中一个字段:
FetchZipTask fzt = new FetchZipTask();
fzt.execute(location);
loc = fzt.locale;
这不起作用,因为当您尝试访问其FetchZipTask
变量时,locale
可能仍在运行。
onPostExecute()
,因此您应该从那里传递结果。
您可以在FetchZipTask
中定义一个接口,将其实例作为构造函数参数传递,并在onPostExecute()
中调用该实例上的相应方法:
public class FetchZipTask extends AsyncTask<String, Void, String> {
// declaring a listener instance
private OnFetchFinishedListener listener;
// the listener interface
public interface OnFetchFinishedListener {
void onFetchFinished(String result);
}
// getting a listener instance from the constructor
public FetchZipTask(OnFetchFinishedListener listener) {
this.listener = listener;
}
// ...
// calling a method of the listener with the result
@Override protected void onPostExecute(String result) {
listener.onFetchFinished(result);
}
}
在Activity
中,在实例化OnFetchFinishedListener
时传递AsyncTask
:
new FetchZipTask(new FetchZipTask.OnFetchFinishedListener() {
@Override
public void onFetchFinished(String result) {
// do whatever you want with the result
Uri geoLocation = Uri.parse("geo:"+ result);
Log.d("Debug", geoLocation.toString());
Intent in = new Intent(Intent.ACTION_VIEW);
in.setData(geoLocation);
if (in.resolveActivity(getPackageManager()) != null) {
startActivity(in);
}
}
}).execute();
就是这样。方向更改可能仍然存在问题,因此您可以将AsyncTask
移至无头Fragment
,或者考虑使用Service
。