mixi engineer blog

*** 引っ越しました。最新の情報はこちら → https://medium.com/mixi-developers *** ミクシィ・グループで、実際に開発に携わっているエンジニア達が執筆している公式ブログです。様々なサービスの開発や運用を行っていく際に得た技術情報から採用情報まで、有益な情報を幅広く取り扱っています。

Android の Commons な知見を集めたライブラリを作りました

こんにちは。今日も元気に Android アプリの開発をしています、横幕です。
最近は、アプリで画像処理をゴリゴリとするのが楽しくなってきました。端末も進化してきており、メモリ搭載量も飛躍的に増えてきているので、そろそろ 64 bit 対応の空気を感じつつ有ります。

さて、私はこれまで、4 つの Android アプリ開発プロジェクトに携わってきました。mixi 公式クライアントアプリmixi コミュニティ公式クライアントアプリ、そして今現在はノハナにジョインして、フォトブックアプリ年賀状アプリに携わっています。
新卒入社以来配属から2年半ほど経ち、その中で得た知見を、Android-Device-CompatibilityAndroidTraining といった形で公開してきましたが、今回新たに、Android アプリを開発する中でよく遭遇する、あるあるネタを詰め込んだ Amalgam ライブラリを公開しましたので、こちらの紹介をさせていただきたいと思います。

nohana/Amalgam - GitHub

https://github.com/nohana/Amalgam

http://nohana.github.io/Amalgam/

続きを読む

mixiのアプリの設計がよく分かるブログ - スマートフォン開発研修教材の補足

こんにちは。Android の横幕です。Android が好きすぎて、来る日も来る日もアプリの実装が頭から離れず、毎日7〜8時間ほど睡眠をとっていますが全く疲れがとれた気がしない今日このごろです。はやく iOS のアプリ開発を覚えたいですが、まだ NSLog の使い方を覚えたばかりです。

さて、先日スマートフォン開発研修教材の公開についてでも触れましたが、Android・iOS のアプリ開発を始める人向けのトレーニング資料を公開しましたところ、以下のブログのような反響をいただきましたので、この場でもって回答をさせていただきたいと思います。

mixiのアプリの設計がよくわからない
http://yamitzky.hatenablog.com/entry/2013/06/19/173713 に遷移します
続きを読む

スマートフォン開発研修教材の公開について

クラフトワークの来日公演3-D CONCERTS 1 2 3 4 5 6 7 8を観にいったら、顔が大きいのか、3Dメガネがきつくて切なかったもりもとです。

株式会社ミクシィでは、新卒入社スタッフをはじめ、これからスマートフォンアプリ開発を行っていく全スタッフを対象に、社内で「スマートフォン開発研修」を始めています。その研修資料をこのたびgithubで公開させていただきました。

mixi-inc/iOSTraining · GitHub
https://github.com/mixi-inc/iOSTraining

mixi-inc/AndroidTraining · GitHub
https://github.com/mixi-inc/AndroidTraining

これら文書は、それぞれCC BY-SA 3.0およびApache License 2.0とCC 2.5 Attributionのデュアルライセンスで公開しています。ご覧になっているみなさまにご参照いただいたり、社内研修にご活用いただくのも大歓迎です。
この資料の公開の経緯とねらいについて、ご説明させていただければと思います。

続きを読む

Androidの機種依存問題を吸収するプロジェクトAndroid-Device-Compatibilityを公開したお話

こんにちは。Androidユニットで開発とスクラムマスターをしています、横幕です。すっかり寒くなって、朝起きるのが辛い季節になりました。

先日、Android(TM)の様々な機種に依存する問題を吸収するためのライブラリプロジェクトをmixi, IncのGitHubリポジトリで公開しました。

今回は、このライブラリプロジェクトを公開するに至った経緯をお話しようと思います。

続きを読む

続・Android開発のちょっとしたお話

こんにちは。横幕です。
今回もAndroid(TM)開発についてお話をしたいと思います。

設定画面の作り込み

今回のトピックは、設定画面のちょっとした工夫の仕方についてです。

Androidでは、PreferenceActivityという設定画面を作るためのActivityが用意されています。
個々の設定項目はXMLで記述し、それをPreferenceActivityがコントローラとして画面を制御するような形になります。

設定画面の大まかな作り方

まずは、どんな設定項目を準備するのかを、res/xml/pref.xmlに定義します。
Androidには予め幾つかの設定方法を用意してあり、例えば項目の一覧の中から1つ選択するListPreferenceや、チェックボックスの状態で設定を変更するCheckBoxPreferenceなどがあります。
また、設定項目のまとまりごとにカテゴライズするためのPreferenceCategoryも用意されており、これらを組み合わせて設定画面に表示するものを記述してきます。

