Android Volley同步请求无法正常工作

时间:2017-01-18 16:35:50

标签: java android android-volley

我正在尝试使用 RequestFuture 向服务器发出同步请求,但它无效。使用异步完成时相同的请求工作正常。

这是我的代码:

 public void fetchModules(){
   JSONObject response = null;
    RequestQueue requestQueue = Volley.newRequestQueue(getContext());

    RequestFuture<JSONObject> future = RequestFuture.newFuture();
    JsonObjectRequest request = new JsonObjectRequest(Url.ALL_MODULES_URL,null,future,future);
    requestQueue.add(request);


    try {
         response = future.get(3, TimeUnit.SECONDS); // Blocks for at most 10 seconds.
    } catch (InterruptedException e) {
             Log.d(TAG,"interupted");
     } catch (ExecutionException e) {
        Log.d(TAG,"execution");
    } catch (TimeoutException e) {
        e.printStackTrace();
    }

    Log.d(TAG,response.toString());
}

我得到了一个nullpointerexception:

  

java.lang.NullPointerException:尝试在空对象引用上调用虚方法'java.lang.String org.json.JSONObject.toString()'                                                                      在com.maths.app.AllModules.fetchModules(AllModules.java:85)                                                                      在com.maths.app.AllModules.onCreateView(AllModules.java:51)                                                                      在android.support.v4.app.Fragment.performCreateView(Fragment.java:2080)                                                                      在android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1108)                                                                      在android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1290)                                                                      在android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)                                                                      在android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1677)                                                                      在android.support.v4.app.FragmentManagerImpl $ 1.run(FragmentManager.java:536)                                                                      在android.os.Handler.handleCallback(Handler.java:746)                                                                      在android.os.Handler.dispatchMessage(Handler.java:95)                                                                      在android.os.Looper.loop(Looper.java:148)                                                                      在android.app.ActivityThread.main(ActivityThread.java:5443)                                                                      at java.lang.reflect.Method.invoke(Native Method)                                                                      在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:728)                                                                      在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

它返回一个空响应。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:6)

TL;博士; 你被try-catch

欺骗了

说明: 因为java.util.concurrent.TimeoutException可能正在UI线程上运行,所以你真的在幕后获得Log这是在主线程上执行调用时的默认行为。

try catch会阻止应用崩溃,但响应仍为空引用,当您尝试 public class TestVolley { private String TAG = "SO_TEST"; private String url = "http://pokeapi.co/api/v2/pokemon-form/1/"; public JSONObject fetchModules(Context ctx){ JSONObject response = null; RequestQueue requestQueue = Volley.newRequestQueue(ctx); RequestFuture<JSONObject> future = RequestFuture.newFuture(); JsonObjectRequest request = new JsonObjectRequest(url,null,future,future); requestQueue.add(request); try { response = future.get(3, TimeUnit.SECONDS); // Blocks for at most 10 seconds. } catch (InterruptedException e) { Log.d(TAG,"interrupted"); } catch (ExecutionException e) { Log.d(TAG,"execution"); } catch (TimeoutException e) { e.printStackTrace(); } Log.d(TAG,response.toString()); return response; } } 结果时,该应用会崩溃应用。 如果您对以下行发表评论,您将看到应用程序不再崩溃(那里)。

  

Log.d(TAG,response.toString());

修复:让RequestFuture网络在另一个线程上调用

一种方法:

AsyncTask

将进行网络通话的public class MyVolleyAsyncTask extends AsyncTask<String,String, JSONObject> { private Context ctx; public MyVolleyAsyncTask(Context hostContext) { ctx = hostContext; } @Override protected JSONObject doInBackground(String... params) { // Method runs on a separate thread, make all the network calls you need TestVolley tester = new TestVolley(); return tester.fetchModules(ctx); } @Override protected void onPostExecute(JSONObject result) { // runs on the UI thread // do something with the result } }

public class MainActivity extends AppCompatActivity {

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

        // this is your old code which will crash the app
        //TestVolley tester = new TestVolley();
        //tester.fetchModules(this);

        // Works!
        new MyVolleyAsyncTask(this).execute();
    }
}

主要活动:

com.so.henriquems.testvolleyfuture D/SO_TEST: {"id":1,"pokemon":{"url":"http:\/\/pokeapi.co\/api\/v2\/pokemon\/1\/","name":"bulbasaur"},[...]

结果:

<table border="0" cellpadding="0" cellspacing="0" width="100%">
       <tr align="center" valign="middle">
          <td align="center" width="50%" class="column" valign="top" style="text-align:left; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-weight:normal; font-size:16px; color:#44464a; line-height:1.4; padding-top:0px; padding-right:0px; padding-bottom:0px; padding-left:0px;">    <img class="person" src="c29229/c29229_4seasons_photos_2.jpg" alt="photo of people" style="width:300; height:auto; border:0 none; display:block;" />    </td>
          <td align="center" valign="middle" width="50%" class="column" style="text-align:center; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-weight:normal; font-size:16px; color:#ffffff; line-height:1.4; padding-top:0px; padding-right:30px; padding-bottom:0px; padding-left:30px; background-color: #ab811d;">
             <h2 style="text-align:center; font-weight: normal !important; font-size: 24px; color:#ffffff; margin-bottom: 20px !important;">
                <div class="spacer" style="padding-top: 40px; display:none;">&nbsp;</div>
                Complete your beneficiary designation
             </h2>
             <p style="margin-bottom:0px;"><a href="#" style="color:#ffffff; text-decoration:underline;">Vea esta correo electr&oacute;nico en&nbsp;espa&ntilde;ol</a></p>
          </td>
       </tr>
    </table>

希望这有帮助

喝彩!

答案 1 :(得分:1)

我们可以使用RxJava。

让我们假设 fetchModules 方法返回JSONObject

Observable<JSONObject> moduleObservable = Observable.defer(new Callable<ObservableSource<? extends JSONObject>>() {
        @Override
        public ObservableSource<? extends JSONObject> call() throws Exception {
            return Observable.just(fetchModules());
        }
    });

在MainActivity中

moduleObservable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new io.reactivex.Observer<JSONObject>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(JSONObject response) {
                    // Your response is here
                }

                @Override
                public void onError(Throwable e) {
                     showAlert(context, e.getMessage());
                }

                @Override
                public void onComplete() {

                }
            });

答案 2 :(得分:0)

在我自己研究这个问题后,你不能(在写作的那一刻)在主线程中做到这一点

我希望Volley在主线程中完成它,因为我需要阻止直到Volley完成响应。这是不可能的,Volley上的同步请求必须在异步线程中,而不是在主线程中。

我所做的工作是,在Volley请求的onResponse方法中执行后续代码