tsurutanのつぶやき

備忘録としてつぶやきます

Pythonでスクレイピングをしてみよう!

f:id:tsurutan:20161006123120j:plain

今回はPythonでスクレイピングをするやり方について説明しようと思います。

まだpythonを始めたばかりスクレイピングって難しそうだけどどうやってやるの?と苦しんでいる読者を想定しています。

Scrapingでできること

店舗一覧、商品一覧を抽出する ・ニュースサイトからヘッドライン一覧を抽出する ・ページのURLを全て抽出する などなど今まで煩わしかったことが解消できます!

Pythonの開発環境を整える

まずはPythonの開発環境を整えましょう。

ただ今回は日本語を今後扱うことを前提としてpython3のインストールの仕方について説明したいと思います。(pythonだと日本語の扱いがめんどくさい)

Homebrewのインストール

homebrewとはパッケージ管理システムで、ターミナルからコマンドを打ち込むことで簡単にインストールすることができます。

まずはxcodeツールが入っているか確認してください。

入っていなければ下記のコマンドを入力してください。

sudo xcode-select --install

そして次に公式サイトに書いてある通り

brew.sh

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

を入力してください。これで完成です。

python3のインストール

先ほどインストールしたbrewを使ってpython3を持ってきたいと思います。

まず

$ brew search python
app-engine-python                        python                                 
boost-python                             python3                                
gst-python                               wxpython                               
homebrew/versions/gst-python010          zpython                                
homebrew/apache/mod_python               Caskroom/cask/python                   
homebrew/python/python-dbus              Caskroom/cask/python3                  
homebrew/python/vpython                

と入力し、python3があることを確認しましょう。

確認が取れましたらpython3のインストールを行います。

brew install python3

はい、これで完成です。とても簡単ですね!

スクレイピングをしてみよう

スクレイピングをするにあたってまずseleniumBeautifulSoupをインストールしましょう。

これらをインストールするのもとても簡単で

pip3 install beautifulsoup4

pip3 install selenium

を入力すれば完了です。

また、seleniumではchrome driverというchromeを仮想的に立ち上げるドライバーが必要となるので

sites.google.com

ここからダウンロードし、適切なフォルダに保存しておいてください。(後でpathを指定するのでわかりやすいところに)

さて準備が整いましたのでコードに移っていきたいと思います。

news.yahoo.co.jp

今回はyahoo newsのトピック一覧から記事のタイトルと遷移先、カテゴリーを取ってくるところを実装してみたいと思います。

まず初めに先ほどインストールしたselniumとbeautifusoupをインポートします

from selenium import webdriver
from bs4 import BeautifulSoup

次にwebdriverの初期化を行います。

driver = webdriver.Chrome("/path/tmp/chromedriver")

webdriver.Chromeに渡しているのは先ほどダウンロードしたchrome driverのpathです。

そして本題、いよいよニュース記事の取得に入っていこうかと思います。

def get_yahoonews():
        driver.get("http://news.yahoo.co.jp/list/?c=world")
        html = driver.page_source
        soup = BeautifulSoup(html, "html.parser")
        for list in soup.body.find("ul", class_="list").find_all("li"):
            category = list.find("span", class_="cate").string
            title = list.find("span", class_="ttl").string
            href = list.a.get("href")

まずdriver.getの引数にyahoo newsの記事のurlを渡しております。 そして

html = driver.page_source
soup = BeautifulSoup(html, "html.parser")

webdriverで取得したhtmlを解析できるようにBeautifulSoupに渡します。

そして

for list in soup.body.find("ul", class_="list").find_all("li"):
            category = list.find("span", class_="cate").string
            title = list.find("span", class_="ttl").string
            href = list.a.get("href")

ここで解析を行ってタイトルと、カテゴリーと遷移先を取得しているのですが

まず一行目に

for list in soup.body.find("ul", class_="list").find_all("li")

