1年に1回くらいAndroid開発をするかしないかくらいの人間のメモ(2015年夏)


1年に1度か2度程度、検証等でAndroidアプリを開発をする機会が訪れるのですが、Hello Worldレベルからすっかり忘れてしまうので、主要な要素を思い出すためのメモ。

##前回(2014年中盤)の開発から変わったこと

* Lollipopが出た
* Volleyがdependenciesに書けば使えるようになっている
* JsonObjectReqestの引数の型チェックが厳しくなっている
* Android Studioのアイコンが変わった（1.3.1になった）

##やりたいこと

そんなに多くない。
前提知識として

* ショートカット
* デバッグログ出力

実装としては、

* レイアウト
* ボタンクリック
* 画面遷移
* パラメーター渡し
* JSON連携
* ListView（これやると底なしですが、とりあえずjsonを表示するところまで）

くらい。

##ショートカット

とりあえずはこの２つ。

* コードの形成 Option + Command + l
* ライブラリの補完 Option + enter

##デバッグログ出力

とりあえず、

* Log.d(string tag,string msg)

という形式。LogCatでフィルタリングして見る。
その他、Log.v, Log.i, Log.w, Log.e などなど。

>ログが出力されない時はadb serverのリスタートか、Android StudioでTools->Android->Enable ADB IntegrationをOn/Offしてみる。

##レイアウト

Layoutは、LinearLayoutさえコントロールできれば何とかなります。
私は手書き派なので、とりあえず、ルート要素として下記の記述を基本とします。

* namespaceの定義
* layout_widthとlayout_heightの定義
* 必要に応じてorientation

が最小単位といったところ。


```xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</LinearLayout>
```

>Command + Option + l でコード整形。

##ボタンクリック

クリックイベントの実装法は皆さんお悩みのようですが、私はプログラマさんが一番嫌う？Androud Studioで、ボタンプロパティのonClickに直接イベントメソッドを記述する方法を選ぶことにします(buttonにandroid:onClick属性設定）。何しろ年に1度なので。

ViewにTextViewとボタンを設置し、それぞれ、

* txt1
* bnt1

と命名。

そして、MainActivityのどこかに、

```java
public void changeText(View view)
{
    TextView tv = (TextView)findViewById(R.id.txt1);
    tv.setText("hoge");
}
```
などと書く。

>buttonはこれでなんとかなりますが、他のオブジェクトを利用するさい、結局setOnClickListener()を使うので、全体的な一貫性としては、setOnClickListener()を利用したほうがいいのかもしれません。

setOnClickListener()も一応書きます。

```java
Button btn = (Button)findViewById(R.id.btn1);
btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("tama", "clicked");
    }
});
```

記述量はかわらないですね。。Java8に対応するとラムダで書けるようになるのでしょうか。
Javaだとややこしそうですが、要はjQueryで、

```js
$("#btn").click(function(){
	console.log("hoge");
});
```
ってしてるのと同じ。無名（匿名）関数。

最近だと、[Android/Annotations](http://androidannotations.org/)とか、[Butter Knife](http://jakewharton.github.io/butterknife/)みたいな、簡単記述用のライブラリもあるようです。

そもそもGoogleはなぜ、Android開発言語をJavaにしたのか。Swiftみたいに、新しいの出して欲しい。

##画面遷移

####Activityの追加

何は無くても、遷移先のActivityの追加が必要。プロジェクトを右クリックして、新規->Activity->Blank Activityとする。Manifestへの追加もやってくれる。楽ちん。

####パーツの配置

* MainActivityにbtn1とtxt1を配置
* SubActivityにbtn2とtxt2を配置

btn1にSubへの遷移コードを、btn2にMainへの遷移（自分を消す）コードを書く。

####btn1のonClick

```java
public void gotoSub(View view)
{
	//create intent
    Intent intent = new Intent(getApplication(), SubActivity.class);
    
    //start intent
    startActivity(intent);
}
```

####btn2のonClick

遷移というより、消しているだけ。

```java
finish();
```

##パラメーター渡し
次に遷移時のパラメーター渡し。
ただ渡すだけなら簡単。戻してもらうなら帰りのための準備が少々必要。

###ただ渡すだけ

####btn1のonClick（送り側）

```java
public void gotoSub(View view)
{
	//create intent
    Intent intent = new Intent(getApplication(), SubActivity.class);

    //param
    intent.putExtra("name","hoge");
    intent.putExtra("age",40);

    //start intent
    startActivity(intent);
}
```

####btn2のonClick（受け取り側）

特に受け取るイベントがないので、とりあえずonCreate()で受け取り。
受け取るときは型を意識する必要あり。

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sub);
    
    //create intent
    Intent intent = getIntent();
    
    //受け取り
    String name = intent.getStringExtra("name");
    Integer age = intent.getIntExtra("age",0);
    
    //内容出力
    Log.d("tama",name);
    Log.d("tama", age.toString());
}
```

###戻してもらう

難しくはないが、

* requestCodeが必要（一意ならなんでも良い）
* startActivityForResult()を使う
* onAcitivityResult()で受け取る

という形となる。

####btn1のonClick（送り側）

```java
public void gotoSub(View view)
{
    //create intent
    Intent intent = new Intent(getApplication(), SubActivity.class);

    //params
    intent.putExtra("name","hoge");
    intent.putExtra("age",40);

    //+requestcode
    int requestCode = 1000;

    //+startactivity
    startActivityForResult(intent,requestCode);
}

