web系な備忘録

私が忘れてもブログがあるもの

Android Studio - サンプルプロジェクトを読んでみる

MainActivity

ActionBarActivityを継承している。

ActionBarはAndroidアプリの上部についてるナビゲーションバーのこと。標準のサポートライブラリに含まれている。

android.support.v7.app | Android Developers

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

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment())
                    .commit();
        }
    }

Bundle savedInstanceStateとは、アプリ終了時の状態を保存しているもの。なのでこのif節では、初回起動時にどうするかという処理をしている。 (初回起動時だけじゃなくて、何か他の時にも入りそう/未確認)

getSupportFragmentManager()は、現在のActivityに関連するFragmentManagerを取得するもの。

FragmentActivity | Android Developers

そこで取得したMangaerを使って、トランザクションを開始し、PlaceHolderFragmentというフラグメントをR.id.containerというidで定義されたlayoutに紐付ける。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:ignore="MergeRootFrame" />

layoutファイルのtools:contextとはなんぞや??

xml - What's "tools:context" in Android layout files? - Stack Overflow

StackOverflowによると、UIエディタがレイアウトをレンダリングするときに使うActivityということで…ここと連動しているみたい↓

f:id:sn_f:20131229000943p:plain

ActivityだけでなくFragmentを指定することも出来る。

fragment_main.xml

tools:context=".MainActivity$PlaceholderFragment

tools:ignoreではAndroid Lintを部分的に無視する設定をしている。

AndroidLintについての説明はこちらが詳しい。

Android Lint の利用方法を記載 | Bescottee

lintとはそもそも湿布に使われているようなふわふわ起毛した布とか綿くずのことを言うらしい。で、C言語には

lintとは、主にC言語ソースコードに対し、コンパイラより詳細かつ厳密なチェックを行うプログラムである。

というものがある。free lint(糸くずが出ない)って言葉から転じて、僅かな綻びもないコード…という意味になったかは知らないけど(すみません思いつきで言っています)、とにかくlintはちょっとしたミスを指摘してくれるやつです。例えばhtml lintなら閉じタグが足りないよ!とか言ってくれます。

で、Android Lintも同様に細かなチェックをしてくれるようで、これはADT16(2011年12月版)から追加された機能のようです。

lintが何をチェックしているかは以下で見れます。

http://tools.android.com/tips/lint-checks

目についたものを抜粋してみると…

  • NewApi: Finds API accesses to APIs that are not supported in all targeted API versions
    • ターゲットとしているAPIバージョン全てで使えるわけではないAPI(古いのでしか使えないとか新しいのでしか使えないとか)を使っている
  • ShowToast: Looks for code creating a Toast but forgetting to call show() on it
    • Toast作ってるけどshowしていない(確かにこれ書き忘れやすいよね…)
  • Deprecated: Looks for usages of deprecated layouts, attributes, and so on.
    • 非推奨なレイアウトとか属性とかを使っている

などなど。色々ありますね。

さて、知りたかったMergeRootFrameはどんなやつなのかというと

MergeRootFrame

Summary: Checks whether a root <FrameLayout> can be replaced with a <merge> tag

Priority: 4 / 10 Severity: Warning Category: Performance

If a <FrameLayout> is the root of a layout and does not provide background or padding etc, it can often be replaced with a tag which is slightly more efficient. Note that this depends on context, so make sure you understand how the <merge> tag works before proceeding.

More information: Android Layout Tricks #3: Optimize by merging | Android Developers Blog <<

合ってるか分からないけど訳してみると…

ルートのFrameLayoutが<merge>タグで置換されていいかどうかチェックする。 もしFrameLayoutがレイアウトのルートで、背景やpaddingを提供しないなら、mergeタグに置換することで少し効率的にできます。これは状況次第なので、mergeタグがどのような働きをするのかちゃんと理解してくださいね。

…という感じ?

Android Layout Tricks #3: Optimize by merging | Android Developers Blog

mergeタグを使うとレイアウトの階層が深くなるのを抑えることができます。

hierarchy viewerで実際に確認してみようと思ったのですが、Android Studioのどこにあるのか見つけられない…orz

探しまわっていたら、棚ぼた的に、Preferences->Inspections->Android LintでどのLintを検知してどれは無視するのか、自由に設定できることが分かりました。

話を大きく戻して、PlaceholderFragmentですが、MainActivityの下の方に定義されていました。

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            return rootView;
        }
    }

Fragmentはサポートライブラリ(v4)で定義されている機能で、Activityとレイアウトの間を取り持つものというイメージで…いいのかな…。

Activityで直接レイアウトとロジックを管理すると、1つの画面に複数の機能が含まれるときに大変。例えばfbの左からスライドして出てくるメニュー画面と、ヘッダーと、コンテンツ部分なんかはそれぞれのレイアウトにそれぞれをロジックをくっつける感じで扱えた方が便利です。特にAndroidの場合画面が大きい端末が多かったりするので、横レイアウトの時には左のメニューを出しっぱなしにしたい、とかいう場合に、ロジックは同じものを使い回せるのでFragmentは便利です。

……ってことがこの本に載ってました。もっと正しく分かりやすく書いてあるので詳しくはこちらを参照で。

Android UI Cookbook for 4.0 ICS(Ice Cream Sandwich)アプリ開発術

Android UI Cookbook for 4.0 ICS(Ice Cream Sandwich)アプリ開発術

Fragmentの中にもライフサイクルがあります。

Fragmentを動的に変化させる « Tech Booster

onCreateViewはFragmentに関連付けるViewを返します。

View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            return rootView;

ここでcontainerにはactivity_main.xmlで定義されているFrameLayout(つまりActivity全体の大枠のレイアウト)が入ります。 http://y-anz-m.blogspot.jp/2012/04/android-viewgroup.html

なので、rootViewデバッグして見てみると、android.widget.RelativeLayout(fragment_main.xmlで定義されている大枠)になっています。

要は、第三引数がtrueなら、第二引数を返し、第三引数がfalseなら第一引数のルートレイアウトを返す。ただし、第二引数がnullの場合には第一引数のルートレイアウトを返す。…のかな…。

ちょっとこの辺りは要勉強という感じがします。

一旦ここまで。