Medley Developer Blog

株式会社メドレーのエンジニア・デザイナーによるブログです

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

今回の内容について

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

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

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

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

やりやすかった部分

Android Studioのありがたさ

f:id:dev-medley:20170727194320p:plain

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

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

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

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

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

f:id:dev-medley:20170727194345p:plain

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

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

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

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

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

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

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

f:id:dev-medley:20170727195637p:plain

基本的には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つだけ許せないことがありまして、それが バックグラウンドプロパティ関連のプロパティの貧弱さ というものです。

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

f:id:dev-medley:20170727194414p:plain

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="http://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は手順が多いので面倒です。

f:id:dev-medley:20170727194509p:plain

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

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="http://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開発やってみようと思っていただけたら良いなと思います。 もっといろいろ知りたいという方は「話を聞いてみたい」ボタンを押してもらえれば!

お知らせ

メドレーでは一緒に働くエンジニア・デザイナーを募集しています。

www.wantedly.com

www.medley.jp