如何将AsyncTask类的值返回到另一个类?

时间:2016-09-03 04:53:54

标签: android android-asynctask

我有一个选项菜单项,允许用户使用意图 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;
}
}

1 个答案:

答案 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

相关问题