AndrodJavaで面倒くさい処理の一つが非同期処理、Thread作ったり、AsyncTask使ったりすればいいわけですが、例えば1つ非同期処理を走らせて、帰って来た結果を判定しまた別の非同期処理を走らす、みたいなことになるともう猛烈に書くの大変なわけです。できればもうチョッと簡単に非同期をすましたい、コールバックを簡単にかければあとは賢いライブラリに非同期処理をやっていただければいいわけです。AndroiderにはおなじみのHTTPクライアントRetrofit
を使って今回は写真共有サービス「フォト蔵」さんのsearch_publicAPIを叩いてみたいと思います。事前に取得キーなどは不要です
Retrofit用のインターフェースと実装を準備
も、細かい実装方法は上記のリンクを読んでください。も、びっくりするぐらい簡単、まず、パラーメータを受け取ってRetrofitのどのコマンドを使うか指定するインターフェースを指定します
public interface PhotoZoApi { @GET("/rest/search_public.json?limit=5") Call<mainSerchPhotoZo> getPotoZo(@Query("keyword") String keyword,@Query("limit") Integer limit); }
んで、あとはRetrofit本体とインターフェースのインスタンスを作って、実際にリクエストを投げる命令を書くだけです。
override fun retrofitCall(keyword:String,limit:Int,callback:(mainSerchPhotoZo?) -> Unit) { val retro = Retrofit.Builder() .baseUrl("https://api.photozou.jp") .addConverterFactory(GsonConverterFactory.create()) .build() val service = retro.create(PhotoZoApi::class.java) val call = service.getPotoZo(keyword,limit) call.enqueue(object : Callback<mainSerchPhotoZo>{ override fun onResponse(response: Response<mainSerchPhotoZo>?, retrofit: Retrofit?) { if (response?.body()?.stat == "ok"){ callback(response?.body()) }else{ callback(null) } } override fun onFailure(t: Throwable?) { callback(null) } }) }
Retrofirの実装部分を関数化してるんですが、引数に関数リテラル(いわゆる無名関数)を詰めるのがポイントで、リクエストした結果が返ってきた際、無名関数の引数に結果を詰めてやります。で、実際にこの関数をリクエストするコードが以下
これが高階関数の威力か・・・(CV:池田 秀一)
retrofitCall(keyword, limit, { callback -> callback?.info?.photo?.let { photo -> v.mPhoto = photo val adapter = PhotoAdapter(photo, v.activity.applicationContext) v.my_recycler_view.adapter = adapter } })
引数、関数リテラルの部分にHTTPリクエストが返ってきてからの処理、この場合は返ってきたJsonをRecycleViewのAdapterにはめる処理を行っています、関数リテラル内の実行部分はmeinThreadになるのでこの中でビュー操作をすればエラーになりません。も、非同期処理これだけで済みます。( ・`ω・´)ドヤァ!、もう私はこれだけでKotlinに移行してよかった!むしろ非同期処理だけはKotlinで書きたい!という感じです。あ、でも高階関数使ったらJavaクラスから読めないかも?と思った皆さん、そんなことはありません。KotlinはJavatとの強力な連携が売り。
public class TestFragmentUI { protected void test(String keyword, Integer limit,RecycleFragment v){ RestApi restApi = new RestApi(); restApi.retrofitCall(keyword, limit, new Function1<mainSerchPhotoZo, Unit>() { @Override public Unit invoke(mainSerchPhotoZo mainSerchPhotoZo) { if (mainSerchPhotoZo != null){ for (Photo photo : mainSerchPhotoZo.getInfo().getPhoto()) { Log.d("photoArray",photo.toString()); } } return null; } }); } }
関数リテラルの部分の引数はFunctionでインスタンスを作ってUnit部分はInvokeメソッド以下で指示すればおk。Javaとの連携が以下のスライドで詳しく述べられてます。すごくわかりやすい解説です。
この記事で作ったプロジェクトはGitHubにあげてあるのでご参考にどうぞ、