* res/xml/pref.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory android:title="設定1">
        <CheckBoxPreference
            android:key="checkbox_1"
            android:title="チェックボックス1"
            android:summaryOn="チェックしました"
            android:summaryOff="チェックしていません"/>
        <ListPreference
            android:key="list_1"
            android:title="リスト1"
            android:summary="選択した項目"
            android:dialogTitle="選んでください"
            android:entries="@array/list_entries"
            android:entryValues="@array/list_entry_values"/>
    </PreferenceCategory>
    <PreferenceCategory android:title="設定2">
        <EditTextPreference
            android:key="edit_text_1"
            android:title="テキスト1"
            android:summary="入力した内容"
            android:dialogTitle="入力してください"/>
    </PreferenceCategory>
</PreferenceScreen>

* res/values/arrays.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="list_entries">
        <item>First Element</item>
        <item>Second Element</item>
        <item>Third Element</item>
    </string-array>
    <string-array name="list_entry_values">
        <item>First Value</item>
        <item>Second Value</item>
        <item>Third Value</item>
    </string-array>
</resources>

設定項目のスタイルに応じて、記述するアトリビュートも変わってきますね。
android:keyは、設定を読み書きするために使う情報です。キーとバリューのペアで扱うイメージですね。
android:titleには、何を設定するのかを記述します。例えば、「文字の大きさ」と言った具合です。
android:summaryには、実際に何が設定されているかを記述します。「文字の大きさ」であれば、「14pt」などですね。
これ以外にも、ダイアログを表示するListPreferenceやEditTextPreferenceには、ダイアログのタイトルのアトリビュート(android:dialogTitle)や、
一覧の項目を設定するためのアトリビュート(android:entries、android:entryValues)などが用意されています。

これらのアトリビュートはプログラムで簡単に操作できるようになっています。

次にプログラム側の作り方を見ていきましょう。
設定画面は、PreferenceActivityを継承して作ります。
通常のActivityと違うのは、onCreateをオーバライドしたときに、setContentView()でレイアウトを指定するのではなく、addPreferencesFromResource()でpref.xmlを読み取ることです。

* MyPreferenceActivity.java

package com.text.app05;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class MyPreferenceActivity extends PreferenceActivity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.pref);
  }
}

* AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.app04"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="8" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".Example05Activity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:label="@string/app_name"
            android:name=".MyPreferenceActivity" >
        </activity>
    </application>
</manifest>

これだけで、設定画面を表示することができ、実際に設定内容の読み出し・保存も出来ているはずです。

画面1

しかし、このままでは設定内容に応じて見た目を変更することができません。
設定に変更があったことを知るには、OnPreferenceChangeListenerを実装する必要があります。

package com.test.app05;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;

public class MyPreferenceActivity extends PreferenceActivity {
    private ListPreference mListPreference;
    private EditTextPreference mEditTextPreference;
    private SharedPreferences mSharedPreference;
    private OnPreferenceChangeListener mListPreferenceListener = new OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            preference.setSummary((String) newValue);
            return true;
        }
    };
    private OnPreferenceChangeListener mEditTextPreferenceListener = new OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            preference.setSummary((String) newValue);
            return true;
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref);

        mSharedPreference = PreferenceManager.getDefaultSharedPreferences(this);
        mListPreference = (ListPreference)findPreference("list_1");
        mEditTextPreference = (EditTextPreference)findPreference("edit_text_1");

        mListPreference.setSummary(mSharedPreference.getString("list_1", "First Value"));
        mListPreference.setOnPreferenceChangeListener(mListPreferenceListener);
        mEditTextPreference.setSummary(mSharedPreference.getString("edit_text_1", "Not assigned"));
        mEditTextPreference.setOnPreferenceChangeListener(mEditTextPreferenceListener);
    }
}

個々の設定項目(Preference)を取得するには、findPreference()を利用します。引数にandroid:keyアトリビュートの値を指定することで特定します。
そして、取得してきたPreferenceにOnPreferenceChangeListenerをセットします。
これで、設定を変更すると、それに応じて内容の表示も切り替えることができるようになりました。

画面2

表現の工夫

設定、と一口に言っても、実際の関心は、文字の大きさ・着信音・背景色・時間など、多岐にわたります。

そのような関心の中で、現在設定されている内容を表示することを考えてみると、
例えば、文字の大きさであれば、現在設定されている内容の表現として、「大」「中」「小」と言った表示の表現がありますし、
時間についても、「1時間ごと」「2時間ごと」等と言った表現が考えられます。

