CORDEA blog

Android applications engineer

Kotlin + OkHttp3 + Retrofit2 でヘッダの追加とか

Kotlin でアプリ書いてる時にちょっと戸惑った


 

OkHttpClient のヘッダーの追加は

val httpClient =
                    OkHttpClient.Builder()
                            .addInterceptor {
                                it.proceed(it.request()
                                        .newBuilder()
                                        .addHeader("Content-Type", "application/json")
                                        .build())
                            }
                            .build()


これを Retrofit で使用する場合

Retrofit.Builder()
                .baseUrl { HttpUrl.parse(url) }
                .client(httpClient)
                .build()
                .create(HogeHogeApiInterface::class.java, context)
                .postHuge()
                ...


Observable 返したい場合や、gson 使いたい場合
ここらへんは java と変わり無いですが

Retrofit.Builder()
                .baseUrl { HttpUrl.parse(url) }
                .client(httpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                ...

ちなみに HttpLoggingInterceptor 使う場合

val httpClient =
                    OkHttpClient.Builder()
                            .addInterceptor {
                                ...
                            }
                            .addInterceptor(okhttp3.logging.HttpLoggingInterceptor()
                            .setLevel(okhttp3.logging.HttpLoggingInterceptor.Level.BASIC))
                            .build()


実際に使ってるのはここらへんです。

もうちょっと知見が集まってくれると Kotlin 使う人は増えそうな気がする

Blackberry 10 での Json の扱い方について

Blackberry OS 10 のネイティブアプリ開発で Json を扱うことがあったのでメモ

C++Json を扱う場合、Cascades framework にある JsonDataAccess を用いるのが簡便だと思います。
Qt の対応バージョンが 4.8 で、Qt5.5? で追加された Json サポートを利用することができないためです。
使おうと思えば Qt5 も使えるようなので、その場合は Qt の Json サポートを利用するのがよいかもしれません。

qml で使用する場合は、JSON.parse() で行けるはず。

Parse

    QString jsonData = ....

    JsonDataAccess jda;
    QVariant var = jda.loadFromBuffer(jsonData);

    // map
    QVariantMap map = var.value<QVariantMap>();
    // list
    QVariantList list = var.value<QVariantList>();


レスポンスとして Json が返ってくる場合、このような使い方になります

QVariantMap ApiRequest::onRequestFinished(QNetworkReply* reply)
{
    if (reply && reply->error() == QNetworkReply::NoError) {
        const QByteArray buffer(reply->readAll());

        JsonDataAccess jda;
        QString jsonData = "hogehoge";
        QVariant var = jda.loadFromBuffer(jsonData);
        QVariantMap map =  var.value<QVariantMap>();
        ...
    }
}

 

Stringify

    QVariantMap map;
    map["hoge"] = "hogehoge";

    JsonDataAccess jda;

    QByteArray jsonString;
    jda.saveToBuffer(QVariant(map), &jsonString);


POST リクエストとか送る時はこんな感じ

void ApiRequest::request(QString username, QString password, QString factorKey)
{
    QNetworkRequest request;
    request.setUrl(QUrl("http://cordea.jp"));

    connect(mManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onRequestFinished(QNetworkReply*)));

    QVariantMap map;
    map["hoge"] = "hogehoge";

    JsonDataAccess jda;
    QByteArray body;
    jda.saveToBuffer(QVariant(map), &body);

    mManager->post(request, body);
}


c++ 的に書き方があっているかは若干不安。


F# で Android アプリ開発いいよねって話を今更。

Xamarin と F# 使って Android アプリ開発の話。

最近 F# とか blackberry とかやってて完全に変人扱いされています。
ですが、Rx とか流行ってるし、次にくるのは F# だと信じています。


Android Java or Kotlin はもちろん、
Xamarin C# に比べても人口も情報も圧倒的に少ないですが
でも IDE があって、サポートされているだけでも上々ですよね。

