【Android】Activity間でデータの共有 ->Applicationクラスの使い方
各アクティビティ間でデータを共有したい時は通常
- Serializableインターフェイスを実装してIntent を使う
-> 確かプリミティブな型しか渡せなかったような気がする。
- Parcelableインターフェイスを実装してIntentを使う
-> オリジナルな型も渡せるけど実装がめんどくさかった気がする。
の方法がある。
だけど、双方とも実装がわかりづらいのと、
参照渡しが確か出来ないので受け渡し元で値が更新されるようなデータの共有には向いていない気がする。
そこでApplicationクラスを継承したデータ共有用のクラスを作成。
グローバル変数のように使えるので全体の見通しも良く使いやすくてGood.
使い方
Applicationクラスを実装したクラス
1. Applicationクラスを継承する
2. メンバーに共有する変数を宣言
3. onTerminateをオーバーライドする。
4. メンバーにアクセスするような関数を定義する。
参考例はこちら
public class MyApplication extends Application { private final String TAG = this.getClass().getName(); public HashMap<String, Double> sensor_data = new HashMap<String, Double>(); @Override public void onCreate() { super.onCreate(); sensor_data.put("SAMPLINGTIME", 0.0); sensor_data.put("ACC_X", 0.0); sensor_data.put("ACC_Y", 0.0); sensor_data.put("ACC_Z", 0.0); } @Override public void onTerminate() { super.onTerminate(); } /* * メンバーにデータをセットするためのメソッド */ public void setObj(String key, Double value){ sensor_data.put(key, value); } /* * メンバーからデータを取得するためのメソッド */ public double getObj(String key){ return sensor_data.get(key); } }
Applicationクラスにアクセスするクラス
1. this.getApplication() を実行してAppクラスが使用できるようにする。
2. Appクラスで定義したデータアクセス用のメソッド等を用いてデータにアクセスする。
参考例はこちら
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // このActivityを画面に表示 setContentView(R.layout.activity_sdc_can_disp); // 受信データを格納しているAppクラスを使用できるようにする myapp = (MyApplication)this.getApplication(); latestdata = new HashMap<String, Double>(); // データを取得 data = myapp.getObj("SDC_FACTOR_FL");
【Android】BindServiceの使い方
ServiceにはIntent ServiceとBindServiceがあり、それぞれの特徴は下記、
IntentService
- UIスレッドとは別のスレッドで作動する
- 実装が比較的楽そう
- 呼び出し元のActivityが破棄されても実行し続ける
BindService
- UIスレッドで動く..(2)
- 実装が少しめんどくさい
- 呼び出し元のActivityが破棄されると一緒に終了する...(1)
ここで呼び出し元のActivityが破棄されると一緒に終了するという特徴(1)が
アプリが終了しても変にサービスが残らなくていいかと思い、BindServiceを採用。
しかしのちに(2)の結局はUIスレッドで動作するという結果を知る.
よってBindServiceではUIの描画を妨げる程の思い動作には向いていないと思われるので注意.
使い方
呼び出し元
1. ServiceConnectionクラスのインターフェイスを実装したサブクラスを作成.
その中に onServiceConnected と onServiceDisconnected をOverrideする.
onServiceConnected内に呼び出し先で定義したBinderクラスを継承した独自クラスのインスタンスを受け取る
2. bindService()でServiceを起動する. bindServiceメソッドはContextクラスのため何もせずそのまま呼び出せる.
呼び出し先
1. Serviceを継承する.
2. onBindメソッドを継承する。これは最初にbindServiceされたときに呼ばれる。
ここでBinderクラスを継承した独自クラスのオブジェクトを返す.
3. Binderクラスを継承した独自クラスを定義する
ここにデータや処理を記述することで呼び出し元がbinderオブジェクトを通して操作できる
4. onCreate, onRunError, onUnbind, OnDestroyメソッドをOverrideする。
参考例はこちら
MainActivity.java (呼び出し元)
public class MainActivity extends AppCompatActivity { // ServiceConnection object class private ServiceConnection conn = new ServiceConnection() { // callback for connection successful @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { System.out.println("Service connected"); // onBindされたときにbinderが返される。このbinderにサービス側で処理やデータを格納しておいて使う側が呼び出す binder = (BindServiceSensorHandling.MyBinder) iBinder; } // callback for connection unsuccessful @Override public void onServiceDisconnected(ComponentName componentName) { System.out.println("Service disconnected"); } }; findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //サービスがすでに動いているかをチェック ActivityManager manage = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); for(ActivityManager.RunningServiceInfo serviceInfo : manage.getRunningServices(Integer.MAX_VALUE)) if(BindServiceSensorHandling.class.getName().equals(serviceInfo.service.getClassName())){ // 動いている場合は一回unBindする unbindService(conn); } // Bind BindService // Intent for MainActivity with Bind service final Intent intent = new Intent(MainActivity.this, BindServiceSensorHandling.class); bindService(intent, conn, Service.BIND_AUTO_CREATE); } } }
BindServiceSensorHandling.java (呼び出し先)
public class BindServiceSensorHandling extends Service{ // onBind()で返されるBinder private MyBinder binder; /* 最初のbindService呼び出しのみ、システムにIBinderインターフェースを渡すために呼ばれる。 */ @Override public IBinder onBind(Intent intent) { System.out.println("Service is binded"); binder = new MyBinder(); return binder; } /* Serviceのインスタンスがない状態で、クライアントがstartServiceまたはbindServiceを呼んだ時に *Serviceのインスタンス生成で呼ばれる。すでにインスタンスが存在している場合は呼ばれない。 */ @Override public void onCreate() {} /* onBind()で返されるbindeオブジェクト. ここに処理やデータを記述する。 */ public class MyBinder extends Binder { boolean sendRequest(int req){ String buf = String.valueOf(req); try { usbSerialPort.write(buf.getBytes(), WRITE_WAIT_MILLIS); return true; }catch (IOException e){ Log.e(TAG, "Mode request error"); return false; } } } @Override public void onRunError(Exception e) { Log.d(TAG, "Runner stopped"); } /*バインドしているクライアントが「全て」いなくなったときに呼ばれる。そのためunbindServiceが呼ばれても、 *ほかにバインドしているクライアントが存在した場合、onUnbindは呼ばれない。 */ @Override public boolean onUnbind(Intent intent) { disconnect(); System.out.println("System is unbined"); return true; } //バインドされたクライアントがなくなって、onUnbindが呼ばれたあとに呼ばれる @Override public void onDestroy() { System.out.println("Service is destroyed"); this.quit = true; } }
【Android】usb-serial-for-androidの使い方
使うとき
使用する際の流れはたぶん...
1. USBデバイスを取得
-> UsbManagerクラスの getSystemService
2. USBシリアルとして使用できるデバイスドライバのリストを列挙
-> UsbSerialProberクラスの getDefaultProber().findAllDrivers(usbManager)
3. 使用するUSBドライバでデバイスを開く
-> UsbManagerクラスの openDevice()
4. 使用するUSBドライバでUSBポートを開く
-> UsbSerialPortクラスの open()
5. シリアル通信パラメータ(BaudRateなど)を設定する
-> UsbSerialPortクラスのsetParameters()
6. データ送信要求をセットする *Arduino系と通信する際はこれが必要。
-> UsbSerialPortクラスのsetDTR()
7. データを送受信する
-> UsbSerialPortクラスのread/write
またはSerialInputOutputManager.Listenerクラスを実装してonNewDataメソッドをOverrideする
USBデバイスとそのデバイスのポートを開く必要がある。
また、6.のsetDTRをしないと通信がスタートしない物もあるので注意。
別途USBのパーミッション処理が必要。
使用例はこちら
public class BindServiceSensorHandling extends Service implements SerialInputOutputManager.Listener{ public SerialInputOutputManager usbIoManager; private UsbDeviceConnection usbConnection; private UsbSerialDriver usbdriver; public UsbSerialPort usbSerialPort; // 1 UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); // 2 List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager); // 3 usbdriver = availableDrivers.get(0); usbConnection = usbManager.openDevice(usbdriver.getDevice()); // 4. Open USB port usbSerialPort = usbdriver.getPorts().get(0); // Most devices have just one port (port 0) usbSerialPort.open(usbConnection); // 5 usbSerialPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // 6 usbSerialPort.setDTR(true); // 7. Listenerクラスをセット.非同期処理を開始 usbIoManager = new SerialInputOutputManager(usbSerialPort, this); Executors.newSingleThreadExecutor().submit(usbIoManager); }
終わるとき
1. USBポートを閉じる
-> UsbSerialPortクラスのclose()
2. リスナーを止める
-> UsbInputOutputManagerクラスのstop()
使用例はこちら
private void disconnect(){ if (usbSerialPort != null) { try { // 1 usbSerialPort.close(); usbSerialPort = null; } catch (IOException e) { } } if(usbIoManager != null) // 2 usbIoManager.stop(); usbIoManager = null; }
【Android】usb-serial-for-android セットアップ、jar作成、インポート
セットアップ
[20/06/10追記]
下記の方法でうまく行かないことがあったので本家のサイトに書かれているように
jitpackというサービスを使ってライブラリをインポートする方法に変更。
1. Projectのbuild.gradleに下記を追加
2. Module.appの方のbuild.gradleに下記を追加
これでライブラリが無事動くようになった。あら不思議。
[追記おわり]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
GitHubでプロジェクトをCloneする。
Cloneの方法は
ここに下記のパスを入れてCloneしてくる。
https://github.com/mik3y/usb-serial-for-android
Jar作成
ライブラリとして他のアプリケーションで使えるようJar化する。
1. build.gradleに処理を追加
下記のbuild.gradleに
を追加する。
いくつかのサイトには
from('build/intermediates/bundles/release/')と書かれていたがこのフォルダは自分がクローンしてたusb-serial-for-androidにはなぜかなく、
ビルドも失敗してしまったので、classes.jarが格納されていた'build/intermediates/aar_main_jar/release/'を使用したところbuild出来た。
2. モジュールのビルド
これを実行するとGradleのメソッド?オプション?からMakeJarが実行できるようになる。
3. MakeJar
これをダブルクリックで実行。
\usb-serial-for-android\usbSerialForAndroid\release\内にusbSerialForAndroidLibrary.jarができる。
【Python】Pyinstaller specファイル
Pyinstaller Specファイルのメモ
# -*- mode: python -*- block_cipher = None a = Analysis( [], # 実行する.pyファイル pathex=[''], # 上記.pyファイルが格納されているフォルダのパス binaries=[], # 依存するdllファイルがあれば datas=[], # 使用する画像ファイルやPDF、iniファイルを記述。タプルの2つ目はフォルダ指示。 e.g.) datas=[("memo.ini", ".")] hiddenimports=[], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) pyz = PYZ( a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.scripts, [], exclude_binaries=True, name='', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=False # 実行時のコンソール表示/非表示(debug時に使用すると便利) ) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name='')
Pyinstallerは実行時に
(例:%USERPROFILE%/AppData/Local/Temp/_MEIxxxxxx)
に展開されて実行される。
そのため、埋め込んだ画像ファイル等のリソースがこれを参照して実行するように
変更する必要あり。
Specファイルを作成後、
Terminalでカレントのディレクトリをspceファイルの場所まで移動して
>pyinstaller ***.spec
を実行する。