質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.41%

  • Java

    14785questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6850questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Android Studio

    4010questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

  • Kotlin

    471questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

android studioでkotlinでのCSV出力について

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 69

tomo01

score 3

前提・実現したいこと

android studio で現在、こちらのサイト
https://qiita.com/seaka829/items/613d27035dab7b3a9121 
からibeaconからmajor、minor、RSSIを取得するアプリを作ったのですが、
取得したデータを保存する方法が分からなくて困っています。

作りたいと思っているものが、
時間ごと(1秒ごととか)に、取得したデータと日付を
自動でフォルダに保存するアプリです。

発生している問題・エラーメッセージ

CSVファイルは作られたのですが、
最初に検知したデータしか入りません。
for文の位置が悪いのでしょうか?

該当のソースコード

package com.websarva.wings.android.beacon_kotlin

import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.os.*
import android.support.v7.app.AppCompatActivity
import android.support.annotation.RequiresApi
import android.support.v4.app.INotificationSideChannel
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*

import org.altbeacon.beacon.*
import java.io.BufferedWriter
import java.io.FileWriter
import java.io.IOException
import java.io.PrintWriter

import java.util.*





class MainActivity : AppCompatActivity(), BeaconConsumer {


    // BeaconManager型変数の宣言
    private var beaconManager: BeaconManager? = null

    // uuidの指定
    private val uuidString: String = "48534442-4C45-4144-80C0-180000000000"
    private val uuid = Identifier.parse(uuidString)

    // ビーコンのフォーマット設定
    private val IBEACON_FORMAT: String = "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"

    private val handler: Handler = Handler()


    /**************************************************
     * AppCompatActivity内のメソッドをoverride
     **************************************************/
    // onCreate
    @RequiresApi(Build.VERSION_CODES.ECLAIR)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // デバイスのBLE対応チェック
        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {

            // 未対応の場合、Toast表示
            showToast("このデバイスはBLE未対応です", Toast.LENGTH_LONG)
        }
        // API 23以上かのチェック
        if (Build.VERSION.SDK_INT >= 23) {

            // パーミッションの要求
            checkPermission()
        }

        // ビーコンマネージャのインスタンスを生成
        beaconManager = BeaconManager.getInstanceForApplication(this)

