【问题标题】:Is there a way to reuse builder code for retrofit有没有办法重用构建器代码进行改造
【发布时间】:2014-01-01 23:17:31
【问题描述】:

我正在使用Retrofit,在每项任务中我都必须这样做:

public class MyTask extends AsyncTask<String, String, String> {

    private void someMethod() {
        final RestAdapter restAdapter = new RestAdapter.Builder()
            .setServer("http://10.0.2.2:8080")
            .build();
        final MyTaskService apiManager = restAdapter.create(MyTaskService.class);
    }

    // ...

}

什么是让这段代码干燥的好方法?

【问题讨论】:

  • 你从哪里得到RestAdapter?我可以知道吗?
  • DRY 是什么意思?
  • 你可以使用一些继承概念
  • @Husyn,DRY 代表 Don't Repeat Yourself

标签: java android retrofit


【解决方案1】:

首先你声明你的父类具有所有常见的行为

public abstract class MyAbstractTask extends AsyncTask<String, String, String> {

 protected void someMethod() { //note that i change private to protected
  final RestAdapter restAdapter = new RestAdapter.Builder().setServer("http://10.0.2.2:8080").build();
  final MyTaskService apiManager = restAdapter.create(MyTaskService.class);
 }

}

然后,你用每个任务扩展它

public   class MyTask extends MyAbstractTask {

 //your someMethod() is available from everywhere in your class

}

public  class MyOtherTask extends MyAbstractTask {

 //your someMethod() is available from everywhere in your class

}

但我不知道您在哪里使用 restAdapter 和 apiManager,以及是否实际需要为每个任务创建一次,因为您可能可以在这些任务之外创建它。

如果你在外部创建它们,然后你需要在你的任务中使用一些东西,记住Dependency_injection 模式也是很好的。


此外,您应该避免在类中硬编码值,例如 http://10.0.2.2:8080

您应该至少使用final static final String server= "http://10.0.2.2:8080",然后使用它,或者更好的是,在最内部的类中使用setter 或构造函数,并从活动或主控制器设置tha 值。

【讨论】:

    【解决方案2】:

    RestAdapter 和生成的服务实例(在本例中为 MyTaskService)都是非常昂贵的对象,应该用作单例。

    这意味着您应该只调用一次restAdapter.create,并在每次需要与之交互时重复使用MyTaskService 的同一个实例。

    我怎么强调都不过分。

    您可以使用常规的单例模式,以确保您在任何地方都只使用这些对象的一个​​实例。依赖注入框架也可以用来管理这些实例,但如果你还没有使用它,那就有点矫枉过正了。

    【讨论】:

    • 感谢您的回复。我对创建调用进行了基准测试,该调用在改造中使用代理类来使用“newProxyInstance”创建请求实例。我在一个设备(运行 4.4 的 Nexus 5)上为一个定义了 1 到 4 个不同复杂度的服务方法的接口做了这个。第一次需要 4-5 毫秒,而在同一运行中,每次后续时间需要 0.3 到 0.5 毫秒。也许我不明白这一点,但你有理由认为这很贵吗? Android是否也在第一次之后缓存创建?只是想弄清楚,仅此而已
    • 它的运行速度并不昂贵,而是在内存方面。每个 RestAdapter 占用大量内存,这就是为什么这里需要单例的原因,因为这样你一次只有一个副本在内存中。您发出 10 个请求的图像,更不用说 100 个请求了,每个请求都有自己的 RestAdapter。垃圾收集器无法足够快地清理它们,这样做很容易耗尽内存。 Android 没有缓存这个,但你可以很容易地使用Singletons
    • @JakeWharton 还是这样吗?我刚刚创建了 100 个 RestAdapter,没有显着增加内存。
    • @Eugene 是的,它仍然很贵。您可能不会注意到其中的 100 个。但是,如果您将这些物品与一些日常丢弃的物品进行比较,您会发现它的价格要高出数百到数百万。该类也被设计为可重用。它是线程安全的,可以进行延迟加载和缓存,并且在优化重用案例方面做了很多工作。这就像每天买新袜子而不是洗它们一样。你可以侥幸逃脱,但这没有任何意义。
    • @jake-wharton 这对 Retrofit 2 仍然有效吗?
    【解决方案3】:

    正如 Jake 所说,您应该使用 singleton pattern 以确保始终使用相同的实例。

    这是一个例子:

    public class ApiManager {
    
        public interface GitHubService {
    
            @GET("/users/{user}/repos")
            List<Repo> listRepos(@Path("user") String user);
    
        }
    
        private static final String API_URL = "https://api.github.com";
    
        private static final RestAdapter REST_ADAPTER = new RestAdapter.Builder()
            .setEndpoint(API_URL)
            .setLogLevel(LogLevel.FULL)
            .build();
    
        private static final GitHubService GIT_HUB_SERVICE = REST_ADAPTER.create(GitHubService.class);
    
        public static GitHubService getService() {
            return GIT_HUB_SERVICE;
        }
    }
    

    您可以像这样使用此示例中的服务:

    ApiManager.getService().listRepos(...);
    

    【讨论】:

    • @Gautham 对于每个请求我必须使用不同的转换器。如何用作单例?
    • @Asthme 为什么要为每个请求使用不同的 addConverterFactory?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多