Android開発爆笑記

レセプターのソフト&ハード開発備忘録

SwiftでSQLiteを使う

import SQLite3

 

class ViewController〜

    var db: OpaquePointer?

    let dbName : String = "your_database_name.db"

    let tableName = "main_table_name"

    override func viewDidLoad() {

        // データベースファイルのパスを取得

        let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)

            .appendingPathComponent(dbName)

 

        // データベースを開く

        if sqlite3_open(fileURL.path, &db) != SQLITE_OK {

            print("データベースを開けませんでした。")

            return

        }

 

        // テーブルの作成

        if !tableExists(tableName: tableName) {

            let createTableQuery = "CREATE TABLE \(tableName) (_id INTEGER PRIMARY KEY AUTOINCREMENT, 〜 memo TEXT);"

            if sqlite3_exec(db, createTableQuery, nil, nil, nil) != SQLITE_OK {

                let errmsg = String(cString: sqlite3_errmsg(db)!)

                print("テーブルを作成できませんでした。エラー: \(errmsg)")

                return

            }

            print("テーブルを作成")

        } else {

            print("テーブルは作成済み")

        }

        〜

} ←viewDidLoad()の対応カッコ

 

    // テーブル有無チェック

    func tableExists(tableName: String) -> Bool {

        let query = "SELECT name FROM sqlite_master WHERE type='table' AND name='\(tableName)';"

        var statement: OpaquePointer?

        sqlite3_prepare_v2(db, query, -1, &statement, nil)

        let result = sqlite3_step(statement)

        sqlite3_finalize(statement)

        return result == SQLITE_ROW

    }

    

    // データ挿入

    func insertData() {

        let insertQuery = "INSERT INTO \(tableName) (〜,memo) VALUES (〜, ?);"

 

        var statement: OpaquePointer?

        if sqlite3_prepare_v2(db, insertQuery, -1, &statement, nil) == SQLITE_OK {

            let b〜

            let memo = "This is a memo"

 

            sqlite3_bind_text(statement, 1, (b〜 as NSString).utf8String, -1, nil)

            〜

            sqlite3_bind_text(statement, 8, (memo as NSString).utf8String, -1, nil)

 

            if sqlite3_step(statement) == SQLITE_DONE {

                print("データの挿入に成功しました。")

            } else {

                let errmsg = String(cString: sqlite3_errmsg(db)!)

                print("データの挿入に失敗しました。エラー: \(errmsg)")

            }

        } else {

            let errmsg = String(cString: sqlite3_errmsg(db)!)

            print("ステートメントの作成に失敗しました。エラー: \(errmsg)")

        }

 

        sqlite3_finalize(statement)

    }

    

    // 全件表示

    func displayData() {

        let selectQuery = "SELECT * FROM \(tableName);"

        var statement: OpaquePointer?

 

        if sqlite3_prepare_v2(db, selectQuery, -1, &statement, nil) == SQLITE_OK {

            while sqlite3_step(statement) == SQLITE_ROW {

                let id = sqlite3_column_int(statement, 0)

                let b〜

                let memo = String(cString: sqlite3_column_text(statement, 8))

 

                print("ID: \(id), B〜, Memo: \(memo)")

            }

        } else {

            let errmsg = String(cString: sqlite3_errmsg(db)!)

            print("データの取得に失敗しました。エラー: \(errmsg)")

        }

 

        sqlite3_finalize(statement)

    }

    

    // 検索

    func searchData() {

        let searchQuery = "SELECT * FROM \(tableName) WHERE key = ?;"

        var statement: OpaquePointer?

 

        if sqlite3_prepare_v2(db, searchQuery, -1, &statement, nil) == SQLITE_OK {

            let searchKey = "文字列"

 

            sqlite3_bind_text(statement, 1, (searchKey as NSString).utf8String, -1, nil)

 

            while sqlite3_step(statement) == SQLITE_ROW {

                let id = sqlite3_column_int(statement, 0)

                let b〜

                〜

                let memo = String(cString: sqlite3_column_text(statement, 8))

 

                print("ID: \(id), B〜, Memo: \(memo)")

            }

        } else {

            let errmsg = String(cString: sqlite3_errmsg(db)!)

            print("データの検索に失敗しました。エラー: \(errmsg)")

        }

 

        sqlite3_finalize(statement)

    }

    

    // 更新

    func updateData() {

        let updateQuery = "UPDATE \(tableName) SET name = ? WHERE key = ?;"

        var statement: OpaquePointer?

 

        if sqlite3_prepare_v2(db, updateQuery, -1, &statement, nil) == SQLITE_OK {

            let newName = "New Brand Name"

            let targetKey = "400000004"

 

            sqlite3_bind_text(statement, 1, (newName as NSString).utf8String, -1, nil)

            sqlite3_bind_text(statement, 2, (targetKey as NSString).utf8String, -1, nil)

 

            if sqlite3_step(statement) == SQLITE_DONE {

                print("データの更新に成功しました。")

            } else {

                let errmsg = String(cString: sqlite3_errmsg(db)!)

                print("データの更新に失敗しました。エラー: \(errmsg)")

            }

        } else {

            let errmsg = String(cString: sqlite3_errmsg(db)!)

            print("ステートメントの作成に失敗しました。エラー: \(errmsg)")

        }

 

        sqlite3_finalize(statement)

    }

    

    // 削除

    func deleteData() {

        let deleteQuery = "DELETE FROM \(tableName) WHERE key = ?;"

        var statement: OpaquePointer?

 

        if sqlite3_prepare_v2(db, deleteQuery, -1, &statement, nil) == SQLITE_OK {

            let targetKey = "文字列"

 

            sqlite3_bind_text(statement, 1, (targetKey as NSString).utf8String, -1, nil)

 

            if sqlite3_step(statement) == SQLITE_DONE {

                print("データの削除に成功しました。")

            } else {

                let errmsg = String(cString: sqlite3_errmsg(db)!)

                print("データの削除に失敗しました。エラー: \(errmsg)")

            }

        } else {

            let errmsg = String(cString: sqlite3_errmsg(db)!)

            print("ステートメントの作成に失敗しました。エラー: \(errmsg)")

        }

 

        sqlite3_finalize(statement)

    }