        // BeaconManagerの設定
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(IBEACON_FORMAT))
    }

    // onResume
    override fun onResume() {
        super.onResume()

        // ビーコンサービスの開始
        beaconManager!!.bind(this)
    }

    // onPause
    override fun onPause() {
        super.onPause()

        // ビーコンサービスの停止
        beaconManager!!.unbind(this)
    }


    /**************************************************
     * BeaconConsumer内のメソッドをoverride
     **************************************************/
    // onBeaconServiceConnect
    override fun onBeaconServiceConnect() {

        try {
            // ビーコン情報の監視を開始、第3,4引数はmajor・minor値を指定する時に使用
            beaconManager!!.startMonitoringBeaconsInRegion(Region("48534442-4C45-4144-80C0-180000000000", uuid, null, null))
        } catch (e: RemoteException) {
            e.printStackTrace()
        }

        // モニタリングの通知受取り処理
        beaconManager!!.addMonitorNotifier(object : MonitorNotifier {

            // 領域内に侵入した時に呼ばれる
            override fun didEnterRegion(region: Region) {

                // レンジングの開始
                beaconManager!!.startRangingBeaconsInRegion(region)
            }

            // 領域外に退出した時に呼ばれる
            override fun didExitRegion(region: Region) {

                // レンジングの停止
                beaconManager!!.stopRangingBeaconsInRegion(region)
            }

            // 領域への侵入/退出のステータスが変化した時に呼ばれる
            override fun didDetermineStateForRegion(i: Int, region: Region) {
                //
            }
        })

        // レンジングの通知受け取り処理
        beaconManager!!.addRangeNotifier(object : RangeNotifier {

            // 範囲内のビーコン情報を受け取る
            override fun didRangeBeaconsInRegion(beacons: Collection<Beacon>, region: Region) {

                var maxMajor: Int?
                var maxMinor: Int?
                var maxrssi: Int?

                // 範囲内の複数のビーコン情報を保持させる変数
                var getMajorList: ArrayList<Int> = ArrayList()
                var getMinorList: ArrayList<Int> = ArrayList()
                var getRssiList: ArrayList<Int> = ArrayList()

                // 範囲内にビーコンがある時の処理
                if (beacons.size > 0) {

                    // 範囲内のビーコンの数だけ繰り返す
                    for (beacon in beacons) {
                        // 複数のビーコン情報をArrayListに分割
                        getMajorList.add(beacon.id2.toInt())
                        getMinorList.add(beacon.id3.toInt())
                        getRssiList.add(beacon.rssi.toInt())


                    }

                    // RSSIが最も大きいインデックスを取得
                    var indexRssi: Int = getRssiList.indexOf(getRssiList.max())

                    // 取得したインデックスのmajor値・minor値を取得
                    maxMajor = getMajorList[indexRssi]
                    maxMinor = getMinorList[indexRssi]
                    maxrssi = getRssiList[indexRssi]

                    //パスの指定
                    val fw = FileWriter(Environment.getExternalStorageDirectory().getPath() + "/test.csv")
                    //バッファリングによって文字列を効率的に書き込む
                    val pw = PrintWriter(BufferedWriter(fw))

                    //内容を指定する
                    pw.print(",")
                    pw.print("MAJOR")
                    pw.print(",")
                    pw.print("MINOR")
                    pw.print(",")
                    pw.print("RSSI")
                    pw.println()

                    for (i in 1..4) {
                        Log.d("Test_Major", maxMajor.toString())
                        Log.d("Test_Minor", maxMinor.toString())
                        Log.d("test_rssi", maxrssi.toString())

                        print(i)
                        pw.print(",")
                        pw.print(maxMajor.toString())
                        pw.print(",")
                        pw.print(maxMinor.toString())
                        pw.print(",")
                        pw.print(maxrssi.toString())
                        pw.println()
                    }

                    //ファイルに書き出す
                    pw.close()






                    handler.post {
                        viewUpdate(maxrssi, maxMajor, maxMinor)
                    }
                }
            }
        })
    }


    /**************************************************
     * メソッド
     **************************************************/
    // トースト表示のメソッド
    fun showToast(text: String, length: Int) {

        // トーストの生成と表示
        var toast: Toast = Toast.makeText(this, text, length)
        toast.show()
    }

    @RequiresApi(Build.VERSION_CODES.M)
    fun checkPermission() {

        // パーミッション未許可の時
        if (checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            // パーミッションの許可ダイアログの表示
            requestPermissions(arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION), 0)
        }

    }


    //一番RRSIが強いmajorとminorの表示と保存
    fun viewUpdate(rssi: Int?, major: Int?, minor: Int?) {

        // Viewの取得
        val rssiTextView: TextView = findViewById(R.id.rssi) as TextView
        val majorTextView: TextView = findViewById(R.id.major) as TextView
        val minorTextView: TextView = findViewById(R.id.minor) as TextView

        majorTextView.text = "major:" + major
        minorTextView.text = "minor:" + minor
        rssiTextView.text = "RSSI:" + rssi + "dBm"




    }

}

試したこと

for文の位置を変えたりしましたがうまくいきません。
現在のプログラムですと、同じ値が4つ保存される状況です。

補足情報(FW/ツールのバージョンなど)

android studio 3.2.1

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tomo01

    2019/01/14 11:30

    はい、uses-permissionタグのことでした。
    MainActivityにも必要なんですね!調べて追記してみます。

    キャンセル

  • keicha_hrs

    2019/01/14 11:31

    何ならそこも回答に追記します。

    キャンセル

  • tomo01

    2019/01/14 11:40

    ありがとうございます!

    キャンセル

回答 1

0

追記・修正依頼に書いたコメントは別として、「同じ値が4つ保存される」ということについては、for文の中でmaxMajor、maxMinor、maxrssiが一度も変化していないからでしょう。これでは「同じ値が4つ」になるのは必然です。

                    for (i in 1..4) {
                        maxMajor = 書き込みたいInt値
                        maxMinor = 書き込みたいInt値 
                        maxrssi = 書き込みたいInt値

                        Log.d("Test_Major", maxMajor.toString())
                        Log.d("Test_Minor", maxMinor.toString())
                        Log.d("test_rssi", maxrssi.toString())

                        print(i)
                        pw.print(",")
                        pw.print(maxMajor.toString())
                        pw.print(",")
                        pw.print(maxMinor.toString())
                        pw.print(",")
                        pw.print(maxrssi.toString())
                        pw.println()
                    }


のようにして、ループを回る度に新たに書き込みたい値を得る記述が必要ではありませんか。


(01/14 12:00追記)
現状のコードにあるACCESS_COARSE_LOCATION権限の確認・取得に加えて、端末の内部ストレージへの書き込み権限を確認・取得するには、

        // パーミッション未許可の時
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
            checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            // パーミッションの許可ダイアログの表示
            requestPermissions(
                arrayOf(
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    android.Manifest.permission.ACCESS_COARSE_LOCATION
                ), 0
            )
        }


