株式会社メドレーDeveloper Portal

2017-07-28

元フロントエンドエンジニアから見た Android 開発

今回の内容について

みなさん、こんにちは。開発本部でオンライン診療アプリ「CLINICS」の開発を担当している平木です。

弊社では、インフラ・サーバ・フロントで役割を区切らず、全ての開発メンバーが必要に応じてスキルを広げながら開発に取り組んでいます。 自分も入社前はフロントエンド専門のエンジニアでしたが、入社後はそれに加えて Rails を使ったサーバサイドの開発や、Swift を使った iOS アプリ開発、 そして、現在メインにやっている Android 開発と一通りのプラットフォームや言語を使って開発するようになっています。

エンジニアが自身のスキルを広げる場合、自分の経験や知識を応用して、新しいプラットフォームを理解していくということが多いと思います。

元フロントエンジニアの経験を持っている自分が Android 開発に関わってみて やりやすかった部分つらかった部分などを書いていこうと思います。同じような立場でこれから開発しようと思う方には少しお役に立てるかもしれません。

やりやすかった部分

Android Studio のありがたさ

20170727194320.png

いきなり IDE の話になっていますが。やはり Android Studio のオールインワン感がとても便利です。Web フロントエンドの開発だと IDE といえば WebStorm など使ったことがありましたが、ライブラリを含めた補完周りなどはやっぱり Java などでの開発した方が IDE は力を発揮しやすいんではないかと思いました。

とりあえずほとんど設定をいじらなくても、補完やドキュメントの参照ができるのはラクです。また JS などで変数に変換してもあんまり便利さが湧きませんが、 Java の場合だと勝手に対応した型もつけてくれたりと至れり尽くせりだと思いました。

ゲッターセッターなども手作業でやると単純作業になりますが、⌘N で勝手に展開してくれますし、Java での開発の冗長な部分をあまり感じないで開発できるのが凄いです。

エミュレータなども自分が使い始めたときは既に起動も高速な感じでしたし、エミュレータの管理なども Android Studio 内で完結するのであまり迷ったりすることがないです。また初心者に優しいなと思ったのが、Activity など作るのにテンプレートがちゃんと用意されてるのであまりファイル構成が分かってない初めの頃でもちゃんと画面を作ることができるところです。

ビルドシステムが分かりやすい

20170727194345.png

ご存知 Gradle ですが、通常の使い方してる分には(あまり Gradle でがんばらなければ)、WebPack とかよりも書きやすいよねと思います。もちろん目的が違いますが。

フロントエンド開発でよく陥りがちな「設定ファイルなんだかプログラムなのか分からないくらい作られた」というような設定ファイルにはなりにくいんじゃないかと感じています。

build.gradle で設定した環境変数などもソースからさっと使うことができますし、良く考えられてるなーと思いました。

公式のライブラリであれば、 build.gradle で lint としてライブラリの更新があることが分かるのも親切です。サードパーティのライブラリもこれがされてるととても嬉しいんですが、 Analyze -> Run Inspection by Name -> Newer Library Versions Available で見てくれるんでガマンしてます。

View 部分の作り方がフロントエンドに似ているので取っつきやすい

これは HTML / CSS を書いていた人間からすると大変に敷居が低いと思いました。

使うパーツは最初はどんなものがあるのか分からないのでドキュメント引いたり、 Design タブからパーツを選択したりして View を作ってましたが、HTML を組む感覚でガンガンと作っていけました。

20170727195637.png

基本的には HTML タグのなかで style 属性付けていくみたいな感じです。margin とか padding とかも同じですし、textAlign なんかもあるので初期のころは本当に助かりました。

もちろん AppBarLayout とか Toolbar とか Theme など Android 独自の概念はありますがそういった差分的なものは知識として覚えていけば良いだけなので、フロントエンドに慣れていると大変に View 作るのがラクだと感じます。

iOS の StoryBoard は未だにつらい。

