Androidで、C++とJavaの実行速度を少しだけ比較

AndroidC++コードの実行速度とJavaコードの実行速度を少しだけ比較してみました。
この検証に使ったコードは以下に公開しています。
github.com

環境

開発環境 Android Studio2.3
NDKバージョン 14.1.38168.74
実行デバイス(Androidバージョン) SH-02H(6.0.1)

実行したコード

実行したコードは、for文中にif文を挟むコードです。
計測されている時間はミリ秒です。

エミュレータではJavaの方がC++よりも実行速度が速くなったりと実行速度がおかしかったので実機で計測しました。

C++の導入やそのコードの使用方法については省略します。

C++
extern "C"
JNIEXPORT jint JNICALL Java_com_wrongrong_cpptest_MainActivity_cppForTest(JNIEnv* env, jobject obj){
    int i,j;
    j = 0;

    for(i = 0;i < 200000000;i++){
        if(i&1 == 1)j++;
    }
    return j;
}
Java
public class JavaForTest {
    public int javaForTest(){
        int i,j;
        j = 0;

        for(i = 0; i < 200000000; i++){
            if((i&1) == 1)j++;
        }
        return j;
    }
}
検証用コード
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TextView tv = (TextView) findViewById(R.id.sample_text);
    String ln = System.lineSeparator();
    JavaForTest jft = new JavaForTest();
    int i,j=0;
    long jftS,jftE,cppS,cppE;

    for(i = 0;i < 200000000;i++)j += i;

    jftS = System.currentTimeMillis();
    i = jft.javaForTest();
    jftE = System.currentTimeMillis();

    cppS = System.currentTimeMillis();
    j = cppForTest();
    cppE = System.currentTimeMillis();

    //出力の整形
    StringBuilder sb = new StringBuilder(String.valueOf(i - j)); sb.append(ln);
    sb.append("Java:"); sb.append(String.valueOf(jftE - jftS)); sb.append(ln);
    sb.append("C++:"); sb.append(String.valueOf(cppE - cppS)); sb.append(ln);
    sb.append("Java/C++:"); sb.append(String.valueOf((double)(jftE - jftS) / (double)(cppE - cppS)));

    tv.setText(sb.toString());
}
脚注

実行速度安定化のための空ループを挟んでみたが、挟まない方がC++Java両方に関して、実行速度は高速でした。
一方、ループを挟まない場合、先に実行した方のコードの実行速度が速くなる傾向がありました。
レジスタの関係でしょうか?

実行結果

JavaC++に対して大体13倍ほど実行速度が遅いという結果になりました。
プログラム実行速度の計測に関して余り知識が無いので何とも言えませんが、やはりリアルタイム処理のような高速性の求められる処理では、C++を用いて処理を行った方が良いのでしょう。

Androidアプリで、タイトルバーを消す方法

色々なサイトを見たが動かない場合によくぶち当たったので、自分の環境で動いた例のサイトを備忘用に保存。

やったこと

values/styles.xml内で、parent="Theme.AppCompat.Light.DarkActionBar"となっている部分をparent="Theme.AppCompat.Light.NoActionBar"と書き換える。

参考サイト

丸々以下の内容。
ja.stackoverflow.com

「生存率計算機」――懲りずにまたアプリを作ってみた

以前作成したScript Calculatorに続き、またアプリを作成してみました。

play.google.com

作成したアプリのタイトルは生存率計算機、厚生労働省のデータを基に生存率を計算します。

play.google.com

github.com

作ったきっかけ

カメラアプリを作ろうと四苦八苦していたのですが、残念ながらリアルで時間が取れない状況が続きそうで、完成まで持っていくには少し厳しい状況と感じていました。

一方この土日は空いていて、開発したいという意欲はあったので、サクッと作ることができそうな題材でアプリを作ってみました。要するに暇つぶしです。

感想

題材が題材だったので、色々なことは感じましたが、取りあえずこのアプリを作ってみた感想としては、暇つぶしでアプリをリリースする日が来るなんて想像していなかった、です。

まあ対して難しいことはしておらず、レベルはお察しな感じですが、ソースコードそのものはきっかり24時間以内で書き上げられたので、そこは成長かなあと思うことにします(笑)。

Android6.0(APIレベル23以上)で、アプリに権限を与える

アプリに権限を与えようとした時に詰まったので、備忘用に。

やること

APIレベル23から、Androidでアプリを動かす際に必要なパーミッションが、アプリインストール時ではなく、その機能を使う時に取得するようになったため、AndroidManifestへの記述だけでなく、そのためのコードが必要になった(今更)。
この権限を与える処理が非常にめんどくさかったので備忘を兼ねて投稿。
ただ、まだ理解が追いついておらず、このやり方で効率が良いのかは確認できていない。
余分なものが入っていないコードはまとめに記載。

