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])
}
}
}
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();
}
}
※自分メモ
※参考ブログ
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
(追記)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>