と書いてあるのですがこれは、yahoo newsのページをhtmlで見てもられると分かるのですが(chromeであればCommand + Space + iで見ることができます)

f:id:tsurutan:20161006121605p:plain

このようにニュースがリスト状になっております。(liの中に記事が入っています)

よってこのニュースリストの要素をpythonで見れるようにfor分で回しているのです。

そして子要素を見てみると

f:id:tsurutan:20161006122139p:plain

このようにタイトルとカテゴリー、遷移先のurlが入っているので、これを

category = list.find("span", class_="cate").string
            title = list.find("span", class_="ttl").string
            href = list.a.get("href")

と書いて取得しているのです。

どうですか?簡単でしょう?

課題

アマゾンの食品一覧から、タイトル、遷移先を取得しなさい。

Amazon.co.jp: 食品: 食品・飲料・お酒

所感

www.tsurutan.com

以前Rubyでスクレイピングをする記事を書いたのですが、個人的にpythonの方が書きやすかった印象があります。

またChromeを仮想的に立ち上げることでiframeなどの時間差で表示されるものも取得できるのでとても使いやすかったです。

また、気をつけて欲しいのはスクレイピングを間を空けずやってしまうとDoS攻撃になってしまうので、10秒ほどの間隔を取ってやることにしましょう!

PythonによるWebスクレイピング

PythonによるWebスクレイピング

実践 Webスクレイピング&クローリング-オープンデータ時代の収集・整形テクニック

実践 Webスクレイピング&クローリング-オープンデータ時代の収集・整形テクニック

JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック

JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック

Android レイアウトの境界線を表示して開発速度を上げる

f:id:tsurutan:20161004220116j:plain

Android Studioで開発をしている場合、デフォルトのLayout Viewerや最近実装されたConstraint Layoutでだいぶデザインの調整がしやすくなっているのですが、いかんせんアプリを動かしてみると想定外のバグが発生してしまします。

そこで、アプリを起動しながらレイアウトの境界線を表示する方法を紹介したいと思います。

レイアウトの境界線の表示方法

まず、初めにAndroidの設定画面を開き端末情報をタップします。

そして下の方にスクロールして言うと ビルド番号 と書かれたところがあるので、そこを7回ほどタップします。

f:id:tsurutan:20161004214920j:plain

すると 開発者向けオプション という新しい項目が出てくるのでそちらをタップします。

f:id:tsurutan:20161004214937j:plain

そして、下の方にスクロールしていくと レイアウト境界を表示 とあるので、そちらをオンにします。

f:id:tsurutan:20161004214947j:plain

するとこのようにレイアウトの境界線が表示されるのです。

f:id:tsurutan:20161004215048j:plain

レイアウトの境界線が表示されることで、細かいデザインの修正(パッディングやマージン)を効率的に行うことができ、また今まで気づかなかったバグを見つけるなど良いことづくしです。(見た目も厨二病っぽくてカッコ良いですね笑)

Smashing Android UI レスポンシブUIとデザインパターン

Smashing Android UI レスポンシブUIとデザインパターン

中二病大事典

中二病大事典

Android Security Internals: An In-Depth Guide to Android's Security Architecture

Android Security Internals: An In-Depth Guide to Android's Security Architecture

Android 簡単にテレビ電話を実装する [Skyway]

f:id:tsurutan:20161004115601p:plain

今回はAndroidでテレビ電話を実装する方法を説明したいと思います。

使用するのはNTT Communicationsさんが提供しているSkywayというライブラリーです。

SkywayはWebRtcを使って、テレビ電話を実現したもので通信処理などの煩わしい部分をこのライブラリーが賄っており、簡単に実装することができます。

Skywayを入れるには?

現在Skywayではライブラリーがmaven上に存在しない為、手動でローカルにとってこないといけません。

github.com

こちらからzipファイルをダウンロードし、解凍したら中にSkyWay.aarというファイルがあるのでそれをandroidプロジェクトのapp直下にあるlibsディレクトリに入れてください。