やったこと

前提として、AndroidManifestにパーミッション関連を記述しておく。

onCreate

今回はアプリ起動時に権限を付与することを想定して、onCreateメソッドから。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //カメラ権限の確認
    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {//権限がまだ無い場合
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAMERA)) {//明示的に権限が拒否されていた時
            //拒否されていた時の処理、なんかしらのメッセージを出すと良いと思われる、今は何も考えずにパーミッションを聞いておく
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);
        } else {//まだ聞いてなかったとき
            //与えても良いか聞く、onRequestPermissionsResultが答えを受ける
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);
        }
    }else {//権限がある場合
        initCameraView();//そのままカメラをセッティング
    }
}

※initCameraViewメソッドは自作したもので、この記事の内容には関係無し

ここではカメラ権限のチェックと、権限が無かった場合の付与を呼び出している。
大半はコード中のコメントに書いた通りで、権限のチェックには

  • 現在権限が与えられているか
    • 権限が無かった場合どうするか
      • 権限が無いのは、ユーザーに拒絶されているからか
        • 拒絶されているならどうするか
        • まだ聞いていないならどうするか
    • 権限が有った場合どうするか

といったような手順が必要。

権限を与えるために呼び出すメソッドは以下。

ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);

Manifest.permission.CAMERAとなっている部分は取得する権限を意味する。
末尾で与えている定数の1は、後述するonRequestPermissionsResultメソッドで利用する。

onRequestPermissionsResult

このメソッドは、権限付与のために呼び出したrequestPermissionsメソッドに対する返答を受け取るメソッド。
これを書かないと権限の有無を確認しないまま処理が開始されてしまい、権限が無いまま機能を利用しようとしてアプリがSecurityExceptionで落ちたりする。

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1: { //ActivityCompat#requestPermissions()の第2引数で指定した値
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//許可された場合
                setContentView(R.layout.activity_main);
                initCameraView();
            }else{//拒否された場合の処理
                //とりあえず終了しておく
                MainActivity.this.finish();
            }
            break;
        }
    }
}

ここでrequestCodeをswitchに渡しているが、この数字が先ほどのrequestPermissionsメソッドに与えた定数。
先ほどは1を渡したので、1に関してはカメラの権限付与がどうなったか確認を行っている。
幾つかの権限を与える最には、enumなりを使ってrequestCordを管理した方が良いかも?
とりあえずここまで実装しておけばアプリに権限を与えることができた。

蛇足

onRequestPermissionsResultにて、initCameraの前にsetContentViewを行っているが、これをしないとカメラを起動する前にアプリが落ちた。
原因を理解する前に多分ビューの切り替えがおかしいんだろと予想して切り替えを記述してみたが、ドンピシャだったので何故落ちるか理解できていない。

まとめ

今回載せたコードから、余計なものを取り除いてまとめたものが以下。

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1: { //requestPermissions()の第2引数で指定した値
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//許可された場合
            }else{//拒否された場合の処理
            }
            break;
        }
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //カメラ権限の確認
    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {//権限がまだ無い場合
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAMERA)) {//明示的に権限が拒否されていた時
            //拒否されていた時の処理
        } else {//まだ聞いてなかったとき
            //与えても良いか聞く、onRequestPermissionsResultが答えを受ける
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);
        }
    }else {//権限がある場合
    }
}

AndroidアプリでWebViewで文字化けした時の対策

 ローカルのHTMLを読み込んだら化けたので対策。

やり方

 HTMLの記述に<meta charset="UTF-8">を追加し、文字コードを指定したら解決した。

 化けた時は文字コードを確認したうえで指定すればOKかな。

Androidアプリで、簡単にファイルにデータを保持する

 開発の備忘のため記事を残す。

やりたいこと

 EditTextなど、アプリ内でユーザーが行った変更をファイルに保持しておき、アプリを起動した際に、データを読み込む。

 設定などを保持することにも応用できるかも?

 プリファレンスを使うなどの方法もあるそうだが、Javaを扱ったことがあるなら単純さの分だけFileを利用するこの記事のやり方が向いているかも。

やり方

 やり方は以下のようにしてFileを初期化すること。ここではhogeというファイル名のファイルを作っている。

File file = new File(getFilesDir(),"hoge");

 ここからBufferReaderなりPrintWriterなりにfileを渡してやれば読み書きできる。

補足

 getFilesDir()は素では呼べないのかもしれないが、自分のソースコード上では特に何もimportせずに動いていた。(備忘と言いつつ書いている時には何で動くのか分からなくなっていた……)

 getCacheDir()でも同じようなことができるようだが、こちらはストレージ容量がキツくなった時に消される可能性があるらしい(未検証)。

参考サイト

 今回の記事は以下のサイトから必要だった部分のみ抽出して作成した。

 Saving Files | Android Developers