尝试首先执行 Retrofit onResponse

Trying to get Retrofit onResponse executed first

我的 activity 中名为 AllStores 的列表仅包含空值。我需要这个列表,因为我想稍后填充我的 ListView。问题是因为我的回调最后执行了。

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

Link: 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

屏幕截图看起来与上面的屏幕截图相同。

我认为您最好让 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;
}

...最后,这是我的测试 activity: public class 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> 作为 activity 的普通成员变量进行操作应该很简单。

希望对您有所帮助。

为了将结果从后台线程获取到主线程,我不得不使用 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
    }
}