//+受け取り
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
    //もろもろ初期化・受け取り
    super.onActivityResult(requestCode, resultCode, intent);
    //受け取り
    String str = intent.getStringExtra("back");
    //出力
    Log.d("tama",str);
}
```

####btn2のonClick（受け取り側）

fisnish()の前に、Intentの処理をするが、一部、普通のパラメーター送りと形式が違う。

* setResult()で戻し値をセットする。

```java
public void gotoMain(View view)
{
    //create intent
    Intent intent = new Intent();
    intent.putExtra("back","back data");
    setResult(RESULT_OK,intent);

    finish();
}
```


##JSON連携

今の時代、何はなくてもJSON(API)連携です。通信はOkHttpとかでもいいのですが、結局複雑なことをやろうとするとVolleyになるのでVolley使います。

###準備：Volleyの読み込み

以前は何かと大変だったのですが、今は、build.grandelのdependenciesに追加すればいいみたいです。
追加するのは(Module:app)の方。

```js
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile 'com.mcxiaoke.volley:library:1.0.18'
}
```

Sync Nowをお忘れなく。

>バージョンは変わるので[ここ](https://github.com/mcxiaoke/android-volley)を参照。

###準備：internet使用許可

AndroidManifest.xmlに

```xml
<uses-permission android:name="android.permission.INTERNET"/>
```

を追加。\<application>と同じ階層。

>Android StudioでGUI使って追加する方法は無いのかな？

###Volleyの利用

btn1のコード（メソッド名がgotoSubなのは上からの流れでお許しを）。

最もシンプルなパターンを書く。btn1をクリックしたら、サーバからjson取得して、Log.d()で表示。
ちなみに、APIから帰ってくるJSONは、

```js
{"status":"OK","msg":"This is a message."}
```

こんなん。
では、Volleyのコード。

>以前書いたコードでは、「JsonObjectRequestがあいまいです」的なエラーが出てコンパイル出来なくなってしまっていまいた。第三引数のnullに(String)nullと型指定することで、回避しました。

```java
public void gotoSub(View view)
{
    //url
    String url = "http://www.bluecode.jp/test/json.php";

    //queue生成
    RequestQueue queue = Volley.newRequestQueue(this);

    //jsonRequest生成
    JsonObjectRequest jsonRequest = new JsonObjectRequest(Request.Method.GET,url,(String)null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject jsonObject) {

                    //JSONの処理
                    try{

                        //１階層目は普通に
                        String status = jsonObject.getString("status");
                        //出力
                        Log.d("tama", "status=" + status);

                    }catch(Exception e){
                        e.printStackTrace();
                    }

                }
            },
            new Response.ErrorListener(){
                @Override
                public void onErrorResponse(VolleyError error){
                    //
                }
            }
    );

    //Queueに追加
    queue.add(jsonRequest);
    
}
```
配列を受け取る方法は[こちら](http://qiita.com/zaburo/items/a868234c4028c2ff433c)もしくは、下記サンプルをどうぞ。

##ListView

感覚を思い出すための最小限のListView表示。

####最低限のListView

* ListViewを配置。lv1という名前にする。
* とりあえずgotoSub()にデータ読み込み・表示実装。

```java
public void gotoSub(View view)
{
    //表示用データ
    String[] strList = {"hoge","foo","shoo"};

    //ListView
    ListView lv = (ListView)findViewById(R.id.lv1);

    //Adapter
    ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,strList);
    
    //set adapter
    lv.setAdapter(arrayAdapter);
}
```

手順としては、

* データ生成（後でも良い）
* ListView生成
* Adapter生成（ListViewのテンプレートやバインドするデータはここで選ぶ）
* ListViewにAdapterをセット

という流れ。

####Volleyで取得した内容をListViewで表示

このへんから雲行きが怪しくなる。が、とりあえず動くコードを載せておきます。
事務用にJSONも変えました。

```js
{"status":"OK","msg":"This is a message.","members":["tanaka","suzuki","yamamoto","sato"]}
```

ListView取得はこんな感じ。配列はJSONArrayで受ける。

```java
public void goAction(View view)
{
    //url
    String url = "http://www.bluecode.jp/test/json.php";

    //queue生成
    RequestQueue queue = Volley.newRequestQueue(this);

    //jsonRequest生成
    JsonObjectRequest jsonRequest = new JsonObjectRequest(Request.Method.GET,url,(String)null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject jsonObject) {

                    //JSONの処理
                    try{

                        //配列の入れ物
                        ArrayList<String> arrayStr = new ArrayList<>();

                        //listview
                        ListView lv = (ListView)findViewById(R.id.lv1);

                        //ステータス取得
                        Log.d("tama","sattus="+jsonObject.getString("status"));

                        //members取得（配列）
                        JSONArray members = jsonObject.getJSONArray("members");

                        //ループしてArrayListへ
                        for(int i = 0; i < members.length(); i++){
                            arrayStr.add(members.getString(i));
                        }

                        //adapter
                        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getApplication(),android.R.layout.simple_list_item_1,arrayStr);

                        //set adapter
                        lv.setAdapter(arrayAdapter);

                        Log.d("tama","success");

                    }catch(Exception e){
                        e.printStackTrace();
                    }

                }
            },
            new Response.ErrorListener(){
                @Override
                public void onErrorResponse(VolleyError error){
                    //
                    Log.d("tama","error");
                }
            }
    );

    //Queueに追加
    queue.add(jsonRequest);
}
```

ここでは、一度ArrayListに入れていますが、JSONObjectを直接扱うカスタムクラス等を作ったほうがいいでしょう。
ListViewの基本は[ドットインストール](http://dotinstall.com/lessons/basic_android_listview_v2)でおさらいする。