实施Retrofitcallback重新创build活动的最佳做法?

我正在切换到Retrofit并试图理解使用asynchronouscallback的正确体系结构。

例如我有一个接口:

interface RESTService{ @GET("/api/getusername") void getUserName(@Query("user_id") String userId, Callback<Response> callback); } 

我从主要活动中运行:

 RestAdapter restAdapter = new RestAdapter.Builder() .setServer("WEBSITE_URL") .build(); RESTService api = restAdapter.create(RESTService.class); api.getUserName(userId, new Callback<Response> {...}); 

然后用户旋转设备,我有新创build的活动…这里发生了什么? 我怎样才能得到新的活动的回应(我认为后台的api调用会比第一个活动的执行时间长)。 也许我必须使用callback的静态实例或什么? 请给我看看正确的方法

对于潜在的长时间运行的服务器调用,我使用一个AsyncTaskLoader 。 对我来说,装载机的主要优点是活动生命周期处理。 只有在您的活动对用户可见的情况下才会调用onLoadFinished 。 装载机也在活动/片段和方向变化之间共享。

所以我创build了一个ApiLoader,它在loadInBackground中使用改进的同步调用。

 abstract public class ApiLoader<Type> extends AsyncTaskLoader<ApiResponse<Type>> { protected ApiService service; protected ApiResponse<Type> response; public ApiLoader(Context context) { super(context); Vibes app = (Vibes) context.getApplicationContext(); service = app.getApiService(); } @Override public ApiResponse<Type> loadInBackground() { ApiResponse<Type> localResponse = new ApiResponse<Type>(); try { localResponse.setResult(callServerInBackground(service)); } catch(Exception e) { localResponse.setError(e); } response = localResponse; return response; } @Override protected void onStartLoading() { super.onStartLoading(); if(response != null) { deliverResult(response); } if(takeContentChanged() || response == null) { forceLoad(); } } @Override protected void onReset() { super.onReset(); response = null; } abstract protected Type callServerInBackground(SecondLevelApiService api) throws Exception; } 

在你的活动中,你可以像这样初始化这个loader:

 getSupportLoaderManager().initLoader(1, null, new LoaderManager.LoaderCallbacks<ApiResponse<DAO>>() { @Override public Loader<ApiResponse<DAO>> onCreateLoader(int id, Bundle args) { spbProgress.setVisibility(View.VISIBLE); return new ApiLoader<DAO>(getApplicationContext()) { @Override protected DAO callServerInBackground(ApiService api) throws Exception { return api.requestDAO(); } }; } @Override public void onLoadFinished(Loader<ApiResponse<DAO>> loader, ApiResponse<DAO> data) { if (!data.hasError()) { DAO dao = data.getResult(); //handle data } else { Exception error = data.getError(); //handle error } } @Override public void onLoaderReset(Loader<ApiResponse<DAO>> loader) {} }); 

如果要多次请求数据,请使用restartLoader而不是initLoader

我一直在我的Android应用程序中使用一种MVP(ModelViewPresenter)实现。 对于Retrofit请求,我让Activity调用了它的相应Presenter,这个Presenter又创build了Retrofit Request,并且作为一个参数,我发送了一个附有自定义Listener的Callback(由演示者实现)。 当callback到达onSuccessonFailure方法时,我调用Listener的相应方法,调用Presenter,然后调用Activity方法:P

现在,如果屏幕转动,当我的活动重新创build它附加到演示者。 这是通过使用Android应用程序的自定义实现来完成的,在该应用程序中保留演示者的实例,并根据Activity的类使用映射来恢复正确的演示者。

我不知道如果这是最好的方式,也许@pareshgoel答案更好,但它一直在为我工作:D

例子:

 public abstract interface RequestListener<T> { void onSuccess(T response); void onFailure(RetrofitError error); } 

 public class RequestCallback<T> implements Callback<T> { protected RequestListener<T> listener; public RequestCallback(RequestListener<T> listener){ this.listener = listener; } @Override public void failure(RetrofitError arg0){ this.listener.onFailure(arg0); } @Override public void success(T arg0, Response arg1){ this.listener.onSuccess(arg0); } } 

在演示者的某个地方实现监听器,在overrode方法上调用一个演示者的方法来调用Activity。 并随时随地打电话给主持人,启动一切:P

 Request rsqt = restAdapter.create(Request.class); rsqt.get(new RequestCallback<YourExpectedObject>(listener)); 

希望它可以帮助你。

首先,你的活动在这里泄漏,因为这一行:api.getUserName(userId,new Callback {…})创build一个匿名的Callback类,它拥有强大的MainActivity引用。 在调用Callback之前旋转设备时,MainActivity不会被垃圾收集。 根据您在Callback.call()中所做的操作,您的应用程序可能会产生未定义的行为。

处理这种情况的一般想法是:

  1. 切勿创build非静态的内部类(或问题中提到的匿名类)。
  2. 相反,创build一个静态类来保存一个WeakReference <>到Activity / Fragment。

以上只是防止泄漏。 它仍然无法帮助您将“改造”调用回您的“活动”。

现在,即使在configuration更改之后,为了将结果返回到组件(在您的案例中为Activity),您可能需要使用附加到您的Activity的无头残留片段,从而调用Retrofit。 阅读更多关于保留片段 – http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean);

一般的想法是,片段自动附加到configuration更改的活动。

我强烈build议你观看在Google I / O上给出的video 。

它讨论了如何通过将服务委托给一个服务来创buildREST请求(这几乎不会被终止)。 当请求完成后,它会立即存储到Android的内置数据库中,以便在Activity准备就绪时立即可用数据。

通过这种方法,您不必担心活动的生命周期,并且您的请求将以更加分离的方式进行处理。

video没有具体谈到改造,但你可以很容易地适应这种范式的改造。

使用Retrofit2处理方向更改。 我在求职面试中被问到这个问题,当时因为不知道而被拒绝了,但现在是这样。

 public class TestActivity extends AppCompatActivity { Call<Object> mCall; @Override public void onDestroy() { super.onDestroy(); if (mCall != null) { if (mCall.isExecuted()) { //An attempt will be made to cancel in-flight calls, and // if the call has not yet been executed it never will be. mCall.cancel(); } } } } 

使用Robospice

您的应用程序中需要数据的所有组件都注册到spice服务。 该服务负责将您的请求发送到服务器(如果需要,可以通过改装)。 当响应返回时,所有注册的组件都会得到通知。 如果其中有一个不可用(比如由于轮换而被踢的活动),则只是没有通知。

好处:无论您是否旋转设备,打开新的对话框/片段等等,都不会丢失一个请求。

当我是一个新手改造时,我从这些网站学到了最好的方法

消费api与改造

翻新教程

这是这种解决scheme的典型限制,默认情况下,Android在用户旋转设备时创build一个新的活动。

但是,这种情况下有一个简单的解决方法,configuration方向侦听器。 完成此操作后,Android不会创build新的活动。

  <activity ... android:configChanges="orientation" /> 

解决这个问题的其他方法是使用Robospice等其他框架进行改造。