【问题标题】:How and where to make the Retrofit call?如何以及在哪里进行改造电话?
【发布时间】:2018-07-01 17:36:25
【问题描述】:

我是一名初级 Android 开发人员,试图通过构建电影数据库应用来学习移动开发。我正在用 Kotlin 编写我的应用程序,并使用 Retrofit 进行网络调用。我不知道如何以及在何处调用以使用来自 tmdb API 的电影海报填充 Recyclerview。

这是我的界面:

interface APImovies {
    fun getMovies()
}

这是我的改造服务器对象的主要活动:

class MainActivity() : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val recyclerView = findViewById<RecyclerView>(R.id.recycler_view);
        recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        recyclerView.layoutManager = GridLayoutManager(this, 3);
        recyclerView.adapter = PosterAdapter()
    }

    object RetrofitServer{
        val client: APImovies by lazy{
            val client = OkHttpClient.Builder().build()
            val retrofit = Retrofit
                    .Builder()
                    .baseUrl("https://api.themoviedb.org/3/movie/550?api_key=")
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(client)
                    .build()
            retrofit.create(APImovies::class.java)
        }
    }
}

这是我目前使用占位符图像填充 Recyclerview 的适配器:

class PosterAdapter() : RecyclerView.Adapter<PosterHolder>(){

    override fun getItemCount(): Int { return 300}

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PosterHolder{
        val layoutInflater = LayoutInflater.from(parent.context)
        val listItem = layoutInflater.inflate(R.layout.list_item, parent, false)
        return PosterHolder(listItem)
    }

    override fun onBindViewHolder(holder: PosterHolder, position: Int) {
        holder.view.movie_poster?.setImageResource(R.mipmap.beauty_and_the_beast_ver3)
        holder.view.movie_poster?.scaleType = ImageView.ScaleType.FIT_XY
    }
}

class PosterHolder(val view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
    var imageView: ImageView? = null

    fun PosterHolder(view: View){ this.imageView = view.findViewById<View>(R.id.movie_poster) as ImageView }

    override fun onClick(p0: View?) {}
}

【问题讨论】:

    标签: android android-recyclerview kotlin retrofit2


    【解决方案1】:

    我使用以下设置。看看这对你有没有帮助。

    interface WebService {
    
        @GET
        fun getMovies(): Call<List<MyResponseObject>>
    
        companion object {
            fun create(): WebService {
                val client = OkHttpClient.Builder().build()
                val retrofit = Retrofit.Builder()
                        .baseUrl("YOUR_BASE_URL")
                        .addConverterFactory(GsonConverterFactory.create())
                        .client(client)
                        .build()
    
                return retrofit.create(WebService::class.java)
            }
        }
    }
    

    MainActivity做如下网络调用

    class MainActivity : AppCompatActivity() {
        private val webService = WebService.create()
        override fun onCreate(savedInstanceState: Bundle?, persistentState: 
        PersistableBundle?) {
            /*...*/
            fetchMovies()
        }
    
        private fun fetchMovies() {
            var call = webService.getMovies()
            call.enqueue(object : Callback<MyResponseObject> {
                override fun onFailure(call: Call<MyResponseObject>?, t: Throwable?) { }
    
                override fun onResponse(call: Call<MyResponseObject>?, response: Response<List<Class>>?) {
                    if (response != null && response.isSuccessful) {
                        val myListData: MyResponseObject = response.body()
                        setUpRecyclerView(myListData) // The usual way of setting up a RecyclerView
                    }
                }
            })
        }
    }
    

    这只是初学者友好。我建议您使用 Android 架构组件和 Dagger 2(用于依赖注入)来研究 MVVM 架构。正如 Nail Shaykhraziev

    所说,由于您使用 Kotlin,因此您可以使用 Kotlin CoroutinesAndroidKTXKodein 用于 DI

    【讨论】:

    • 谢谢。我已接受并赞成您的回答。如果您认为这是一个很好的问题,您能否也给我一个赞成票?
    【解决方案2】:

    我使用这样的一些:

    public final class ApiClient {
    
    private static OkHttpClient sClient;
    private static volatile MovieService movieService;
    
    private ApiClient() {
    }
    
    public static MovieService getMovieService() {
        MovieService service = movieService;
        if (service == null) {
            synchronized (ApiClient.class) {
                service = movieService;
                if (service == null) {
                    service = movieService = buildRetrofit().create(MovieService.class);
                }
            }
        }
        return service; // this is one of the implementation options singlton pattern. You can use some di tools(Kodein, Dagger)
    }
    
    private static Retrofit buildRetrofit() {
    
        return new Retrofit.Builder()
                .baseUrl(BuildConfig.BASE_URL)
                .client(getClient())
                .addConverterFactory(GsonConverterFactory.create(getGson()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }
    
    private static Gson getGson() {
        return new GsonBuilder()
                .setLenient()
                .create();
    }
    
    private static OkHttpClient getClient() {
        OkHttpClient client = sClient;
        if (client == null) {
            synchronized (ApiClient.class) {
                client = sClient;
                if (client == null) {
                    client = sClient = buildClient();
                }
            }
        }
        return client;
    }
    
    private static OkHttpClient buildClient() {
        return new OkHttpClient.Builder()
                .addInterceptor(TokenInterceptor.create())
                .build();
    }}
    

    在你的 Presenter/Interactor/ViewModel 调用改造服务方法之后:

    ApiClient.movieService.popularMovies()
                    .map { it.movies }
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnSubscribe { view.showProgress }
                    .doAfterTerminate { view.hideProgress }
                    .subscribeBy(onSuccess = {
                       view.showMovies(it)
                    }, onError = {
                       view.showErrors()
                    })
    

    关于活动/片段/视图:

    class Activity : AppCompatActivity(), MovieView {
    
      override fun onCreate(savedInstanceState: Bundle?) {
          // your code
       }
    
      override fun showMovies(list: List<Movie>) {
         adapter.update(list)
       }
    }
    

    【讨论】:

    • 感谢您的贡献。出于欣赏,我给了你一个赞成票。如果您认为这是一个很好的问题,您能否也给我一个赞成票?
    猜你喜欢
    • 2021-02-11
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    • 2019-06-30
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 2011-09-04
    相关资源
    最近更新 更多