F# のよさを語るよりも実際にコードを見ていただいたほうが魅力が伝わるかと思いますので、
おなじような実装を Java, C#, F# でしてみました。

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    ListView listView = (ListView) findViewById(R.id.list_view);
    listView.setAdapter(adapter);

    Context context = this;
    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(context, TestActivity.class);
            startActivity(intent);
        }
    });
}

C#

protected override void OnCreate (Bundle bundle)
{
    base.OnCreate (bundle);
    SetContentView (Resource.Layout.FirstView);

    var toolbar = FindViewById<Toolbar> (Resource.Id.toolbar);
    SetSupportActionBar (toolbar);

    var listView = FindViewById<ListView> (Resource.Id.list_view);
    listView.Adapter = adapter;

    FloatingActionButton fab = FindViewById<FloatingActionButton> (Resource.Id.fab);
    fab.Click += (sender, e) => {
        StartActivity (typeof(TestActivity));
    };
}

F#

override me.OnCreate (bundle) =
    base.OnCreate bundle
    me.SetContentView Resource_Layout.Main
    
    let toolbar = me.FindViewById<Toolbar> Resource_Id.toolbar
    me.SetSupportActionBar toolbar
   
    let listView = me.FindViewById<ListView> Resource_Id.list_view
    listView.Adapter <- me.adapter
    
    let onClick e =
        let intent = new Intent(me, typeof<TestActivity>)
        me.StartActivity intent
        
    let fab = me.FindViewById<FloatingActionButton> Resource_Id.fab
    
    fab.Click.Add(onClick)


どうでしょうか。
個人的には brace ないだけでもかなり見通し良いと思っています。

Xamarin を使用されている方もいない方も、ぜひ一度 F# を。



F# でもうちょっとちゃんと実装してあるものはこちらのリポジトリにあります。
github.com
blackberryiOS なども突っ込まれててカラフル。

その Activity 、少し長すぎませんか?

Android の Activity や、layout xml, 気をつけていても長くなってしまう場合があります。

そして、特に一人で開発していたりすると、
長すぎることに気づいてもついつい放置してしまいがちです。

ただ、放置すると、多くの場合引継ぎ等に支障をきたします。
layout xml とかあまりに長すぎると補完聞かなくなったりしますしね...

というわけで、
今回は java file や layout xml が指定行数を超えるとビルドが通らなくなる方法を検討してみました。


checkFileLimits() をビルドの際に呼び出すことで
指定行数を超えるとビルドが通らなくなります。

import groovy.io.FileType

class LineLimit {
    void checkFileLimits(base, layoutLimit, javaLimit) {
        def layout = base + "/src/main/res/layout/"
        def java = base + "/src/main/java/"
        checkLimit(layout, layoutLimit)
        checkLimit(java, javaLimit)
    }