そして app下のbuild.gradle

compile (name: 'SkyWay', ext: 'aar')

と記入し、プロジェクト下のbuild.gradle

allprojects {
    repositories {
        //何かしらのコード
        flatDir {
            dirs 'libs'
        }
    }
}

と記入すれば完成です。これでAndroid内にSkywayライブラリーをインポートすることができます。

API Keyの取得

Skywayライブラリーを使用するためにはAPI key とドメイン名が必要になるためこちらの公式ページから登録を行ってください。

nttcom.github.io

Skywayの使い方

github.com

こちらのサンプルファイルをベースに説明していきたいと思います。

まず初めにPeerの作成をします。

       PeerOption options = new PeerOption();

        //Enter your API Key.
        options.key = "";
        //Enter your registered Domain.
        options.domain = "";

        _peer = new Peer(context, options);

この時 options.key には先ほど取得したAPI Keyを options.domain にはドメイン名をセットしてください。 PeerOption にはkeyやdomain以外にもhostやport, debugなど様々な設定を与えることができます。

そしてPeerを作成した後にリスナーをセットします。

peer.on(Peer.PeerEventEnum.OPEN, new OnCallback()
        {
            @Override
            public void onCallback(Object object)
            {
                Log.d(TAG, "[On/Open]");

                if (object instanceof String)
                {
                    _id = (String) object;
                    Log.d(TAG, "ID:" + _id);

                    updateUI();
                }
            }
        });

        // !!!: Event/Call
        peer.on(Peer.PeerEventEnum.CALL, new OnCallback()
        {
            @Override
            public void onCallback(Object object)
            {
                Log.d(TAG, "[On/Call]");
                if (!(object instanceof MediaConnection))
                {
                    return;
                }

                _media = (MediaConnection) object;

                _media.answer(_msLocal);

                setMediaCallback(_media);

                _bCalling = true;

                updateUI();
            }
        });

        // !!!: Event/Close
        peer.on(Peer.PeerEventEnum.CLOSE, new OnCallback()
        {
            @Override
            public void onCallback(Object object)
            {
                Log.d(TAG, "[On/Close]");
            }
        });

        // !!!: Event/Disconnected
        peer.on(Peer.PeerEventEnum.DISCONNECTED, new OnCallback()
        {
            @Override
            public void onCallback(Object object)
            {
                Log.d(TAG, "[On/Disconnected]");
            }
        });

        // !!!: Event/Error
        peer.on(Peer.PeerEventEnum.ERROR, new OnCallback()
        {
            @Override
            public void onCallback(Object object)
            {
                PeerError error = (PeerError) object;

                Log.d(TAG, "[On/Error]" + error);

                String strMessage = "" + error;
                String strLabel = getString(android.R.string.ok);

                MessageDialogFragment dialog = new MessageDialogFragment();
                dialog.setPositiveLabel(strLabel);
                dialog.setMessage(strMessage);

                dialog.show(getFragmentManager(), "error");
            }
        });

これでPeerの作成は完了です。

次にカメラで撮影された映像を、自分のデバイスで表示したいと思います。

void startLocalStream(){
        Navigator.initialize(_peer);
        MediaConstraints constraints = new MediaConstraints();
        _msLocal = Navigator.getUserMedia(constraints);

        Canvas canvas = (Canvas) findViewById(R.id.svSecondary);
        canvas.addSrc(_msLocal, 0);
    }

まず初めに 映像を取得するクラス Navigatorに先ほど作成したPeerを渡します。

そして Navigatorのオプション的役割を持つ MeidaConstraints を作成し Navigator.getUserMedia の引数に渡します。

MeidaConstraintsにも様々なオプションがあり、動画のみ、音声のみ、フロントカメラなどの設定をすることができます。

これでstreamが取得できたので、これをCanvasに渡せばローカルのストリーム再生は完成です。

そして最後に呼び出しの部分ですね。