ググったときに古めの情報を参考にしても問題が解決できる後方互換性の高さ

ここ数年フロントエンドの技術的な流れが早すぎるというのは一般的に良く言われていますが、良い意味で Android は古い情報もちゃんと使えるというのはとても助かりました。

一番古いので 2011 年くらいの情報だったら使えました。(もちろん廃止されてる…というのも多いのですが)

初めのうちは フロントエンドだとこうやるけど Android ではどうするんだろう というような疑問が多いと思うのですが、特に View に関わるような問題などは古い記述でも問題なく使える後方互換性の高さのおかげで「ググったように書いたのに、今は使えない…」というストレスからかなり開放されます。

つらかった部分

ライブラリや画像を気軽に入れにくい

これついては、フロントエンドの JS などでも別に気軽にさくさくとライブラリを入れていたわけではないですが、いざ入れようとすると Android(というよりもネイティブアプリ全般か)の場合全て APK の容量増加という自体に直結するので中々気をつかいます。

さすがにゲームでもないのに容量重いアプリにするとそもそもダウンロードしてもらえるかどうかも怪しくなります。パッケージする画像なども多用するような仕様にしないようにしています。

あと最初のころにビルドできずに困るわ…と思って必死に対応を調べた 64K 参照制限 も一回設定してしまえば何てことはないんですが、割と初見殺しだと思います。

また実際にプロダクション用にビルドするとなるとフロントエンドでもおなじみのソースの難読化をするのですがその際にライブラリのなかで難読化しちゃいけないなどの指定をしないと余裕で動かなくなります。

ということで各ライブラリを使うときにはProGuardの設定をしないといけないのですが、これも気軽にライブラリ使おうと中々ならない理由でした。

バッググラウンドプロパティ関連の貧弱さ

良い点のところで HTML / CSS と View の作りが似ているので幸せと書いたんですが、1 つだけ許せないことがありまして、それが バックグラウンドプロパティ関連のプロパティの貧弱さ というものです。

どういうことかというと…例えばこんな感じのラベル作るとします。

20170727194414.png

HTML / CSS だったら楽勝だと思います。

<span class="radius">診察待ち</span>
.radius {
  border-radius: 12px;
  padding: 4px 12px;
  background-color: #89c8ba;
  color: #ffffff;
}

しかし Android の場合は

<TextView
    android:id="@+id/upcoming_list_status"
    android:textSize="14sp"
    android:layout_width="100dp"
    android:layout_height="wrap_content"
    android:textAlignment="center"
    android:background="@drawable/label_status_upcoming"
    android:textColor="#FFFFFF"
    android:text="診察待ち" />

とテキスト作ったうえで、 background の指定先のベクターアセットを作ってやらないといけません。 このアセットが paddingbackground-color など指定されているというものになります。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="https://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <stroke android:width="1dp" android:color="@color/label_status_upcoming" />
            <corners android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp" android:topLeftRadius="12dp" android:topRightRadius="12dp" />
            <solid android:color="@color/label_status_upcoming" />
            <padding android:left="12dp" android:right="12dp" android:top="2dp" android:bottom="2dp" />
        </shape>
    </item>
</selector>

とても面倒です。

リストがつらい

配列になっているデータを取り出してリストとして表示するという状況、良くあると思います。 フロントエンドなら <ul/> で囲んだなかの <li/> にデータを forEach() やら map() やら使って作っていくのが常道ですが、Android は手順が多いので面倒です。

20170727194509.png

このようなお知らせのリストを作るのに…

public class NotificationItemHelper {
    private String message;
    private String link;
    private String patientName;

    public NotificationItemHelper(String message, String link, String patientName) {
        this.message = message;
        this.link = link;
        this.patientName = patientName;
    }

    public String getMessage() {
        return message;
    }

    public String getLink() {
        return link;
    }

    public String getPatientName() {
        return patientName;
    }
}

リストに表示するためのクラスを作ってあげて、

public class NotificationListAdapter extends ArrayAdapter<NotificationItemHelper> {