firebase realtimedatabase の children() を使った配下key名取得

まずは普通にデータベースを読む

FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myRef = database.getReference(str);

mListener = myRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {


long
cnt = snapshot.getChildrenCount(); // 直下のChild数を見る
// 直下のチャイルドの各Key名を取得
if ( 0 < cnt ) {
    for (DataSnapshot postSnapshot: snapshot.getChildren()) {
    Log.d(TAG,"child="+ postSnapshot.getKey());
     try {
        Log.d(TAG, "data=" + postSnapshot.getValue().toString());
    } catch (Exception e) {
    }
}

}

そろそろKotolin

始めてKotolinでプロジェクト作成した。

layout.xml は変わらないようだが MainActivity .ktがかなり違う

class MainActivity : AppCompatActivity() {
val str : String? = "aaa"
private lateinit var txtitel : TextView // レイアウト変数指定
private lateinit var btsubmit : Button // ボタン
private lateinit var strarry : Array<String> // 配列

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
txtitel = findViewById<TextView>(R.id.txTitle) // レイアウト変数初期化
btsubmit = findViewById<Button>(R.id.btBtn1)
strarry = Array<String>(20,{""}) // 配列初期化
cngTxt(txtitel)
// ボタン処理
btsubmit.setOnClickListener {
txtitel.setText("bbb")
}
}

private fun cngTxt(txt:TextView) {
txt.setText(str)
// 配列情報
Log.d("kyo",strarry.size.toString())
for(i in 0..strarry.size-1) {
Log.d("kyo",i.toString()+">"+strarry[i])
    }
  }
}

Arrayを組み込む

class MainActivity : AppCompatActivity() {
val str : String? = "aaa" // nullも格納
// private TexiView txtitle;
private lateinit var txtitel : TextView // レイアウト変数指定
private lateinit var btsubmit : Button // ボタン
private lateinit var strarry : Array<String> // 配列

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
txtitel = findViewById<TextView>(R.id.txTitle) // レイアウト変数初期化
btsubmit = findViewById<Button>(R.id.btBtn1)
strarry = Array<String>(20,{""}) // 配列初期化
cngTxt(txtitel)
// ボタン処理
btsubmit.setOnClickListener {
txtitel.setText("bbb")
}
// string-arrayからListArrayで取得
val user_info = resources.getStringArray(R.array.USER_INFO)
for(i in 0..user_info.size-1) {
val inf = user_info[i].split(",")
Log.d("kyo",inf.toString())
for( j in 0..inf.size-1) {
Log.d("kyo",inf[j])
}
}
val lvlist = findViewById<ListView>(R.id.lvList) // ListViewで表示
val arrAdapter = ArrayAdapter(this,android.R.layout.simple_list_item_1,user_info)
lvlist.adapter = arrAdapter
}

private fun cngTxt(txt:TextView) {
txt.setText(str)
// 配列情報
Log.d("kyo",strarry.size.toString())
for(i in 0..strarry.size-1) {
Log.d("kyo",i.toString()+">"+strarry[i])
}
}

}

f:id:receptorinc:20220326090325p:plain

実行後の画面

 

Android端末OS4.4から使えたGPSコード(java用)

◎AndroidManifest.xml に追加

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

とフォアグラウンド指定

