当前位置: 首页 > 知识库问答 >
问题:

Android Volley同步请求不工作

濮阳景天
2023-03-14

我试图使用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组织。json。J主题。com上的null对象引用上的toString()。数学应用程序。所有模块。在com上获取模块(AllModules.java:85)。数学应用程序。所有模块。android上的onCreateView(AllModules.java:51)。支持v4.app。碎片android上的performCreateView(Fragment.java:2080)。支持v4.app。碎片管理。android上的moveToState(FragmentManager.java:1108)。支持v4.app。碎片管理。android上的moveToState(FragmentManager.java:1290)。支持v4.app。回溯记录。在android上运行(backbackrecord.java:801)。支持v4.app。碎片管理。android上的ExependingActions(FragmentManager.java:1677)。支持v4.app。FragmentManagerImpl 1美元。在android上运行(FragmentManager.java:536)。操作系统。处理程序。android上的handleCallback(Handler.java:746)。操作系统。处理程序。android上的dispatchMessage(Handler.java:95)。操作系统。活套。android上的loop(Looper.java:148)。应用程序。活动线程。java上的main(ActivityThread.java:5443)。郎。反思。方法在com上调用(本机方法)。Android内部的操作系统。ZygoteInit$MethodandArgscaler。在com上运行(ZygoteInit.java:728)。Android内部的操作系统。合子岩。main(ZygoteInit.java:618)

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

共有3个答案

酆耀
2023-03-14

在我自己研究了这个问题之后,你不能(在写作的时候)在主线中这样做

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

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

侯博易
2023-03-14

我们可以使用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());
        }
    });

在主活动

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() {

                }
            });
谷梁永年
2023-03-14

你被试抓欺骗了

说明:因为Request estFuture.get()可能在UI线程上运行,所以您实际上在幕后得到了java.util.concurrent.TimeoutException。这是调用在主线程上执行时的默认行为。

try catch阻止应用程序崩溃,但响应仍然是一个空引用,当您尝试Log结果时会使应用程序崩溃。如果您评论以下行,您将看到应用程序不再崩溃(那里)。

日志d(TAG,response.toString());

修复:在另一个线程上进行RequestFuture网络调用!

一种方法是:

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

将进行网络调用的异步任务:

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"},[...]

希望这有帮助

干杯

 类似资料:
  • 问题内容: 同步请求和异步请求之间的性能(速度方面)是否有差异? 使用异步请求的所有原因是什么? 问题答案: 您应该始终使用异步Ajax请求,实际上,我只知道应该使用同步Ajax请求的一个地方,即您是否在Ajax请求中,将新的JavaScript文件嵌入客户端,然后引用类型和/或原始Ajax请求返回的JavaScript文件中的对象。然后,应该(或可以理智地)通过使用同步Ajax请求包括对这个新J

  • 本文向大家介绍详解XMLHttpRequest(一)同步请求和异步请求,包括了详解XMLHttpRequest(一)同步请求和异步请求的使用技巧和注意事项,需要的朋友参考一下 XMLHttpRequest 让发送一个HTTP请求变得非常容易。你只需要简单的创建一个请求对象实例,打开一个URL,然后发送这个请求。当传输完毕后,结果的HTTP状态以及返回的响应内容也可以从请求对象中获取。  通过XML

  • 本文向大家介绍全面解析iOS中同步请求、异步请求、GET请求、POST请求,包括了全面解析iOS中同步请求、异步请求、GET请求、POST请求的使用技巧和注意事项,需要的朋友参考一下 先给大家分别介绍下iOS中同步请求、异步请求、GET请求、POST所代表的意思,然后在逐一通过实例给大家介绍。 1、同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进

  • 下面的代码我得到当我使用异步.当我使用同步时,它成功了。 链接失败,但在异步和同步情况下都成功。 出什么事了?这是在Python3.4中实现的。2在FreeBSD8上,aiohttp 0.14。4,请求2.5。3. 此操作的输出为:

  • 问题内容: 如果我需要按顺序调用3 http API,那么以下代码将是更好的选择: 问题答案: 使用像这样的延期。 如果您需要传递范围,则只需执行以下操作

  • 这个练习直接来自SCJP,由凯西·塞拉和伯特·贝茨完成 同步代码块 在这个练习中,我们将尝试同步一个代码块。在该代码块中,我们将获得对象的锁,以便其他线程在代码块执行时无法修改它。我们将创建三个线程,它们都将尝试操作同一对象。每个线程将输出一个字母100次,然后将该字母递增一次。我们将使用的对象是StringBuffer。 我们可以在一个String对象上进行同步,但是字符串一旦创建就不能被修改,