    private int layoutResource;

    public NotificationListAdapter(Context context, int resource, List<NotificationItemHelper> objects) {
        super(context, resource, objects);
        this.layoutResource = resource;
    }

    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;

        if (view == null) {
            LayoutInflater layoutInflater = LayoutInflater.from(getContext());
            view = layoutInflater.inflate(layoutResource, null);
        }

        NotificationItemHelper notificationItemHelper = getItem(position);

        if (notificationItemHelper != null) {
            TextView message = (TextView) view.findViewById(R.id.notification_list_message);
            TextView patientName = (TextView) view.findViewById(R.id.notification_list_patient_name);

            if (message != null) {
                message.setText(notificationItemHelper.getMessage());
            }

            if (patientName != null) {
                patientName.setText(notificationItemHelper.getPatientName());
            }
        }

        return view;
    }
}

それを View に表示させるための Adapter というものを作り、

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/upcoming_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingStart="@dimen/spacing_small"
    android:paddingEnd="@dimen/spacing_small"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingTop="@dimen/spacing_small"
        android:paddingBottom="@dimen/spacing_small"
        android:orientation="vertical">

        <TextView
            android:id="@+id/notification_list_message"
            style="@style/TextBoldStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/spacing_xsmall" />

        <TextView
            android:id="@+id/notification_list_patient_name"
            style="@style/TextNormalStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/spacing_xsmall"
            android:textColor="@color/text_color_secondary" />
    </LinearLayout>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|center_vertical"
        android:src="@drawable/ic_keyboard_arrow_right_black_24dp" />
</LinearLayout>

実際のリストの内容を xml で作ってあげて、

<ListView
    android:id="@+id/notification_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

リストのラッパーを指定して

List<NotificationItemHelper> notificationItemList = new ArrayList<>();
ListView notificationListView = findViewById(R.id.notification_list);
List<NotificationResponse> notifications = notificationsResponse.getNotificationResponses();
for (Notification notification : notifications) {
    NotificationItemHelper item = new NotificationItemHelper(
            notification.getMessage(),
            notification.getLink(),
            notification.getPatientName());
    notificationItemList.add(item);
}

NotificationListAdapter notificationListAdapter = new NotificationListAdapter(this, R.layout.notification_layout, notificationItemList);
notificationListView.setAdapter(notificationListAdapter);

ここまでやってようやくリストが表示されます。未だに面倒だなーと思います。

最後に

色々と細かい例を上げましたが、いかがでしょうか。

今回は書いてませんが、ライブラリも JS とは考え方違って面白いなあと思うものがあります。特に View パーツを簡単に選んだり、イベントを書くことができるButterKnifeやバリデーションライブラリのAndroid Saripaarのように Java のアノテーションを付けるだけで簡単に使える部分などは Java に触れてこなかった身としては新鮮でした。

全体的な印象としてはプラットフォーム特有のクセなどはもちろんありますが、フロントエンドエンジニアでもかなり取り組みやすいのではないかと感じています。何より Android 実機で自分が作ったものが動いてるのを見るとブラウザで自分が作ったサイトが動いているというのとは一味違った達成感があります。

もちろん開発していく内に、たとえば JS にはないスレッドの概念が立ち塞がったり Android 特有のライフサイクルに悩まされたりもしますが、公式のドキュメントも充実していますし、Stack Overflow など見て解決することがかなり多いです。

これを読んで Android 開発やってみようと思っていただけたら良いなと思います。 もっといろいろ知りたいという方は「話を聞いてみたい」ボタンを押してもらえれば!

お知らせ

メドレーでは医療業界に存在する課題に IT を駆使して取り組んでいきたいデザイナー・エンジニアを募集中です。 皆さまからのご応募お待ちしております。

https://www.medley.jp/jobs/

https://www.medley.jp/team/creator-story.html

株式会社メドレーDeveloper Portal

© 2016 MEDLEY, INC.