异步检索 JSON 数据

Retrieving JSON data asynchronously

所以,也许对 Android 的 Square 的 OkHttp 库有更多经验的人能够向我解释到底发生了什么。我了解 UI 线程的概念和对网络的异步请求,以免弄乱 UI 线程。我的问题是,为什么我的代码在收到响应之前就响应了?我该如何解决这个问题?这是我的代码,不过,出于安全原因,我将省略我正在调用的实际 URL,但它应该 return 的响应也会发布在下面。

package com.example.jeffrey.yetiagenda.ui;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.jeffrey.yetiagenda.R;
import com.example.jeffrey.yetiagenda.api.API;
import com.example.jeffrey.yetiagenda.api.User;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import org.json.JSONException;

import java.io.IOException;

import butterknife.ButterKnife;
import butterknife.InjectView;


public class YetiAgenda extends Activity {

    public static final String TAG = YetiAgenda.class.getSimpleName();

    public String mJSONData;

    @InjectView(R.id.usernameEdit)
    EditText mUsernameEdit;
    @InjectView(R.id.passwordEdit)
    EditText mPasswordEdit;
    @InjectView(R.id.loginButton)
    Button mLoginButton;
    @InjectView(R.id.invalidLoginText)
    TextView mInvalidLoginText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_yeti_agenda);

        ButterKnife.inject(this);

        mInvalidLoginText.setVisibility(View.INVISIBLE);

        //if login is successful, pass id of user to next activity to construct
        mLoginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    mJSONData = null; // for debugging, read below
                    if (APICall("(removed for security reasons)")) {
                        hoorayToast();
                    } else {
                        booToast();
                    }

                } catch (JSONException e) {
                    Log.e(TAG, "Exception caught:", e);
                }
           }
        });
    }

    public void hoorayToast() {
        Toast.makeText(this, "Hooray!",
                Toast.LENGTH_LONG).show();
    }

    public void booToast() {
        Toast.makeText(this, "Boo!",
                Toast.LENGTH_LONG).show();
    }

    public void toggleInvalidText() {
        if (mInvalidLoginText.getVisibility() == View.VISIBLE) {
            mInvalidLoginText.setVisibility(View.INVISIBLE);
        } else {
            mInvalidLoginText.setVisibility(View.VISIBLE);
        }
   }

    public boolean APICall(String url) throws JSONException{
       // unnecessary finagling Android Studio suggested

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url).build();

        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                // alertUserAboutError();
                Log.e(TAG, "Exception caught:", e);
            }

            @Override
            public void onResponse(Response response) throws IOException {
                try {
                    mJSONData = response.body().string();
                    Log.v(TAG,response.body().string());
                    Log.v(TAG, mJSONData);
                    if (response.isSuccessful()) {
                        // Signal that response was successful
                    } else {
                        // alertUserAboutError();
                    }
                }
                catch (IOException e) {
                    Log.e(TAG, "Exception caught:", e);
                }
            }
        });
        if (mJSONData != null) return true;
        else return false;
    }
}

现在,returned JSON 应该如下所示:

{"logIn":true,"id":"5","userType":"1"}

总而言之,每当我点击带有 onClickListener() 的按钮时,我都会收到 "Boo!" Toast 弹出窗口,但几乎紧接着,在 logcat 中,我看到我收到了JSON,当我在将 mJSONData 设置为 null 之前放置一个断点时,我第一次按下按钮时什么也没有,但是在我第二次按下按钮之后(并循环返回)调试器)JSON 现在已存储到字符串中,因为它通常会导致我的应用程序崩溃(在将其煮沸并简单地检查它是否为 null 之前)。

感谢所有花时间和精力帮助我了解到底发生了什么以及我可以做些什么来改变它的人。

按下按钮后简单地弹出进度。并在 onResponse 方法中使用回调接口。 快速草稿示例:

interface ApiCallCallback
{
void onSuccess(//RESPONSE);
void onError(String pErrorMessage);
}

public boolean APICall(String url, final ApiCallCallback pCallback)
...
@Override 
            public void onResponse(Response response) throws IOException {
                try { 
                    mJSONData = response.body().string();
                    Log.v(TAG,response.body().string());
                    Log.v(TAG, mJSONData);
                    if (response.isSuccessful()) {
                         pCallback.onSuccess(//RESPONSE);
                        // Signal that response was successful 
                    } else { 
                         pCallback.onError(//ERROR);
                        // alertUserAboutError(); 
                    } 
                } 
                catch (IOException e) {
                    Log.e(TAG, "Exception caught:", e);
                } 

//您的 activity 或片段应该实现 ApiCallCallback

mLoginButton.setOnClickListener(new View.OnClickListener() {
            @Override 
            public void onClick(View v) {
                try { 
                    mJSONData = null; 
                   //just run apicall to start data receive
                   APICall("(removed for security reasons)", this)) 
                } catch (JSONException e) {
                    Log.e(TAG, "Exception caught:", e);
                } 
           } 
        }); 

当 APICall 将调用任何接口侦听器时,这意味着数据已准备就绪,您可以使用它或出现问题。

onSuccess(); OnError();

您还应该检查称为观察者的设计模式。