我有一个使用android上的okhttp库调用外部API的方法,我能够访问该方法/线程中返回的数据,但无法返回该数据或在其他地方使用它。有什么问题吗?
我尝试将数据放入另一个类(从AsyncTask扩展),但仍然无法正常工作。
public class DisplayImage extends AppCompatActivity {
ImageView imageView;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_image);
imageView = findViewById(R.id.mImageView);
textView = findViewById(R.id.textView);
Bitmap bitmap = BitmapFactory.decodeFile(getIntent().getStringExtra("image_path"));
imageView.setImageBitmap(bitmap);
String imagePath = getIntent().getStringExtra("image_path");
try {
//map returned here
HashMap<String, double[]> map = getCropInfo(imagePath);
//This text view doesn't update
textView.setText(String.valueOf(map.get("ID")[0]));
} catch (Exception e) {
e.printStackTrace();
}
}
HashMap getCropInfo(String imageUri) throws Exception {
final HashMap<String, double[]> map = new HashMap<>();
OkHttpClient client = new OkHttpClient();
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/jpg");
File file = new File(imageUri);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("image", file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file))
.build();
Request request = new Request.Builder()
.header("Prediction-Key", "") //predictionkey hidden
.header("Content-Type", "application/octet-stream")
.url("https://westeurope.api.cognitive.microsoft.com/customvision/v3.0/Prediction/7f5583c8-36e6-4598-8fc3-f9e7db218ec7/detect/iterations/Iteration1/image")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
public void onResponse(Call call, final Response response) throws IOException {
// Read data on the worker thread
final String responseData = response.body().string();
// Run view-related code back on the main thread
DisplayImage.this.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
JSONObject jsonObject = new JSONObject(responseData);
JSONArray jsonArray = jsonObject.getJSONArray("predictions");
double highestIDProbability = 0;
double highestVoltageProbability = 0;
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject tempObject = jsonArray.getJSONObject(i);
if(tempObject.getString("tagName").equals("ID") && tempObject.getDouble("probability") > highestIDProbability) {
highestIDProbability = tempObject.getDouble("probability");
map.put("ID", getCoordinatesPixels(tempObject));
}
else if(tempObject.getString("tagName").equals("Voltage") && tempObject.getDouble("probability") > highestVoltageProbability) {
highestVoltageProbability = tempObject.getDouble("probability");
map.put("Voltage", getCoordinatesPixels(tempObject));
}
}
//setting text view works from here.
//textView.setText(String.valueOf(map.get("ID")[0]));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
//I am returning map
return map;
}
static double[] getCoordinatesPixels(JSONObject object) {
double[] arr = new double[4];
try {
JSONObject innerObject = object.getJSONObject("boundingBox");
arr[0] = innerObject.getDouble("left");
arr[1] = innerObject.getDouble("top");
arr[2] = innerObject.getDouble("width");
arr[3] = innerObject.getDouble("height");
} catch (JSONException e) {
e.printStackTrace();
}
return arr;
}
}
我需要返回地图,以便可以在外部使用数据。
答案 0 :(得分:0)
我认为您通常会遇到与OkHttp和网络请求的异步性质有关的问题。进行新呼叫时,该呼叫将排队并异步处理。这意味着代码最有可能在异步调用完成之前之前和之前修改回调,return map;
执行。如果您需要在回调范围之外访问地图,则有两个主要选项。
阻止通话。本质上,这意味着您必须强制该函数停止运行,直到return map;
发生之前,先触发OkHttp回调。我绝对不建议这样做,因为这样做会破坏将长期运行的任务移至其他线程的整个目的。
在onResponse()
回调中调用一个函数。在回调本身内部构造map
,然后仅调用以该映射为参数的函数来处理您需要对该map
进行的任何操作。另外,您也可以将map
设置为全局变量,以便几乎可以从任何地方访问它。
在旁注中,如果要使用此数据将更改传播回UI或其他程序状态,我建议使用ViewModel(这是一个模型对象,可以保存数据,并且可以超出Activity生命周期)与MutableLiveData之类的东西(这是一个数据包装器,基本上可以观察到的东西)配对。
使用这种设置,您可以将map
对象放在ViewModel中。然后,您可以从需要了解map
上的更新的任何上下文(活动,片段等)中注册观察者。最后,在回调中,您只需要更新ViewModel的map
。这会自动通知所有注册的观察员。
祝你好运!