<application~

    ~</activity>

        <!-- Foreground services in Q+ require type. -->
        <service
            android:name=".MainActivity"
            android:enabled="true"
            android:exported="true"
            android:foregroundServiceType="location" />

 

◎モジュールの build.gradle に追加

    implementation 'com.google.android.gms:play-services-location:17.0.0'

その後 SYNCを実行

 

◎MainActivity.java は要求に応じてimport「Alt+Enter」を実行。以前と違うのは「implements LocationListener」関連が無い事。

public class MainActivity extends AppCompatActivity {
    // GPS用の変数
    private FusedLocationProviderClient fusedLocationClient;

    //
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // GPS用の変数
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        // 1回目のrequestLocationUpdates呼出
        startLocationRequest();
    }

    // 2回以上呼び出されるので関数にする
    private void startLocationRequest() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // 位置情報パーミッション呼出→戻りに行く
            String [ ] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
            ActivityCompat.requestPermissions(this,permissions,1000);
            return;
        }
        // 位置情報の取得方法を設定
        LocationRequest locationRequest = LocationRequest.create();
        locationRequest.setInterval(15000);        // 位置情報更新間隔の希望(msec) 15秒
        locationRequest.setFastestInterval(5000); // 位置情報更新間隔の最速値(msec) 5秒
        locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); // この位置情報要求の優先度
        fusedLocationClient.requestLocationUpdates(locationRequest,  new MyLocationCallback(), null);
    }

    // 位置情報受取コールバッククラス
    private class MyLocationCallback extends LocationCallback {
        @Override
        public void onLocationResult(LocationResult locationResult) {
            if (locationResult == null) {
                return;
            }
            // 現在値を取得
            Location location = locationResult.getLastLocation();
            Date ima = new Date(location.getTime());
            String buf = String.format(Locale.US,"%tH%tM%tS",ima,ima,ima)+">"+String.valueOf(location.getLatitude())+","+String.valueOf(location.getLongitude());
            Log.d("kyo",buf);
            dispmesse(buf);
        };
    }

    // パーミッション呼出からの戻り
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions, @NonNull int grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 1000:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // パーミッション後の必要な処理
                    Log.d("GPS", "set");
                    // 2回目以降のrequestLocationUpdates呼出
                    startLocationRequest();
                } else {
                    // パーミッションが得られなかった時
                    // 処理を中断する・エラーメッセージを出す・アプリケーションを終了する等
                    Log.d("GPS", "no");
                    finish();
                }
                break;
        }
    }

    // トースト用関数
    private void dispmesse(String str) {
        Toast.makeText(this,str,Toast.LENGTH_SHORT).show();
    }

}

 

※自分メモ

※参考ブログ

qiita.com

pikopiko.artm.jp

wifiでAndroid端末とデバック接続をする

Window10PC上のadb.exeがAndroid開発環境ディレクトリになくてもOKでした。

AndroidStudioのUSBケーブル経由でAndroid開発モード機をつなぐ。

まずはcmd.exeでコマンドウインドウを開き

「cd C:¥Users¥あなた¥~色々~¥tools」等でadb.exeがあるディレクトリ移動

C:\Users\あなた\~\tools>adb tcpip 5555[ENT]

ここでAndroidStudioとつないでいたUSBを外す。

C:\Users\あなた\~\tools>adb connect 192.168.1.102[ENT]
connected to 192.168.1.102:5555

接続完了

C:\Users\あなた\~\tools>adb disconnect[ENT]

接続終了

ファイル選択からファイル名を取得する。

◎選択呼出し側

static final int REQUEST_OPEN_FILE = 1001;
private Context context;

 

context = MainActivity.this;

 

intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("text/csv");   //TEXT_CSV file only (←追記)
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(intent, "Open a file"), REQUEST_OPEN_FILE);

 

◎選択後戻り

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (RESULT_OK == resultCode) {
        if (REQUEST_OPEN_FILE == requestCode) {
            Uri uri = data.getData();
            String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};    // ※
            Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null) {
                String path = null;
                if (cursor.moveToFirst()) {
                    path = cursor.getString(0);
                    Log.d("kyo", path);
                }
                cursor.close();
            }
        }
    }
    super.onActivityResult(requestCode, resultCode, data);
}

 

◎得られる情報

「ファイル名.csv

 

※MediaStore.MediaColumns.DISPLAY_NAME

developer.android.com

 

(追記)intent.setType("*/*");にすると単なるファイル選択になり後の処理は分かりやすかった。

スクロールとレイアウト

Androidの画面をブラウザみたいに上下にスクロール出来るレイアウト指定にする

 

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:orientation="vertical"
            android:descendantFocusability="beforeDescendants"
            android:focusableInTouchMode="true"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

   …テキストやイメージやボタン

        </LinearLayout>
    </ScrollView>