見出し画像

【データ配布】PythonでAndroidアプリ作成してみる #9 ログ画面の作成とアプリの完成

こんにちは、Rcatです。
さて、前回バックアップ機能のほとんどが完成しましたので、アプリ側の作り込みをやっていきたいと思います。
というのも前回バックアップしてる最中実はアプリが完全にフリーズするんですよね。
コンソール側の表示やサーバー側のログを見ればきちんと動作しているというのはわかるのですが、画面だけ見るとフリーズして何しているのかわからないという状態です。
というわけで、バックアップの進行状況がわかるように画面を追加していきましょう。
そして、今回の機能を組み込めばアプリとしては一応完成ということになります。一応とつけているのは最後に説明しますが、まだ終わりではありません。
ただ、一区切りついたのは事実なので現状のデータを一旦配布も行います。

本シリーズはこちら


画面のレイアウトについて

レイアウト検討

まずはアプリの画面レイアウトを考えていきましょう。
こちらに関しては一番最初に紹介したと思いますが、以下のような画面レイアウトで行きます。また使用する要素は次の通りです。
単純にログを表示するだけなので、今までのguiの中で最も単純です。
アクションは中止ボタンだけです。

KVファイルの作成

画面レイアウトのKVファイルは次のようにします。
ポイントとしてはログの表示が左上から始まるところくらいでしょうか?
このラベル表示を左上に固定しておかないと入力されている文字の量に応じて、ログがガンガン動くので非常に見づらいです。

<BackUpProgressScreen>:
    BoxLayout:
        orientation:'vertical'
        Label:
            id:title
            text: "進行状況"
            font_size: "30sp"
            size_hint_y: 0.1
        Label:
            id:log
            halign: 'left'
            valign: 'top'
            text_size: self.size
            text: ""
            font_size: "20sp"
            size_hint_y: 0.7
        Button:
            text: "キャンセル"
            id: Cancel_Button
            font_size: "10sp"
            size_hint_y: 0.1
            on_release:root.Cancel_Button_Click()

実際にできた画面がこちら
バックアップボタンを押さない表示されないので、すでにログが表示されています。

Python側クラスの作成

次にログのPython側です。
こちらも要素が少ないので非常に簡単です。
ポイントとしては画面切り替え時のイベントを変更しました。
前回までon_enterだったのですが、それだと画面が切り替わるアニメーションが終わってから呼び出されるのでタイミングが遅かったです。
それだとログの初期化よりも先にバックアップ関数の準備のログが入ってきてしまうので、ログ表示されないという問題がありました。
そのためpre_enterに変更しています。
次にログを表示する関数は一番下にあります。
効率がいいのか悪いのか分かりませんが、ログについてはqueueに保存しておき、10件分だけを毎回joinでつなげてテキスト化しています。HTMLならリストボックスに追加するんですが、kivyだと重くなるという話なのでこのような対応にしました。まぁ動いてることが分かればいいのです。気に入らない方はこの辺を変更しましょう。
また、キャンセルボタンはグローバル変数と結びつけており、そのステータスを変更することでキャンセルの実装を行っています。

class BackUpProgressScreen(Screen):
	def __init__(self, **kw):
		super().__init__(**kw)
		self.Logq = deque()
#-------------------------------------------------------------------------------------------
	def on_pre_enter(self):
		"画面切り替え時のイベント(kvファイルではなくここに書くだけでいい)"
		self.ids.log.text = ""
		self.Logq = deque()
		self.ids.Cancel_Button.text = "キャンセル"
#-------------------------------------------------------------------------------------------
	def Cancel_Button_Click(self):
		"キャンセルボタン押下時"
		global BackUPStatus
		BackUPStatus = False
		self.ids.Cancel_Button.text = "終了中"
#-------------------------------------------------------------------------------------------
	def Log(self,text):
		self.Logq.append(text)
		if len(self.Logq) > 10: self.Logq.popleft()
		self.ids.log.text = "\n".join(self.Logq)

グローバル領域で少し変更

画面切り替え実装時に紹介したこちらの部分ですが、少しグローバル領域にはみ出しています。
具体的にはログの部分です。まず、ログのスクリーンをインスタンスした後、その中のログを表示する関数だけグローバル変数に代入しています。
バックアップ自体はメインのスクリーンの中に収まっているものであり、このログスクリーンとの関係性が一切ないので、こうでもしない限りログが追加できないからです。
こうすることで代入した変数から関数を呼び出すことができ、どこでもログを追加することができます。

スレッドと画面切り替え

フリーズ対策

