phicdy devlog

Androidアプリ開発やその他技術系の記事をたまに書きます

AndroidとかiOSとかモバイル多め。その他技術的なことも書いていきます。

【Java】メインスレッドから別スレッドの停止

自分用メモ。


メインスレッドからの停止

  • Thread#interrupt()で行う。Thread#stop()メソッドは安全性を壊す可能性があり、非推奨
  • Thread#interrupt()自体はインタラプト状態を変更するだけ。
  • ただし、スレッドがThread#sleep(), Thread#wait(), Thread#join()を実行して止まっている間にThread#interrupt()を実行するとInterruptedExceptionを投げる。
  • これはThread#sleep(), Thread#wait(), Thread#join()側がメソッドの中でスレッドのインタラプト状態を見て、明示的にInterruptedExceptionを投げているため
  • Thread#sleep(), Thread#join()を読んだスレッドに対しては、Thread#interrupt()を実行する際にスレッドのロックを取る必要はなく、いつでも呼ぶことができる
  • Thread#wait()を呼んだスレッドに対してThread#interrupt()を呼ぶとロックを再び取り直してからInterruptedExceptionを投げる
  • Thread#isInterrupted()でインタラプト状態を取得できる


スレッド自身を止めるメソッド

メソッド 説明
sleep() 指定された時間だけ実行を停止
wait() スレッドがウェイトセットに入ってnotify/notifyAllされるのを待つ
join() 指定したスレッドが終了するのを待つ


コード

public class Sample {
     private Thread thread = null;

     public void startThread() {
         thread = new Thread() {
              @Override
               public void run() {
                   while(!isInterrupted()) {
                        // 処理
                   }
               }
         };
         thread.start();
     }

     public void stopThread() {
         if (thread == null) {
             return;
         }
         thread.interrupt();
     }
}

Intel Stick PCを買いました

f:id:phicdy:20150612194158j:plain

インテルから発売されたIntel Stick PCを買いました。

www.iodata.jp


Intel Stick PCとは

  • インテルから発売されたスティック型のPC
  • テレビのHDMIポートに刺して使う
  • サイズは37(W)×103(D)×12(H)mmで非常に小さい
  • Windows8.1搭載
  • 値段はアイ・オー・データのページで税込み22140円
  • 冷却ファンを搭載し、安定な動作を実現


スペック

アイ・オー・データのページより抜粋

www.iodata.jp

項目 仕様
OS Windows 8.1 with Bing 32ビット
CPU インテル® Atom™ プロセッサー Z3735F(4コア、1.33GHz)
メモリ DDR3L(1.35V、1333 MHz、2GB)
ストレージ 32GB eMMC
解像度 1920×1080
通信機能 IEEE802.11b/g/n、Bluetooth4.0
インターフェイス HDMI映像出力×1、USB 2.0ポート×1、microSDXCカードスロット×1
ネットワーク IEEE 802.11 b/g/n、Bluetooth® V4.0
外形寸法(本体のみ) 37(W)×103(D)×12(H)mm ※突起部除く
質量(本体のみ) 約54g


中身

f:id:phicdy:20150612195348j:plain

  • 本体
  • 電源アダプター
  • 変換プラグ
  • HDMI延長ケーブル
  • 電源供給用USBケーブル
  • マカフィーアンチウイルスプラス1年ライセンス
  • かんたんセットアップガイド
  • Quick Start Guide(英語)

電源アダプターの変換プラグが何種類かついているので海外旅行にも持っていけそう。。。

f:id:phicdy:20150612195726j:plain


接続

まず電源アダプターに日本用のプラグをつける。

f:id:phicdy:20150612195852j:plain

f:id:phicdy:20150612195909j:plain

f:id:phicdy:20150612195924j:plain

電源アダプターと本体をUSBケーブルで繋ぐ

f:id:phicdy:20150612200001j:plain

テレビのHDMIポートに接続する。

電源アダプターをコンセントに入れると自動で電源がつく

f:id:phicdy:20150613115939j:plain

初期設定の注意点として有線マウス・キーボードがないと初期設定ができない。

私は後で気付いて買いに行きました・・・


使用感

