RetrofitでYoutubeの動画情報を取得して，Androidアプリ内に保持する．

この記事では，大きく３つのことを行います．

1. [Youtubeから「共有」をした際の一覧に自分のアプリを登録する．](#-1-youtubeから共有をした際の一覧に自分のアプリを登録する)
2. [「共有」した際のリンク情報から，IDを取得し，そのIDからYoutubeの動画情報を取得する．](#-2-共有した際のリンク情報からidを取得しそのidからyoutubeの動画情報を取得する)
3. [Retrofit & GsonでAPIにアクセス．動画情報を取得アプリ上に表示する．](#-3-retrofit--gsonでapiにアクセス動画情報を取得アプリ上に表示する-)

コードは，ここにおいてます．[SharedText](https://github.com/NoirTomiyama/SharedText)

<a id="-1-youtubeから共有をした際の一覧に自分のアプリを登録する"></a>
## <a href="#-1-youtubeから共有をした際の一覧に自分のアプリを登録する"> 1. Youtubeから「共有」をした際の一覧に自分のアプリを登録する．</a>  
まず，Manifest.xmlにintent-filterを追加します．

```xml:AndroidManifest.xml
// ... 中略 ...
  <activity android:name=".SharedActivity">
      <intent-filter>
          <action android:name="android.intent.action.SEND" />
          <category android:name="android.intent.category.DEFAULT" />
          <data android:mimeType="text/plain"/>
      </intent-filter>
  </activity>
// ... 中略 ...
```

次にSharedActivity.javaで受け取ってみる．

```java:SharedActivity.java
public class SharedActivity extends AppCompatActivity {

    TextView textView;
    ImageView thumbnail;

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

        textView = findViewById(R.id.movieId);
        thumbnail = findViewById(R.id.thumbnail);

        Intent intent = getIntent();
        String id = null;

        if(intent.getType().equals("text/plain")){
            String text = intent.getStringExtra(Intent.EXTRA_TEXT);
            Log.d("text",text);
        }
    }
// ... 中略 ...
}
```

これでtextにIntentで渡ってきたリンクを受け取ることができます．

[参考]
 * [データのシェア - 他のプログラムからのデータを受け取る](http://android.keicode.com/basics/sharing-receiving-text.php)
 * [\# 暗黙的インテントを受け取る(ドキュメント)](https://developer.android.com/guide/components/intents-filters?hl=ja)

<a id="-2-共有した際のリンク情報からidを取得しそのidからyoutubeの動画情報を取得する"></a>
## <a href="#-2-共有した際のリンク情報からidを取得しそのidからyoutubeの動画情報を取得する"> 2. 「共有」した際のリンク情報から，IDを取得し，そのIDからYoutubeの動画情報を取得する．</a>  

### IDの取得方法

これは素直にリンクの文字列からIDを抜き出しました．
`https://youtu.be/yT_ylSCgY6Q`
という感じで文字列が取得できるので，後ろの`yT_ylSCgY6Q`が動画のID．

ちなみに，上のリンクでは，BUMP OF CHICKEN feat. HATSUNE MIKU「ray」に飛びます．

### Youtubeの動画情報を取得する．

[YouTubeの動画情報をData API v3を使って取得する](https://qiita.com/moshisora/items/4ea23d5abd7b4d852955)の記事のように，Youtubeの動画の情報を取得するには，[**Youtube Data API**](https://developers.google.com/youtube/v3/getting-started?hl=ja) を用います．
API keyを取得して，以下のURLをブラウザで入力してください．API Keyの取得については，[YouTubeの動画情報をData API v3を使って取得する](https://qiita.com/moshisora/items/4ea23d5abd7b4d852955) を参照してください．

```
https://www.googleapis.com/youtube/v3/videos?id=yT_ylSCgY6Q&key=【API Key】&fields=items(id,snippet(channelTitle,title,thumbnails),statistics)&part=snippet,contentDetails,statistics
```
【API Key】の部分に，取得したkeyを入力してください．

結果としては，以下のように得られます．

```json:result
{
 "items": [
  {
   "id": "yT_ylSCgY6Q",
   "snippet": {
    "title": "BUMP OF CHICKEN feat. HATSUNE MIKU「ray」",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/yT_ylSCgY6Q/default.jpg",
      "width": 120,
      "height": 90
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/yT_ylSCgY6Q/mqdefault.jpg",
      "width": 320,
      "height": 180
     },
     "high": {
      "url": "https://i.ytimg.com/vi/yT_ylSCgY6Q/hqdefault.jpg",
      "width": 480,
      "height": 360
     },
     "standard": {
      "url": "https://i.ytimg.com/vi/yT_ylSCgY6Q/sddefault.jpg",
      "width": 640,
      "height": 480
     },
     "maxres": {
      "url": "https://i.ytimg.com/vi/yT_ylSCgY6Q/maxresdefault.jpg",
      "width": 1280,
      "height": 720
     }
    },
    "channelTitle": "BUMP OF CHICKEN"
   },
   "statistics": {
    "viewCount": "12691874",
    "likeCount": "65136",
    "dislikeCount": "3062",
    "favoriteCount": "0",
    "commentCount": "4337"
   }
  }
 ]
}
```
[参考]
* [YouTubeの動画情報をData API v3を使って取得する](https://qiita.com/moshisora/items/4ea23d5abd7b4d852955)

<a id="-3-retrofit--gsonでapiにアクセス動画情報を取得アプリ上に表示する-"></a>
## <a href="#-3-retrofit--gsonでapiにアクセス動画情報を取得アプリ上に表示する-"> 3. Retrofit & GsonでAPIにアクセス．動画情報を取得アプリ上に表示する． </a> 
### 概要
* Retrofit: Android の HTTP クライアントライブラリ
* Gson: JSON を Java のオブジェクトに変換するライブラリ

### 導入
* build.gradle (Module: app) に追加

```gradle
dependencies {
    // ... 中略 ...
    implementation 'com.google.code.gson:gson:2.8.4'
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    // ... 中略 ...
}
```
[参考]
* [Retrofit](http://square.github.io/retrofit/#download)
* [Gson](https://github.com/google/gson)

### APIのインタフェースの実装
```java:ApiService.java
public interface ApiService {
    @Headers("Accept-Language: ja")
    @GET("/youtube/v3/videos?")
    Call<APIResponse> requestMovie(@Query("id") String id,
                                    @Query("key") String key,
                                    @Query("fields") String fields,
                                    @Query("part") String part);
}
```
### API から取得したデータを Java オブジェクトとして格納するクラスを定義

```java:APIResponse.java
public class APIResponse {

    public List<Item> items;

    public List<Item> getItems() {
        return items;
    }
}
```

```java:Item.java
public class Item {

    @SerializedName("id")
    private String id;

    @SerializedName("snippet")
    private Snippet snippet;

    @SerializedName("statistics")
    private Statistics statistics;

    public String getId() {
        return id;
    }

    public Snippet getSnippet() {
        return snippet;
    }

    public Statistics getStatistics() {
        return statistics;
    }
}
```

```java:Snippet.java
public class Snippet {

    @SerializedName("title")
    private String title;

    @SerializedName("thumbnails")
    private Thumbnails thumbnails;

    public class Thumbnails {

        @SerializedName("default")
        public Default aDefault;

        @SerializedName("medium")
        public Medium medium;

        @SerializedName("high")
        public High high;

        public High getHigh() {
            return high;
        }

        @SerializedName("standard")
        public Standard standard;

        @SerializedName("maxres")
        public Maxres maxres;


        public class Default {
            String url;
            String width;
            String height;
        }

        public class Medium {
            String url;
            String width;
            String height;

        }

        public class High {
            String url;
            String width;
            String height;

            public String getUrl() {
                return url;
            }
        }

        public class Standard {
            String url;
            String width;
            String height;
        }

        public class Maxres {
            String url;
            String width;
            String height;
        }

    }

    @SerializedName("channelTitle")
    String channelTitle;

    public String getTitle() {
        return title;
    }

    public Thumbnails getThumbnails() {
        return thumbnails;
    }

    public String getChannelTitle() {
        return channelTitle;
    }
}
```

```java:Statistics.java
public class Statistics {

    @SerializedName("viewCount")
    String viewCount;

    @SerializedName("likeCount")
    String likeCount;

    @SerializedName("dislikeCount")
    String dislikeCount;

    @SerializedName("favoriteCount")
    String favoriteCount;

    @SerializedName("commentCount")
    String commentCount;


    public String getViewCount() {
        return viewCount;
    }

    public String getLikeCount() {
        return likeCount;
    }

    public String getDislikeCount() {
        return dislikeCount;
    }

    public String getFavoriteCount() {
        return favoriteCount;
    }

    public String getCommentCount() {
        return commentCount;
    }
}
```
記事を書いていて，修飾子まわりをあまり考えずに書いてしまっていたことに気づいたので，そのあたりはよしなにしていただけると嬉しいです．

### YouTube Data API v3にアクセスし、動画の情報を取得するための処理の実装
```java:MainActivity.java
public class MainActivity extends AppCompatActivity {

    private Retrofit mRetrofit;
    private ApiService mService;

    // API KEY 各自Consoleから作成
    private final String API_KEY = "dummyAPIKey"; // 適宜APIKeyを変えてください．
    private final String FIELDS = "items(id,snippet(channelTitle,title,thumbnails),statistics)";
    private final String PART = "snippet,contentDetails,statistics";

    // "BUMP OF CHICKEN feat. HATSUNE MIKU「ray」"
    private String testId = "yT_ylSCgY6Q";

    ImageView picture;
    TextView title;
    Button button;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRetrofit = new Retrofit.Builder()
                .baseUrl("https://www.googleapis.com")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        mService = mRetrofit.create(ApiService.class);

        picture = findViewById(R.id.picture);
        title = findViewById(R.id.title);
        button = findViewById(R.id.button);
        button.setOnClickListener(onClickListener);
    }
    
    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            Call<APIResponse> mCall = mService.requestMovie(testId,API_KEY,FIELDS,PART);

            mCall.enqueue(new Callback<APIResponse>() {
                @Override
                public void onResponse(Call<APIResponse> call, Response<APIResponse> response) {

                    // レスポンスからItemを取得
                    List<Item> items = response.body().getItems();

                    for(Item item : items){

                        Uri uri = Uri.parse(item.getSnippet().getThumbnails().getHigh().getUrl());
                        Uri.Builder builder = uri.buildUpon();
                        AsyncTaskHttpRequest task = new AsyncTaskHttpRequest(picture);
                        task.execute(builder);
                        
                        title.setText(item.getSnippet().getTitle());
                    }
                }

                @Override
                public void onFailure(Call<APIResponse> call, Throwable t) {

                }
            });

        }
    };
    

}

```
なお，URLから画像を取得し，ImageViewに表示させるのに，以下のサイトを参考にしました．上のコードをコピペしても，AsyncTaskHttpRequestクラスが未定義になるので，注意してください．
[参考]
* [【Androidプログラミング入門 #007】ネット上の画像を取得しImageViewに表示する](http://android.swift-studying.com/entry/20151024/1445666337)

### レイアウトファイルの実装
```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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=".MainActivity">

    <ImageView
        android:id="@+id/picture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toTopOf="@+id/title"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/title"
        app:layout_constraintVertical_bias="0.3" />

</android.support.constraint.ConstraintLayout>
```

```xml:activity.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".SharedActivity">

    <ImageView
        android:id="@+id/thumbnail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="8dp"
        android:padding="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.201"
        app:srcCompat="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/movieId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="TextView"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
```

### AndroidManifest.xml
念の為，マニフェストファイルも載せておきます．

```xml:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomiyama.noir.sharedtext">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".SharedActivity">

            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain"/>

            </intent-filter>
        </activity>
    </application>

</manifest>
```

[参考]
Retrofit周りでAPIにアクセスしたりするあたりで非常に参考になりました．また，細かい点は，Githubにあげてるコードを参照してください．
* [Retrofit + Gson で、 API にアクセス & JSON のパージング処理を簡潔に実装する](https://qiita.com/Hachimori/items/c7349ec068924b7ce045)