ではここで、色の設定について考えてみたいと思います。

今何色に設定しているか、を表示したい場合、色の名前を表示するという手段もありますが、
直感的には、色そのものを表示したほうが、分かりやすさがぐっと向上すると思います。

実装方法

設定画面の個々の項目には、widgetLayoutというアトリビュートがあります。
公式開発ドキュメントには、レイアウトへのリファレンスを記述することができることが書かれています。実際、チェックボックスを表示するCheckboxPreferenceもこのwidgetLayoutを利用して作られているようです。
つまり、このwidgetLayoutに独自のレイアウトのリファレンスを記述すれば、チェックボックス以外のViewを表示することができることになります。

例えば、先程のpref.xmlの、ListPreferenceにwidgetLayoutを利用してみると...

* pref.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory android:title="設定1">
        <CheckBoxPreference
            android:key="checkbox_1"
            android:title="チェックボックス1"
            android:summaryOn="チェックしました"
            android:summaryOff="チェックしていません"/>
        <ListPreference
            android:key="list_1"
            android:title="リスト1"
            android:summary="選択した項目"
            android:dialogTitle="選んでください"
            android:entries="@array/list_entries"
            android:entryValues="@array/list_entry_values"
            android:widgetLayout="@layout/indicator"/>
    </PreferenceCategory>
    <PreferenceCategory android:title="設定2">
        <EditTextPreference
            android:key="edit_text_1"
            android:title="テキスト1"
            android:summary="入力した内容"
            android:dialogTitle="入力してください"/>
    </PreferenceCategory>
</PreferenceScreen>

* indicator.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true">
    <View
        android:id="@+id/indicator"
        android:layout_width="30dip"
        android:layout_height="30dip"
        android:background="#FF0000"/>
</FrameLayout>

画像4

このように表示されるはずです。

レイアウトへのリファレンスですから、Viewに限らず、ImageViewを置いて画像を表示する、ということも実現可能ですね。

せっかくですから、項目に応じてViewの色を変更してみましょう。

widgetLayoutを操作するには、ListPreferenceを拡張する必要があります。
ListPreferenceを継承し、onBindView()の中で、widgetLayoutのViewを取り出して、背景色を変更します。

package com.test.app05;

import com.test.app05.R;
import android.content.Context;
import android.graphics.Color;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.view.View;

public class MyListPreference extends ListPreference {
    public MyListPreference(Context context) {
        super(context);
    }

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

    @Override
    public void onBindView(View view) {
        super.onBindView(view);
        View v = view.findViewById(R.id.indicator);
        if ("First Value".equals(getValue())) {
            v.setBackgroundColor(Color.RED);
        } else if ("Second Value".equals(getValue())) {
            v.setBackgroundColor(Color.BLUE);
        } else if ("Third Value".equals(getValue())){
            v.setBackgroundColor(Color.GREEN);
        } else {
            v.setBackgroundColor(Color.RED);
        }
    }
}

また、pref.xmlのListPreferenceを、独自に定義したMyListPreferenceに変更します。
要素名をFQNで指定するだけで完了です。


<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory android:title="設定1">
        <CheckBoxPreference
            android:key="checkbox_1"
            android:title="チェックボックス1"
            android:summaryOn="チェックしました"
            android:summaryOff="チェックしていません"/>
        <com.test.app05.MyListPreference
            android:key="list_1"
            android:title="リスト1"
            android:summary="選択した項目"
            android:dialogTitle="選んでください"
            android:entries="@array/list_entries"
            android:entryValues="@array/list_entry_values"
            android:widgetLayout="@layout/indicator"/>
    </PreferenceCategory>
    <PreferenceCategory android:title="設定2">
        <EditTextPreference
            android:key="edit_text_1"
            android:title="テキスト1"
            android:summary="入力した内容"
            android:dialogTitle="入力してください"/>
    </PreferenceCategory>
</PreferenceScreen>

これで、設定の内容に応じてwidgetLayoutの背景色を変更することができるようになりました。

画像4

終わりに

今回は設定画面の作り込みについてのお話でした。
利用頻度はそれほど高くない場所かもしれませんが、だからこそ、使い方を学習する手間・思い出す手間が極力少ないUI設計にしていくことが重要になってくるのだと思います。

最後になりましたが、先日弊社主催のAndroid開発イベント「Build Challenge for Android」が開催されました。
その際に使用したスライド資料を掲載致しますので、こちらも合わせて参考にしていただければと思います。