4KのYoutubeを再生してみたところ、4K(2160p)、HD(1440p)は再生が厳しかったが、それ以下なら再生できた。


GoPro: Tomorrowland in 4K - YouTube

USB端子が1つしかないのでUSBハブが必須。

キーボードとマウスならだけ電源アダプター付きのUSBハブでなくてもいけたが、これ以上何かつけようと思ったら電源アダプター付きのUSBハブにする必要がある。

旅行に持っていきやすいとは思うが、キーボードとマウスを持っていく必要があるので、それならノートPCでいいような気がする・・・

テレビの裏につけるだけでWindows PCが使えるので、ノートPCを買うまでもない人なら2万程度でPCが増えるのでいいと思う。

Minecraft買って動かせるか試してみたいところ。

モバイルバッテリーでも起動できるかもしれないのでこちらも試してみたい。

DockerでAndroidの環境を構築する

Androidでテストを同時並行に実行したいなーと思っていたので作ってみた。

github.com


Javaのインストール

github.com

こちらからコードを拝借。ただ、add-aptがデフォルトではUbuntuに入っていないのでatp-getでインストールする

# For add-apt-repositor in order to install Java
RUN apt-get install -y software-properties-common

# Install Java
RUN \
  echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
  add-apt-repository -y ppa:webupd8team/java && \
  apt-get update && \
  apt-get install -y oracle-java8-installer && \
  rm -rf /var/lib/apt/lists/* && \
  rm -rf /var/cache/oracle-jdk8-installer

# Define commonly used JAVA_HOME variable
ENV JAVA_HOME /usr/lib/jvm/java-8-oracle

Android SDKのインストール

Android SDKGoogleのページにあるので、ダウンロードしてくればよい。問題はtoolsなどのインストールで、インストールの最中度々承認を求められる。今回はexpcetコマンドを使って、特定の文が来たらそれに対してキーを送るようにしてスキップしている。

あとうまくいかなかった点としては、32bit互換性のためにライブラリをインストールすることと、toolsのアップデート中にtmpフォルダへのコピーが失敗してインストールが失敗するということがあった。

前者はapt-getでlib32stdc++6をインストールする。 後者は、toolsを一旦別フォルダに退避し、退避したtoolsのandroidコマンドを使ってtoolsのアップデートを行う。

ADD expect-android-update.sh .
RUN chmod +x expect-android-update.sh
RUN apt-get install -y wget
RUN apt-get update
RUN apt-get -y install expect
RUN apt-get -y install lib32stdc++6
RUN wget http://dl.google.com/android/android-sdk_r24.2-linux.tgz && \
    mv android-sdk_r24.2-linux.tgz /opt && \
    cd /opt && \
    tar zxvf android-sdk_r24.2-linux.tgz && \
    rm android-sdk_r24.2-linux.tgz && \
    cd android-sdk-linux && \
    cp -a tools copy-tools && \
    /expect-android-update.sh platform-tools && \
    ./platform-tools/adb kill-server && \
    rm -rf temp/ && \
    /expect-android-update.sh tools && \
    /expect-android-update.sh build-tools-22.0.1,android-18,android-19,android-21,android-22,sys-img-armeabi-v7a-android-22,sys-img-armeabi-v7a-android-21,sys-img-armeabi-v7a-android-19,sys-img-armeabi-v7a-android-18
         
ENV ANDROID_SDK_HOME /opt/android-sdk-linux
ENV ANDROID_HOME /opt/android-sdk-linux
ENV PATH $PATH:/opt/android-sdk-linux/platform-tools:/opt/android-sdk-linux/tools

adbで端末のモデル名を取得する

adb shell cat /system/build.prop | grep ro\.product\.model | awk -F"=" 'NR==1 {print $2}' | tr -d ' ' | awk -v RS='\r\n' '{print $1}'


詳細はこちらから

d.hatena.ne.jp


ほとんどの機種は上記記事のコマンドで問題ないのだが、Nexus5のような端末だとro.product.modelが「Nexus 5」のようにスペースが入っている。

そのため、tr -d ' ' を追加した。

Alfredからビルドする

最近、なるべくマウスから手を離したくないなーと思ってなんでもかんでもターミナルでコマンドなりシェルスクリプトでやろうとしている。

ビルドに関してもオプションを受け取れるようにして、シェルスクリプトで切り替えているのだけども、実行するには一回ターミナルを開いて実行して終わったら元の画面に戻って・・・ということになるので、なるべく開きたくない。

これをAlfredでなんとかならないかなと試行錯誤してできるようになったのでメモ。

環境

Alfredとは

AlfredはMac用のランチャーアプリ。バックグラウンドで常駐し、option+spaceでいつでもどこからでも起動できる。

www.alfredapp.com

AlfredのUI自体はただの入力欄で、起動するとフォアグラウンドに出てきて、アプリの頭文字を入力することで素早くアプリを起動できる。

f:id:phicdy:20150407235051p:plain

Alfredのいいところはいつでもどこからでも起動できるというところで、どんな作業をしていようとアプリを起動できる。

またアプリ起動だけでなく、Google検索やファイル検索といった検索機能もカスタマイズして利用できる。

今回はビルドを行うアプリケーションを作成して、それをAlfredから起動することで、いつでもどこからでもビルドができるようにした。

そのビルドを行うアプリケーションを簡単に作れるのがMacに標準で入っているAutomatorである。

Automatorの設定

Automatorでは開始の通知の表示とビルドスクリプトの実行、 そして終了の通知の表示を行うだけである。

まず、Automatorを開き通知を右の欄にドラッグする。

f:id:phicdy:20150418170039j:plain

タイトル等は適当に。

次にシェルスクリプトの実行をドラッグする。 ここでの注意点として、Automatorからシェルスクリプトを実行する際、bash_profileが読み込まれないので、明示的に読み込む必要がある。

f:id:phicdy:20150418170100j:plain

最後にもう一度通知を追加して保存する。

f:id:phicdy:20150418170125j:plain

保存先は、Alfredの検索対象(/Applicationsなど)となっているフォルダにする。

Alfredから起動できるようになる。

f:id:phicdy:20150418194536j:plain

通知は右上に出る。

f:id:phicdy:20150418194609j:plain

通知がすぐ消えるのを変えたい場合は、設定から通知を通知パネルに変更すれば、自分で消すまでは残り続ける

f:id:phicdy:20150418194623j:plain

おわりに

Alfredからビルドできるようになったけど、ビルド対象やビルドオプションが増えるたびにAutomatorで設定する必要があるのどうにかならないかな。。。

JenkinsのJUnitでNoClassDefFoundError

JUnitの結果のXMLファイルがなぜかNoClassDefFoundErrorで読めなかったが、解決したのでメモ。

環境

エラーと原因

エラーは以下の通り。

Process leaked file descriptors. See http://wiki.jenkins-ci.org/display/JENKINS/Spawning+processes+from+build for more information
Recording test results
ERROR: Publisher hudson.tasks.junit.JUnitResultArchiver aborted due to exception
java.lang.NoClassDefFoundError: hudson/tasks/junit/JUnitParser$ParseResultCallable
     at hudson.tasks.junit.JUnitParser.parseResult(JUnitParser.java:90)
     at hudson.tasks.junit.JUnitResultArchiver.parse(JUnitResultArchiver.java:120)
     at hudson.tasks.junit.JUnitResultArchiver.perform(JUnitResultArchiver.java:137)
     at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:74)
     at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
     at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:770)
     at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:734)
     at hudson.model.Build$BuildExecution.post2(Build.java:183)
     at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:683)
     at hudson.model.Run.execute(Run.java:1770)
     at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
     at hudson.model.ResourceController.execute(ResourceController.java:89)
     at hudson.model.Executor.run(Executor.java:240)

 

調べた結果以下のページで解決した。 

[#JENKINS-26060] Using Jenkins 1.583. Today updated plugins, junit publisher now crashes. - Jenkins JIRA

The problem is that JUnit 1.3 is actually incompatible with Jenkins before 1.587 except 1.580.1 LTS. Unfortunately this cannot be expressed through dependencies, and to make it available to LTS users, it'll also be made available to users on weeklies >1.580.


どうもJenkinsのバージョンが1.587より古く、JUnitプラグインのバージョンが1.3だと不具合が出てしまうらしい。 

私の環境ではJUnitプラグインのバージョンは1.5だったが、同様の問題が発生したので、1.3以降なら起きるのかもしれない(未検証)。


解決方法

Workarounds:
・Downgrade JUnit to 1.2
・Downgrade/cross-grade Jenkins to 1.580.1 LTS
・Upgrade Jenkins to 1.587 or higher
As this only affects older weekly releases between 1.580 and 1.586, it's not worth the effort to fix. The general expectation is that users keep their instance fairly close to the current release when using the weeklies.  


JUnitのバージョンを下げるか、Jenkinsのバージョンを1.580.1にするか1.587以上にすればいいとのことなので、Jenkinsのバージョンを最新版にして解決。

# 一応バックアップ
$sudo mv /usr/share/jenkins/jenkins.war /usr/share/jenkins/jenkins.war.1.581
# Jenkinsの設定画面からダウンロード
$sudo cp /home/hoge/Download/jenkins.war /usr/share/jenkins/
# 再起動
$sudo /etc/init.d/jenkins restart


というかJenkinsの管理画面でアップデートしろとずっと出ていたのを無視していたのがよくなかったな。。。  

mitmproxyで端末の通信内容を見る

mitmproxyとは

mitmproxyはコンソール型の通信監視ツールである。

mitmproxyは、プロキシを通じて通信サーバと端末の間に入り、その通信内容を表示する。

mitmproxy - home

f:id:phicdy:20150530154256p:plain


例えばモバイルのアプリケーションを開発している際に、端末から実際に行っている通信内容を確認したいときがある。

ログなどに出力すれば見ることはできるが、細かい情報を見ようとするならば実際に通信内容を見るしかない。

mitmproxyを使えば、リアルタイムに通信内容を確認できる。

今回はVirtualBox上のUbuntuにインストールして、Androidの通信を見てみた。

環境

 

インストール

pipを使ってインストールできる。

RUN apt-get -y update

# Install pip
sudo apt-get -y install python-dev
sudo apt-get -y install libxml2-dev
sudo apt-get -y install libxslt1-dev
sudo apt-get -y install zlib1g-dev
sudo apt-get -y install libffi-dev
sudo apt-get -y install libssl-dev
sudo apt-get -y install python-pip

# Install mitmproxy
sudo pip install mitmproxy

 

準備

端末

Androidの場合、Wi-Fi設定にてプロキシを設定できるのは3.2 以上のみである。

まず端末とmitmproxyの入ったUbuntuを同ネットワーク上に繋ぐ。

次に端末のWi-Fi設定から接続しているSSIDを長押しする。

そして「ネットワークを変更」から「詳細オプションを表示」にチェックを入れてプロキシを設定する。

プロキシのホストはUbuntuIPアドレス、ポートは自由に設定できる。

 

証明書のインストール

mitmproxyを使うと、mitmproxyを通じて通信を行うことになるので、端末に証明書をインストールする必要がある。

まずmitmproxyを起動する。デフォルトのポートは8080なので、プロキシのポートを8080以外に設定した場合は、-pオプションで変更する。

mitmproxy -p 8001

証明書をインストールする方法は2つある。

  • http://mitm.it にアクセスする。
  • adb pushで証明書を端末に直接入れてインストールする。

http://mitm.it にアクセスする際はmitmproxyを起動しておかないと接続できない。

証明書はmitmproxyを1度実行後、~/.mitmproxy/mitmproxy-ca-cert.cer に置かれるのでこれをadb pushで端末に入れる。

証明書を端末に入れた後は、設定 -> セキュリティ -> ストレージからインストール でインストールできる。

 

使い方

mitmproxyはコンソールで操作するツールになっている。

左にカーソルがあり、見たい通信のところでEnterキーを押すことで詳しい中身が見れる。

下の画像はAmazonにアクセスしたときのリクエスト内容である。

f:id:phicdy:20150530154314p:plain


tabキーを押すことでサーバからのレスポンスを確認できる。

f:id:phicdy:20150530154323p:plain

 

その他にも通信内容を変更して送り返したり、通信のフィルタリングを行ったりといろいろな機能がある。

下記記事に詳しい使い方が書いてある。

モバイルアプリ開発者のための mitmproxy 入門 - Qiita