void calling(String strPeerId)
    {
        //////////////////////////////////////////////////////////////////////
        ////////////////// START: Calling SkyWay Peer   //////////////////////
        //////////////////////////////////////////////////////////////////////

        if (null == _peer)
        {
            return;
        }

        if (null != _media)
        {
            _media.close();
            _media = null;
        }

        CallOption option = new CallOption();

        _media = _peer.call(strPeerId, _msLocal, option);

        if (null != _media)
        {
            setMediaCallback(_media);

            _bCalling = true;
        }

        //////////////////////////////////////////////////////////////////////
        /////////////////// END: Calling SkyWay Peer   ///////////////////////
        //////////////////////////////////////////////////////////////////////


        updateUI();
    }

ここの _media = _peer.call(strPeerId, _msLocal, option);でコールをしています。第一引数には呼び出し先のPeer Idを指定しています。

ちなみにPeer IdはPeerを作成するときに指定することができます。デフォルトはランダムでIDは振り当てられます。

第二引数では先ほど作成したローカルのストリームが渡され、第三引数にはCallOptionが渡されます。

はい、これでテレビ電話の実装が完成しました。

いかがでしたでしょうか?

これで皆さんもテレビ電話機能を持つサービスを簡単に作ることができますね!

詳しいドキュメントは公式ページに記載されていますので、ぜひ目を通してみてください。

SkyWay ドキュメント

Android Retrofit 2 を使った Http通信

今日はRetrofit2を使ってAndroidのHttpレスポンスの実装方法を紹介したいと思います。

Retrofit2って?

f:id:tsurutan:20161004000732j:plain

Retrofit2はSquare(Jake 神)が開発しているネットワークアクセスライブラリです。

特徴的なのはサーバ側のAPIをインタフェースとして定義することで、API呼び出しの実装とAPI定義を分離しコードの見通しを簡潔に保つことができるという点です。

実装とAPI定義が分離しているため、後からAPIを追加することも容易となり保守性の高い設計ができそうです。

以前まではVolleyが主流でしたが今のイケてるサービスはほとんどRetrofit2を使っているのではないのでしょうか?

使い方

まず、想定として http://example.com/users/tsurutan/get というレスポンスを叩くと

{"user": {
  "id": 100,
  "name": "tsurutan",
}}

といったJsonが返ってくるとします。

この時Retrofit2では

public interface UserService {
  @GET("users/{user}/get")
  Call<User> getUser(@Path("user") String user);
}

このように記述します。

まずAPI用のインタフェースを作成します。

@GET というアノテーションがありますがこれは文字通りゲットレスポンスを表します。@Get以外にも@Post@Deleteなど様々なレスポンスに対応しております。

ただし@Patchは残念ながら存在しない為Postにヘッダーを加えてPatchに変換しないといけません。

また@Postを使ってMultipart通信を行えないのが少し難点かもしれません。。(この場合はIonやVolleyと言ったライブラリーを別途使った方が良いかもしれません)

また @Get( ) の中身にはレスポンスのエンドポイントを記します。

この場合エンドポイントの{user}の部分が各ユーザーごとに異なると思うのでその場合メソッドの引数に @Pathと指定し動的に変更することができます。

そしてCallの型に指定されているUserはgsonを使ったクラスで表されます。

gsonって何?という方に簡単にgsonについて説明したいと思います。

GSONは、Googleが提供するJSONデータとJavaオブジェクトを相互に変換するためのライブラリです。 JavaでJSONを扱うためのライブラリは他にJackson、JSONIC等があります。 GSONのメインとなるのは Gson クラスです。

例えば先ほどの

{"user": {
  "id": 100,
  "name": "tsurutan",
}}

というJsonのレスポンスを

class User {
  private int id;
  private String name;

  public int getId() {
    return id;
  }
  
  public void setId(int id) {
    this.id = id;
  }
  