一番最初に述べましたが、バックアップボタンを押すとフリーズします。
これはボタンを押した時のイベントの中で全てバックアップの処理を行っており、終わるまで関数から抜けられないからです。

このような形でボタンを押したイベントで呼び出す関数か完全に終わるまで抜けられません。どうやら関数を抜けるまではguiがフリーズする仕様のようです。TKでもそうでしたので、まあ当たり前なんでしょうか

こうなったら解決する手段は一つみんな大好きthreadです。
というわけで下記のように変更しました。
この状態であれば、バックアップ関数を別スレッドで立てるので、イベント関数からすぐに抜けることができます。

スレッドでguiを更新できない問題が発生

さて、フリーズを解消できたのはいいのですが。バックアップ終了後、画面をログからメインに推移しようとしたところ、エラーが出ました。

TypeError: Cannot change graphics instruction outside the main Kivy thread

調べてみるとメインスレッド以外でguiに手を出したのが悪かったみたいです。今までgui系はまともに扱ってこなかったので初めて知りましたが、メインループ以外でguiに手を出すのは禁じてみたいです。

ログからメインに画面推移というのは、スレッドの最後に下記の行を追加することを言います

S.current="mainmenu"

対策(純正のイベントを使う)

いくつか調べていたところ、ちょうど良さそうなイベントがありましたので、そちらを使用することにしました。
実はすでにお見せしているのですが、ボタン押下時のイベントに"Clock.schedule_interval"というのがいるのがおわかりでしょうか?
これを使うことで、一定間隔のイベントを定義することができます。
今回はこのイベントの中に次のような関数を1秒おきに実行するというものを定義しています。
この方法で画面推移をすることでエラーを解消することができました。
常時見張っているというのがなんかもったいない気もしますが、しょうがないですね。

スマホにインストール

さて、パソコンでの動作確認ができたところで、スマホです。
結果はなんと一発オッケー。まあそんなに難しいことをしたわけではないですが、今まで何かしらここに持ってった瞬間NG食らってたので、すんなり行って良かったです。

アプリの全容

予定と現状の比較

ここで一区切りつきましたので、当初の予定と現状のguiがどのようになっているのか見ていきましょう。
比較は下記の通りです。当初の予定が甘くて足りない要素が追加されていたりしますが。ほぼ予定通りとなっています。

具体的なアプリの操作方法

それでは、ここでアプリの操作方法についておさらいしていきましょう。

まずはメイン画面です。
メイン画面ではプロファイルを選択とバックアップの開始、そして設定を行うことができます。
プロファイルが1つだけであれば、バックアップのボタンを押すだけで、すぐにバックアップを開始することができる仕様です。

設定画面です。メインから設定ボタンを押すことで移行できます。
クライアント情報として、クライアント名、パスワードサーバーの設定を行います。これらはサーバーと接続し、バックアップを開始する認証に使用します。

次にプロファイルの編集が行えます。
初回は新規作成を行い、プロファイルを作った後、フォルダー選択画面からフォルダを選び追加していきます。
フォルダーの左側のチェックはそのフォルダを保存するという意味です。全てのチェックを外すことで、プロファイルを削除することができます。

フォルダー選択画面
設定画面からフォルダを選択ボタンを押すことで移行できます。
バックアップしたいフォルダを選んで、そのフォルダの中身が表示されている状態で、選択ボタンを押すことでリストに追加できます。

進行状況
バックアップを開始するとこの画面が表示されます。
現在、どのフォルダーやファイルをバックアップしていくのかといったログが流れます。
一番下の中断ボタンを押すことでバックアップの中断を行うこともできます。

データの配布

まずはこの記事を書いている時点のソースコードの配布を行います。
これ以降の予定や今後の改造については、別個最新の記事で配布を予定しています。

ソースコード及びサーバー

https://script.google.com/macros/s/AKfycbysRqb7488rvLGPqOOhGlr0w513zIHC67BEPzJtPAKrAc4lKfDCmsB0mVL1Ha5BY5P0/exec?name=kivy_Androidアプリ_バックアップ_dev

アプリ(apk)

こちら

配布データの詳しい取得方法リンク先で紹介していますので、手順に則りご確認をお願いします。

まとめ

今回はアプリとして最低限の動作を組み込みを行いました。
これにて一応アプリとして使用することが可能です。
次回はアプリアイコンなどをカスタマイズして、ちゃんとしたリリースアプリとしてのコンパイルを行っていきたいと思います。
それではまたお会いしましょう。


情報が役に立ったと思えば、僅かでも投げ銭していただけるとありがたいです。