2015-04-24 110 views
1

所以,也许有一点Square Square的OkHttp库Android的经验稍多一点的人可以向我解释到底发生了什么。我理解UI线程的概念和对Web的异步请求,以免混乱UI线程。我的问题是,为什么我的代码在收到响应之前进行响应?我该如何解决这个问题?尽管这里是我的代码,但出于安全原因,我将忽略我所调用的实际URL,但它应该返回的响应也会在下面发布。现在异步检索JSON数据

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; 
    } 
} 

,返回的JSON应如下: “嘘”

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

总之,每当我与onClickListener(),我得到的点击按钮Toast弹出窗口,但几乎直接在logcat中,我看到我收到了JSON,当我在将mJSONData设置为null之前放置一个断点时,第一次按下按钮时什么都没有,但是在按下按钮第二次(并通过调试器循环)JSON现在已被存储到String中,之后它通常会导致我的应用程序崩溃(在将它煮沸并简单检查它是否为空之前)。

谢谢任何​​花时间和精力来帮助我理解到底发生了什么以及我能做些什么来改变它的人。

+0

考虑使用改进与OkHttp一起:https://github.com/square/retrofit –

回答

0

只是按下按钮后弹出进度。并在您的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); 
       } 

//你的活动或片段应该实现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();

您还应该检查一个名为observer的设计模式。

+0

不会骗你,不完全理解你的意思。我还没有使用过Java接口,你可以添加一个快速编辑来解释这将如何解决这个问题?这将如何阻止APICall返回空字符串并等待应用更改? –

+0

你的实现atm是错误的,因为你正在做异步工作,并且在你启动它之后,你正在等待一个结果。这是不可能的,因为它需要时间来连接/获取数据等。这就是为什么你必须使用回调接口。 – Klawikowski

+0

好吧,我明白你的意思了。现在,如果这不是问题,你能简单地解释一下回调接口如何阻止它吗?我明白你的意思是期待一个没有被检索到的结果,但是界面是否强制应用程序等待“回调”已经建立并被证明是成功的? –