  public String getName() {
    return name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
}

と言ったクラスを記述することでJsonをオブジェクトにパースしてくれる優れたライブラリーなのです。

注意して欲しいのは変数の名前とJsonのkeyの名前が一致しているということです。

これはgsonが自動的に判断してくれる為あえてこのようにしております。

またkeyにtsuru_tanと言った感じにアンダーバーが入る場合はtsuru_tanとするか、gsonのフォーマット規約を変更してtsuruTanのように記述することもできます。

retrofit 2ではこのgsonを介することでapiから間接的にオブジェクトを取得することができるのです。

次に

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://example.com/")
 .addConverterFactory(GsonConverterFactory.create())
    .build();

UserService service = retrofit.create(UserService.class);

と記述します。このようにして先ほど作成したインタフェースを呼び出すのです。

ここで addConvertFactoryGsonConverterFactory.create()を渡しているのは先ほど説明したgsonを使う為メソッドを呼び出しております。

そして最後に

service.getUser("tsurutan").enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccess()) {
                    //Success !!
                } else {
                    Toast.makeText(getActivity(), getString(R.string.error_text), Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                Toast.makeText(getActivity(), getString(R.string.error_text), Toast.LENGTH_SHORT).show();
            }
        });

と記入します。getUserで引数にuser名を渡しその後enqueueでコールバックに対するコードを記入します

            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccess()) {
                    User user = response.body();
                    //Success !!
                } else {
                    Toast.makeText(getActivity(), getString(R.string.error_text), Toast.LENGTH_SHORT).show();
                }
            }

このメソッドはレスポンスのコードが400~451以外の時に呼び出されます。

またresponse.isSuccess()ではコードが200~226の時にtrueを返します。

そして成功した時にresponse.body()を呼び出すことで、先ほど作成したUserを受け取ることができます。

AndroidにおいてはAPI通信を非同期で行わなければならなく、以前までは非常にこのあたりのコードが長くなっておりました。

しかしこのようなライブラリーの登場でコードの簡潔化、開発の爆速化が実現しました。

Jake神に足を向けて寝ることはもう出来ませんね。

どうやって使うの?

compile 'com.squareup.retrofit2:retrofit:(insert latest version)'

お馴染みapp層のbuild.gradleにこの一行を加えるだけです!

簡単すぎて笑えてきますね!

超初心者でも大丈夫! はじめてのAndroidプログラミング Android Studio 2対応

超初心者でも大丈夫! はじめてのAndroidプログラミング Android Studio 2対応

ランダムフォレスト(機械学習)による文章分類

前置き

今回はランダムフォレストという手法で機械学習を行い文章の分類を行おうと思います。

例えばこのような生物医療に使われるデータベースがあったとします。

name of enzyme

alkaline phosphatases

comment

Comparison with alkaline phosphatases and 5-nucleotidase

name of enzyme酵素の名前で comment はその酵素についてのコメントです。 このようなデータベースを普通使うことはないと思うのですが、とりあえずこちらを使います。

想像してみてください。

あなたは生物学者です。

あなたは研究で扱った酵素について一つ一つコメントをつけ、データベースに保存していました。

しかし、ある日不運なことに一部酵素の名前データーが破損してしまいました。

この時、あなたは酵素とコメントがセットになっているデータとコメントのみのデータを持っています。

そこであなたは紛失してしまった酵素の名前をコメントを元に復元したいと考えました。

そこで扱うのが機械学習ランダムフォレストです。

機械にコメントと酵素の名前を学習させて、その後コメントから酵素の名前を予測してもらいましょう。

ツール

機械学習するためのツールを準備します。 使用する言語はpythonで、ライブラリーとして gensimsklearn を使用します

gensim

これはのちに説明するのですが、特徴ベクトルを作成するために使います。
特徴ベクトルとは機械がコメントを学習できるようにするために数値のベクトルで表されたものです。

sklearn

このライブラリーは機械学習などを行うために必要となるモジュールが豊富に含まれているものです。
今回はsklearnのランダムフォレストを使って学習を行います。

