SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

トップエスイーからのアウトカム ~ ソフトウェア工学の現場から

Androidアプリケーション開発におけるActivityの肥大化を防ぐデザインパターン

トップエスイーからのアウトカム ~ ソフトウェア工学の現場から 第5回

Activity肥大化を防ぐデザインパターン

 では、10個のアプリを解析して見つけたActivity肥大化問題に対する良い解決策をデザインパターンとして紹介します。トップエスイーの修了制作では4つのデザインパターンを提示しましたが、今回はそのうちの1つについて、紹介・解説をしたいと思います。

 提示するのは「Fragmentを使って、Layoutのパーツごとに実装クラスを分ける」デザインパターンです。肥大化したクラスを分割するのはもちろん一般的な対処です。ここでポイントになることは、AndroidのActivity周りで使われている「よくある機能分割の方針」を、調査したいくつかのアプリケーションから抽出できたということです。その方針とは、Activityクラスの中身を画面上のパーツごとにFragmentクラスのサブクラスに分解する、ということです。分解するため、それぞれのFragmentクラスのサブクラスは元のActivityのサブクラスより管理しやすい小さな単位になり、実装する機能も特定の機能に絞られます。

 この解決策は10個のアプリのうち4個のアプリ、具体的には以下のアプリで使われていました。

  • K-9 Mail
  • Offline Calendar
  • Open-camera
  • Calculator

 1つのアプリケーションで見られるだけの手法でももちろん、意味はあるでしょう。しかしながら、これは多数のユーザーの支持を集めているアプリケーションのうち4つのアプリケーションで共通に使われている手法です。この手法はより広い問題を解くことができる可能性が大いにあるといえます。さまざまな問題に適用できる可能性がある手法を「パターン」として提唱することで、これから先に立ち向かう必要がある問題にも適用しやすくなります。そしてパターン適用を繰り返し行うことで、パターンそのものの分析がさらに進むことも期待できます。

デザインパターンを利用せずに、シンプルなAndroidアプリを実装する

 具体的なコード例を挙げながら解説していきます。まず、デザインパターンを利用せずにシンプルなAndroidアプリを実装してみます。その後、デザインパターンを適用した実装を行います。

 AndroidStudio(バージョンは2.3.1)でActivityを作成する際に「BasicActivity」というテンプレートを利用すると、図1のような画面を表示するActivityが生成されます。FloatingActionButtonが1つと、メニューが実装されています。

図1 自動生成された状態のActivity
図1 自動生成された状態のActivity

 自動生成されたActivityクラスの実装はリスト1の通りです。なお、自動生成されたコメント行は削除しました。onCreateとonCreateOptionsMenu、onOptionsItemSelectedの3つのメソッドが最初から定義されています。

リスト1 自動生成されたActivityクラス
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // FloatingActionButtonに関する実装
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    // メニューに関する実装
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

 まだ機能を実装していないのにも関わらず、コード量はそこそこ多くなっています。特にFloatingActionButtonとメニューに関する実装があるので、その分コード量増加につながっています。FloatingActionButtonが押された時の処理と、メニューが選択された時の処理が書かれると、さらにコード量は増えます。それに加え、この画面でのメインの機能が実装されれば、Activityクラスのソースコード量は膨大になることが容易に想像できます。

 メインの機能を追加してみましょう。画面の中央にボタンを配置して、ボタンが押されたらメッセージを画面下に表示する、といったシンプルな機能を実装します。何の工夫も行わずに素直に実装しようとすると、まずレイアウト定義のファイルにボタンを追加すると思います。ボタン追加後のレイアウトファイル定義はリスト2のようになります。

リスト2 レイアウト定義ファイル
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="kazu.code_zin_sample_app.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <!-- ボタンを追加 -->
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button"
        android:layout_gravity="center"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

 「ボタンを追加」とコメントした箇所以外は自動生成されたxmlファイルです(厳密にはincludeが使われていたのですが、シンプルにするためincludeを使わない構成に変更しました)。

 続いて、リスト3の通りにActivityクラスのサブクラスであるMainActivityに機能追加の実装を行います。MainActivityクラスのonCreate()メソッドにコードを追加します。

リスト3 修正したMainActivity クラスのonCreate()メソッド
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

    // メインの機能の実装
    Button button = (Button)findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Button clicked.", Snackbar.LENGTH_LONG).show();
        }
    });
}

 onCreate()が少し大きなメソッドになってしまいました。1つのクラスに、さまざまな処理(FloatingActionが押された時の処理、画面中央のボタンが押された時の処理、メニューに関する処理)が実装されているのも望ましくないですね。

次のページ
デザインパターンを適用する

この記事は参考になりましたか?

トップエスイーからのアウトカム ~ ソフトウェア工学の現場から連載記事一覧

もっと読む

この記事の著者

若松 和憲(リコーITソリューションズ株式会社)(ワカマツ カズノリ)

 2015年にトップエスイーを受講。現業務はWebアプリケーション開発。認定スクラムマスターを取得しており、チームでより高い価値を創出できるよう日々奮闘している。AWSに非常に関心があり、現業務でも活用している。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/10232 2017/06/21 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー