试图首先执行Retrofit onResponse

时间:2015-12-17 23:30:42

标签: java android retrofit synchronous

我名为AllStores的活动中的列表仅包含null。我需要这个列表,因为我想稍后填充我的ListView。问题是由于我的回调是最后执行而引起的。

为了澄清我在下面做了一个截图:

链接:http://i.imgur.com/bIkWjld.png

屏幕截图还说明了我真正想要的内容。为了达到这个目的,我尝试了AsyncTask。然而,正如您在屏幕截图中看到的那样,它没有成功。

以下是代码:

EDIT 2.0我已将getSubprise()方法更改为同步并使用AsyncTask

AllStores.java:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Response<List<Store>> subprises = new StoreService().getSubprises();
    System.out.println("AllStores (Activity) - subprise " + subprises);
}

StoreService.java:

       public Response<List<Store>> getSubprises() {
        new LongOperation().execute("");
        System.out.println("getStores (StoreService.java) value "+ getStores());
        return getStores();
    }

    private class LongOperation extends AsyncTask<String, Void, Response<List<Store>>> {

        @Override
        protected Response<List<Store>> doInBackground(String... params) {
            System.out.println("doInBackground executed second");
            try {
                Call<List<Store>> call = subpriseAPI.listStores();
                stores=call.execute();
                Iterator it=stores.body().iterator();
//                while(it.hasNext())
//                    System.out.println(((Store)it.next()).getSTREET());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return stores;
        }

        @Override
        protected void onPreExecute() {
            //Can't put the call here because this is the main thread
            System.out.println("onPreExecute first");
        }

        @Override
        protected void onPostExecute(Response<List<Store>> result) {
            //Can't put the call here because this is the main thread
            setStores(stores);
        }
    }

    public Response<List<Store>> getStores() {
        return stores;
    }

    public void setStores(Response<List<Store>> stores) {
        this.stores = stores;
    }

但是我现在仍然得到相同的结果,请参阅下面的屏幕截图:

link:http://i.imgur.com/GOGFXMR.png

屏幕截图与上面的屏幕截图相同。

2 个答案:

答案 0 :(得分:1)

要将后台线程的结果传递给主线程,我必须使用AsyncTask.get()。通过使用它我可以在我的stores变量中看到一个值而不是一个空值。

您可以在下面看到我想要查看的代码:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public Response<List<Store>> getSubprises() throws IOException, ExecutionException, InterruptedException {
    LongOperation longOperation = new LongOperation();
    longOperation.execute("");
    stores = longOperation.get();
    return stores;
}

private class LongOperation extends AsyncTask<String, Void, Response<List<Store>>> {
    @Override
    protected Response<List<Store>> doInBackground(String... params) {
        //System.out.println("doInBackground executed second");
        try {
            Call<List<Store>> call = subpriseAPI.listStores();
            stores=call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stores;
    }

    @Override
    protected void onPreExecute() {
        //Can't put the call here because this is the main thread
        //System.out.println("onPreExecute first");
    }

    @Override
    protected void onPostExecute(Response<List<Store>> result) {
        //Can't put the call here because this is the main thread
    }
}

答案 1 :(得分:0)

我认为让Retrofit在其内部HTTP执行程序内部调用调用会更好。这将涉及将您的API接口更改为以下内容:

public interface SubpriseAPI {
    @GET("api/locations/get")
    List<Store> listStores();
}

...并包含Retrofit的任何相关配置,以便将反序列化处理为Store类型。

但是,如果你想自己调用这些调用,你可以考虑托管你自己的执行器实例(或者你想运行你的工作线程),就像这样(不是这个确切的实现,但你应该明白) :

class StoreService {
...
private final ExecutorService executorService = Executors.newCachedThreadPool();
...
public Response<List<Store>> getSubprises() {
  executorService.submit(new Callable<List<Store>>() {
            @Override
            public List<Store> call() throws Exception {
                final Call<List<Store>> call = subpriseAPI.listStores();

                try {
                    if(stores == null) {
                        stores = new ArrayList<>();
                    } else {
                        stores.clear();
                    }

                    stores.addAll(call.execute());

                    System.out.println("stores "+ stores);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).get();
...

<强>更新

我没有意识到你(显然)正在使用Retrofit 2.我有机会尝试一下,这就是我想出来的。

这是我在app / build.gradle中的相关依赖项:

compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'

...这是我的API界面:

public interface Api {
    @Headers("Accept: application/json")
    @GET("/v2/567595ad0f0000ea23315d02")
    public Call<List<Widget>> widgets();

}

...这是一个简单的DTO,我将把一些JSON解组为:

public class Widget {
    public String value;
}

...最后,这是我的测试活动: 公共类Retrofit2TestActivity扩展了AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Api mockyApi = new Retrofit.Builder()
            .baseUrl("http://www.mocky.io")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(Api.class);

        mockyApi.widgets().enqueue(new Callback<List<Widget>>() {
            @Override
            public void onResponse(Response<List<Widget>> response, Retrofit retrofit) {
                if(response.isSuccess()) {
                    Log.d(Retrofit2TestActivity.class.getName(), "## widgets.size() == " + response.body().size());
                } else {
                    Log.d(Retrofit2TestActivity.class.getName(), String.format("## response was NOT successful [%d]", response.code()));
                }
            }

            @Override
            public void onFailure(Throwable t) {
                Log.d(Retrofit2TestActivity.class.getName(), String.format("## response was NOT successful [%s]", t.getMessage()));
            }
        });
    }

}

显然,您应该将Widget替换为Store类型。除此之外,操纵List<Store>作为活动的正常成员变量应该是直截了当的。

我希望有所帮助。