これらのライブラリーは pip install gensim pip install sklearnでインストールすることができます。とても簡単ですね!

それではまず、コメントから重要そうな単語を取り出します。

from gensim import corpora
import mysql

mysql = mysql.MySql()
words = []
for line in mysql.read_medtag():
    words.append(line["comment"].split(" "))

dictionary = corpora.Dictionary(words)
dictionary.filter_extremes(no_below=3, no_above=0.3)
dictionary.save_as_text('dict.txt')

このコードで何をしているか説明すると、

mysql = mysql.MySql()
words = []
for line in mysql.read_medtag():
    words.append(line["comment"].split(" "))

ここでデータベースからコメントを読み込み、スペースを区切りに文章を単語に分解して words という配列に格納していきます。

そして残りのコード

dictionary = corpora.Dictionary(words)
dictionary.filter_extremes(no_below=3, no_above=0.3)
dictionary.save_as_text('dict.txt')

では特徴語を作成し、dict.txt に保存しておきます。テキストに保存することで再度データベースを呼び出すことがなく、学習時間が節約できます。特にデータベースが大きいときには有効です。 corpora とはgensim に含まれているクラスでこちらを使い特徴語の辞書を作成します。 dictionary.filter_extremes(no_below=3, no_above=0.3) では特徴語として相応しくない単語を除いております。 no_below で指定された数値より下回る頻度で出現した単語は特徴語としてみなされず、また逆に no_above で書かれた割合より多く出現している単語は除かれます。ただ単に出現頻度が高い単語を特徴後とするのはあまり良い考えではないからです。(I He などの単語は出現頻度は高いが重要ではない)

少し長くなってしまったので、次回にランダムフォレストの実装について説明しようと思います。

アプリを大量生産してGoogleを怒らせた話

先日RSSをキーワード入力から登録できるアプリケーションを開発しリリースしました。

f:id:tsurutan:20160817113038p:plain

ところが。。。

f:id:tsurutan:20160823205336p:plain

なんとポリシー違反ということでアプリが停止されてしましました。

露骨な性表現を含むコンテンツに関するポリシーに違反だったのですが、どうやら検索キーワードで性的なものを入力するとヒットしてしまうのが原因だったっぽいです。

しかし、せっかく作ったアプリを公開できないのは勿体ないなあと考え、これを2chまとめアプリとして量産できないかという案が浮かびました。

そこでリリースしたアプリをベースに1日2個、ある分野に特化した2chまとめアプリを開発しリリースしました。

f:id:tsurutan:20160823204701p:plain

順調に開発しリリースしていたのですが、「声優まとめ速報」という9個目のアプリをリリースした後にこのようなメールが届きました。

f:id:tsurutan:20160823205427p:plain

「!?!?!?!?!?!?!?」

最初このメールが来た時、何が何だか分かりませんでした。

このメールにはどうやらyoutubeがバックグラウンド再生される実装がなされているためポリシーに違反するということだったらしい。しかし、そのような機能は実装していないし。。 WebViewを使っているので、そこからyoutubeを再生してバックグラウンド再生されてしまうのだろうか?そして、どうしてこのアプリだけ承認されなかったのか?(他のアプリは全く同じコードで書かれているが、無事リリースされている)

などなど色々と疑問をgoogleに申し出してみたのですが、googleさんからは同じ内容を記されたテンプレートメールが返ってきました。

これはダメだと諦めやや疑問を残しながらも、作業を進め次々とアプリを量産していきました。

そして12個目のアプリ「ゲームまとめ速報」をplay storeにあげた後再びgoogleさんから

f:id:tsurutan:20160823210120p:plain

露骨な性表現を含むコンテンツに関するポリシーに違反をしたためアプリを停止した旨が書かれたメールが届きました。

一応、前回違反を停止されたのを教訓に性表現を含むコンテンツを表示しないように厳選したサイトを登録していたのですが。。