のように記述してください。これで、今まで取得していた位置情報と合わせて両方の権限の確認と取得ができます。

それから余談なのですが、書き込み記述について。恐らく書き込みたい値はgetMajorList[]、getMinorList[]、getRssiList[]から得られる値なのだろうと思います(違ったらすみません)。それならば

                    for (i in 0..3) {
                        val major = getMajorList[i].toString()
                        val minor = getMinorList[i].toString()
                        val rssi = getRssiList[i].toString()

                        Log.d("Test_Major", major)
                        Log.d("Test_Minor", minor)
                        Log.d("test_rssi", rssi)

                        pw.println("${i + 1},$major,$minor,$rssi")
                    }


(01/14 21:40 コード訂正)

のように簡潔に書けるはずです。Kotlinには、文字列の中に"${式}"と記述する(変数名のみならば{}は不要)と、式がInt型などであったとしても適切な文字列に変換される機能があります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/14 16:00

    ありがとうございます。
    はい、書き込みたい値はその3つです。

    実際にmainactivityのpermission の記述と、for文の書き換えをしましたが、まだ、書き込みがうまくいっていないようです。一番初めに取得したデータのみ記述して、終わってしまっています。

    ```
    // レンジングの通知受け取り処理
    beaconManager!!.addRangeNotifier(object : RangeNotifier {

    // 範囲内のビーコン情報を受け取る
    override fun didRangeBeaconsInRegion(beacons: Collection<Beacon>, region: Region) {
    //パスの指定


    var maxMajor: Int?
    var maxMinor: Int?
    var maxrssi: Int?

    // 範囲内の複数のビーコン情報を保持させる変数
    var getMajorList: ArrayList<Int> = ArrayList()
    var getMinorList: ArrayList<Int> = ArrayList()
    var getRssiList: ArrayList<Int> = ArrayList()

    // 範囲内にビーコンがある時の処理
    if (beacons.size > 0) {

    // 範囲内のビーコンの数だけ繰り返す
    for (beacon in beacons) {
    // 複数のビーコン情報をArrayListに分割
    getMajorList.add(beacon.id2.toInt())
    getMinorList.add(beacon.id3.toInt())
    getRssiList.add(beacon.rssi.toInt())


    }

    // RSSIが最も大きいインデックスを取得
    var indexRssi: Int = getRssiList.indexOf(getRssiList.max())

    // 取得したインデックスのmajor値・minor値を取得
    maxMajor = getMajorList[indexRssi]
    maxMinor = getMinorList[indexRssi]
    maxrssi = getRssiList[indexRssi]

    val fw = FileWriter(Environment.getExternalStorageDirectory().getPath() + "/test.csv")
    //バッファリングによって文字列を効率的に書き込む
    val pw = PrintWriter(BufferedWriter(fw))

    //内容を指定する
    pw.print(",")
    pw.print("MAJOR")
    pw.print(",")
    pw.print("MINOR")
    pw.print(",")
    pw.print("RSSI")
    pw.println()

    for (i in 0..indexRssi) {
    val maxMajor = getMajorList[i].toString()
    val maxMinor = getMinorList[i].toString()
    val maxrssi = getRssiList[i].toString()

    Log.d("Test_Major", maxMajor)
    Log.d("Test_Minor", maxMinor)
    Log.d("test_rssi", maxrssi)

    pw.println("${i + 1},$maxMajor,$maxMinor,$maxrssi")

    }

    pw.close()


    handler.post {
    viewUpdate(maxrssi, maxMajor, maxMinor)
    }



    }
    }
    })

    ```

    キャンセル

  • 2019/01/14 19:22 編集

    > 一番初めに取得したデータのみ記述して、終わってしまっています。

    私はindexRssiで得られた回数分回したいのかと思ったのですが、勘違いだったでしょうか?変数の中にmaxと付いているのだから、配列中で一番大きな値を得たかったのかな?配列には必ず4つのデータが入っていて、書き込みのためのループも4回固定で回したかったということでしょうか?

    キャンセル

  • 2019/01/14 20:41

    説明不足ですみません。
    仰る通り、indexRssiで得られただけ記録がしたいです。
    4つはサンプルとして正しく動いてるか調べるためだけの数でした。

    キャンセル

  • 2019/01/14 21:45

    getMajorList、getMinorList、getRssiListの各リストに入っているデータをそれぞれ頭から4つ書き込む、という前提で例示コードを書き直してみました。こういうことでいいのでしょうかね?ただ、これは各リストに4つ以上データが存在している必要があります。配列範囲外をアクセスをすると、例外が発生してアプリが落ちます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.41%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Java

    14785questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6850questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Android Studio

    4010questions

    Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

  • Kotlin

    471questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。