酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

iOSとAndroidとで非同期処理を書く

iOSとAndroidの両方を実装する機会が多いです。

Splatoon 2の発売に向けてikatomoの再開発をしています*1。その再開発にあたりiOS版とAndroid版とで処理を揃えたいと考えました。

https://itunes.apple.com/jp/app/ikatomo-for-splatoon/id1066729147?mt=8&uo=4

処理を揃えるといっても厳密に揃えることはなくてだいたい一緒ぐらいレベルの話です。

ここでは、仮にhttps://www.google.co.jp/にアクセスして先頭から100文字を取得する処理を実装してみました。

目次

Android

最初にRxJava(RxAndroid)とVolleyを使った実装を書いていたのですが、野村氏の指摘によるとVolleyよりもOkHttpの方がモダンらしい。

そうだったのか……。OkHttpを使ったバージョンを追加してみました。

RxJavaとOkHttpを使ってみた

RxJava(RxAndroid)とOkHttpを使ってみました。

import android.content.Context;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class API {
    public static Observable<String> google(Context context) {
        return Observable.create(subscriber -> {
            final String url = "https://www.google.co.jp/";
            try {
                Request request = new Request.Builder()
                        .url(url)
                        .get()
                        .build();

                OkHttpClient client = new OkHttpClient();
                Response response = client.newCall(request).execute();
                
                subscriber.onNext("Response: " + response.body().string().substring(0, 100));
                subscriber.onCompleted();
            } catch (IOException | JSONException e) {
                subscriber.onError(e);
            }
        });
    }
}

RxJava(RxAndroid)とVolleyを使ってみた

RxJavaとVolleyを使ってみました。

import android.content.Context;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

public class API {
    public static Observable<String> google(Context context) {
        return Observable.create(subscriber -> {
            final String url = "https://www.google.co.jp/";
            final StringRequest stringRequest = new StringRequest(Request.Method.GET, url, response -> {
                subscriber.onNext("Response: " + response.substring(0, 100));
                subscriber.onCompleted();
            }, error -> {
                subscriber.onError(error);
            });
            RequestQueue queue = Volley.newRequestQueue(context);
            queue.add(stringRequest);
        });
    }
}

使い方

public void onClick(View view) {
    subscriptions.add(API.google(getActivity())
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe((result) -> {
                //成功時
                Log.e(TAG, result);
            }, (error) -> {
                //失敗時
                Log.e(TAG, "error!!!");
            }, () -> {
                //完了時
                Log.e(TAG, "complete!!!");
            }));
}

ikatomoのiOS版ではネット(イカリング)からデータをダウンロードしてJSONをパース、そのあとRealmに保存するような使い方をしています。そういう意味でいうとAndroid版ではObservableではなくてCompletableで良いかもしれない。

iOS

BrightFuturesとAlamofireを使いました。

import Foundation
import Alamofire
import BrightFutures

class API {
    
    static func google() -> Future<String, APIError> {
        let promise = Promise<String, APIError>()
        
        let url = "https://www.google.co.jp/"
        Alamofire.request(url).responseString { (response) in
            if let _ = response.error {
                promise.failure(APIError.invalidConnection)
                return
            }

            guard let value = response.value else {
                promise.failure(APIError.invalidOperation)
                return
            }
            
            let str = value.substring(to: value.index(value.startIndex, offsetBy: 100))
            promise.success("Response: \(str)")
        }
        return promise.future
    }
}

使い方

func buttonAction() {
    API.google().andThen { (_) in
        //完了時
        print("complete!!!")
    }.onSuccess { (result) in
        //成功時
        print(result)
    }.onFailure { (error) in
        //失敗時
        print("error!!!")
    }
}

*1:7月21日からはゲームしかしてないと思います