何度アプリを見ても、そのような表現を持ったページにはいかないのに。。

正直このアプリが違反になってしまうと現在リリースされている他のアプリも対象になってしまいます。

そして、アプリを3個以上停止されてしまうと、アカウントも停止されてしまいます。

そう、今私は2個アプリを停止されています。

リーチです。

現在リリースしているアプリで割と利益が出ていたのですが、アカウント停止を喰らうとこのアプリも停止されてしまいます。

これはヤバイと考えた私は、汗水流して量産したアプリケーションを全て公開停止にしました。

勿体なかったのですが、やはりアカウント停止を避けるためには仕方ありません。

そしてこれから私は「あと一回違反するとアカウント停止」というナイフを突きつけられながらアプリを開発するのです。

これに懲りてアプリを大量生産することを辞めます。

そして、今回頻繁にアプリを開発しリリースをしていたことでgoogleさんに目をつけられるようになった気がします。

アプリを絞って地道に開発していった方が精神的にも良いということを身を持って感じました。

AndroidでJava8を使う(Jackツールチェーン)

Jackツールチェーン

今回はAndroidでJava8を使う方法を紹介したいと思います。 以前までretrolambdaというライブラリーが主流でしたが、Android StudioがアップデートしJackツールチェーンというAndroid StudioでJava8が有効にできる素晴らしいツールが使えるようになり至るところの会社がjackツールチェーンに移行し始めている頃です(多分)。 Jackツールチェーンで扱えるJava8の機能は下記のようになります。

さらにさらに下記のJava8機能のAPIも使えるようになりました。

リフレクションおよび言語関連の API

  • java.lang.FunctionalInterface
  • java.lang.annotation.Repeatable
  • java.lang.reflect.Method.isDefault()
  • 以下のような反復アノテーション関連のリフレクション API AnnotatedElement.getAnnotationsByType(Class)

ユーティリティ API

  • java.util.function

ただし前のAndroidバージョンでテストをする際は、必ず build.gradle ファイルの compileSdkVersion と targetSdkVersion の値を 23 以下に設定しないといけません。

ちなみにラムダ式を使うと

findViewById(R.id.button).setOnClickListener(new View.setOnClickListener() {
  @Override
  public void onClick(View view) {
    // event
  }
});

これが。。。

findViewById(R.id.button).setOnClickListener(view -> {
  // event
});

こうなります!!最高ですね。

Gradle設定

Jackツールチェーンを有効にするにはapp直下の build.gradle を下記のように書き直します。

android {
  ...
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

以上です!

既知の問題

残念ながらJackチェーンツールにも問題点があります。 Android Studio 2.0(ベータ版)で導入された Instant Run は、現段階では Jack と併用できません。そのため新しいツールチェーンの使用中は、Instant Run が無効になります。

Jack はアプリのコンパイル中に中間クラスファイルを生成しないため、中間ファイルに依存する以下のようなツールは現在 Jack と併用できません。

  • クラスファイルに作用する Lint Detector
  • アプリのクラスファイルを必要とするツールやライブラリ(JaCoCo や Mockito など)

Effective Android

Effective Android

  • 作者: TechBooster,小太刀御禄,出村成和,重田大助,西岡靖代,宮川大輔,柏本和俊,あんざいゆき,八木俊広,木村尭海,小林慎治,有山圭二,中西良明,わかめまさひろ,新井祐一,桝井草介,久郷達也,寺園聖文,shige0501,山下智樹,前田章博,秋葉ちひろ,末広尚義,中澤慧,日高正博,塚田翔也,井形圭介,中川幸哉,山崎誠,山下武志,なまそで,橋爪香織,さとうかずのり,l_b__,ゼロハチネット,長汐祐哉
  • 出版社/メーカー: インプレスジャパン
  • 発売日: 2014/01/17
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (8件) を見る

Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka

Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka

Learning Reactive Programming with Java 8

Learning Reactive Programming with Java 8