    void checkLimit(dir, limit) {
        new File(dir).eachFileRecurse(FileType.FILES) {
            def c = it.text.split("\n").size()
            if (c >= limit) {
                throw new Exception("File exceeds the limit. Number of lines: " + c + ", File name: " + it.name)
            }
        }
    }
}


 

    buildTypes {
        debug {
            def lineLimit = new File(projectDir.absolutePath + "/LineLimit.groovy")
            def sc = new GroovyClassLoader().parseClass(lineLimit)
            def llClass = sc.newInstance()
            llClass.checkFileLimits(projectDir.absolutePath, 499, 999)
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }


 

method の呼び出しが美しくないので
ここらへんは groovy, gradle に明るい方に教えていただきたい

Mackerel の非公式 Android アプリ "Mackerel Client" を公開しました

サーバ管理サービス、Mackerel(マカレル)の Android アプリを作ったので、ストアに公開しました。
と同時に、GitHub にソースを公開しました。

Get it on Google Play

github.com


Kotlin を使って何か作りたいと思っていた時期に
Mackerel の API が提供されていることに気づいたので
とても良いタイミングでした。

 

アプリの特徴

  • アラート・監視設定・ホスト等の情報閲覧
  • アラートのクローズ、監視設定の削除、ホストの退役
  • メトリックグラフの表示


情報の確認を出先でする、という目的のもとに作っていますので
情報の編集等は現時点では実装していません。
ホストの退役も出先ではやらないだろうな...

技術的な特徴

  • Kotlin (重要)
  • Rx


今回は、いろいろと新しいものを取り入れて
ひたすら自由に作っているので、嵌りどころもありました。
そこらへんは後日記事にします


あと、Kotlin + RxKotlin は良いなぁと改めて思いました。
業務で Kotlin 使えるのはいつになるか分かりませんが、個人的には今後も使っていく予定です。


開発では Mackerel のヘルプが充実していて助かりました。
API 仕様が読みやすくてとても良かったです。

Android で Path を animation させるには

android で線を引くようなアニメーションを行う方法について


リポジトリはこちらですgithub.com


とりあえず今回は四角形を描きます

public class PathAnimationView extends View {

    private Path mPath;
    private PathMeasure mMeasure;

    public PathAnimationView(Context context) {
        super(context);
        init();
    }

    public PathAnimationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PathAnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        Path path = new Path();
        path.moveTo(50, 50);
        path.lineTo(50, 100);
        path.lineTo(100, 100);
        path.lineTo(100, 50);
        path.lineTo(50, 50);

        mPath = path;
    }
}

 

あとで path の長さを取得して animation させるので、ここで pathMeasure に path をセットしておきます
また、 Lollipop より低い version の場合、正常に描画されない場合があるので、Hardware Acceleration を切ります


    private void init() {
        Path path = new Path();
        path.moveTo(50, 50);
        path.lineTo(50, 100);
        path.lineTo(100, 100);
        path.lineTo(100, 50);
        path.lineTo(50, 50);

        PathMeasure measure = new PathMeasure();
        measure.setPath(path, false);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }

        mPath = path;
        mMeasure = measure;
    }


 

onDraw の中身は普通に描画する場合と特に変わりません
objectAnimator を使って、0.0-1.0 までの各地点で path を切り出してそれを描画します

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(getResources().getColor(android.R.color.black));
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);

        canvas.drawPath(mPath, paint);
    }

 

objectAnimator の部分

    private void setProgress(float progress) {
        mPath.reset();
        mMeasure.getSegment(0.0f, mMeasure.getLength() * progress, mPath, true);
        invalidate();
    }

    public void startAnimation() {
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "progress", 0.0f, 1.0f);
        animator.setDuration(5000);
        animator.start();
    }

 
あとはこの view を追加して startAnimation() を呼び出す

Jenkins を Docker で運用する

自宅のサーバーで運用している jenkins を docker 上で運用したら楽そうな気がしたので docker のインストールから確認まで行ったメモ。

といっても特に移行作業などはせず、もともと動いていた jenkins を停止して docker hub に公開されている jenkins を pull します。

環境

手順

Install docker

docker 入ってなかった

% sudo yum install -y docker

configure

% vim ~/.zshrc
..

export DOCKER_HOST=tcp://0.0.0.0:2376

...
% source ~/.zshrc


 

docker 起動時の設定を修正する。

% sudo vim /etc/sysconfig/docker
...

OPTIONS='--selinux-enabled -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock -G docker'

...

INSECURE_REGISTRY='--insecure-registry 0.0.0.0:2376'

...

ユーザーを docker グループに追加する

% sudo groupadd docker
% sudo usermod -aG docker $USER


 
 
firewalld を切って iptables を使用する

% sudo systemctl stop firewalld.service
% sudo systemctl disable firewalld.service
% sudo systemctl start iptables.service
% sudo systemctl enable iptables.service

 

Pull

% docker pull jenkins
% docker run --name myjenkins -p 8080:8080 jenkins

 

ここまでやって localhost:8080 にアクセスすると jenkins が立ち上がっていることが確認できます。
はじめは tlsverify をするつもりだったのでかなり苦戦しましたが、結局諦めました...やり方が分かったら追記します