ページ 11

[android]透明な画面を常時表示する

Posted: 2013年4月30日(火) 22:31
by ひよつこ
こんばんは、ひよつこです。
今回もお世話になります。
現在作成中のビュアーアプリもどきとは関係のない話になりますが、よろしくお願いします。

AndroidのServiceはバックグラウンドで動作するため、
WindowManager.LayoutParamsの設定を変更することで
透明な画面を最前面に常時表示させることができる...ハズです。

そこで今回はそれを利用しIntentで渡した情報を元にTextViewを作成します。
そして、そのTextViewを透明な画面に組み込みます。
それによって、画面の最前面には常にユーザーが設定した文字を表示することができます。

そこで、そのようなプログラムを組んでみたのですが、文字を表示してからしばらく経つと、
表示されていた文字が消え、Intentからユーザーの設定した文字列が取得できなくなってしまいます。
ServiceのonDestroy()は呼ばれていないようなので全く原因がわかりません。

説明が下手でスミマセンがよろしくお願いします。

Re: [android]透明な画面を常時表示する

Posted: 2013年4月30日(火) 23:05
by ISLe
正しい前面表示の方法を知りたいということですか?
ネットで見付かる前面表示のサンプルプログラムでも同じように表示が消えるとか?

それともひよつこさん作ったプログラムだけで発生するのでしょうか。

後者であればコードを提示していただかないとどうしようもないですが。

Re: [android]透明な画面を常時表示する

Posted: 2013年5月01日(水) 22:17
by ひよつこ
返信ありがとうございます。
参考になればと思いコードを提示します。

コード:

	private LinearLayout layout;
	private WindowManager wManager;
	private WindowManager.LayoutParams params;
	private NotificationManager nManager;
	private Notification notification;
	private PendingIntent contentIntent;
	private Intent intent;

	@Override
	public void onStart(Intent _intent, int startId){
		super.onStart(intent,startId);
		nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		if(_intent != null)
			this.intent = _intent;
		contentIntent =PendingIntent.getActivity(this, 0, new Intent(this,メインアクティビティークラス), 0);
		wManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
		layout = new LinearLayout(this);
		layout.setLayoutParams(new LayoutParams(0, 0));
		//Notificationの作成
		notification = new Notification(画像Resourceのパス,"文字を表示します",System.currentTimeMillis());
		notification.setLatestEventInfo(getApplicationContext(),"設定","文字の設定",contentIntent);
		//透明な画面の作成
		params = new WindowManager.LayoutParams(
					WindowManager.LayoutParams.FILL_PARENT,
					WindowManager.LayoutParams.FILL_PARENT,
					WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
					WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
					PixelFormat.TRANSLUCENT);
		TextView text = new TextView(this);
		text.setText(this.intent.getStringExtra("text"));
		layout.addView(text);
		nManager.notify(R.string.app_name, notification);
		wManager.addView(layout, params);
	}

	@Override
	public void onDestroy(){
		super.onDestroy();
		wManager.removeView(layout);
		nManager.cancelAll();
	}
以上に提示したのがServiceのコードです。
どうかよろしくお願いします。

Re: [android]透明な画面を常時表示する

Posted: 2013年5月02日(木) 01:06
by ISLe
断片的なコードではほとんど何も分からないですが。

とりあえず「文字を表示してからしばらく経つと」というのは放っておいたServiceから文字が消えるということではないようですね。

Serviceを起動→通知領域をタップ→Activity起動→(※)→Serviceを起動→…
という動作を繰り返しているうちに※のところで渡しているはずの文字列が渡らないということでしょうか。

だとしたら問題はActivityのほうにあると思います。
デバッガを使って、あるいはログ出力して、ActivityがIntentにセットしている文字列をチェックしてみてください。
Intentにセットするときには既に消えていたりしないですか?

Re: [android]透明な画面を常時表示する

Posted: 2013年5月02日(木) 22:00
by ひよつこ
返信ありがとうございます。
アプリの状態が正しく伝わっていないようなのでもう一度説明させて頂きます。

まず今回のアプリのActivityはユーザーの設定した文字列をIntentに付けて
Serviceを起動する処理のみを行うもので、その文字列も正しくServiceに渡せています。

問題はServiceによって画面の最前面に表示された文字列が消えるという点です。
というのは、Serviceを起動してからしばらくは文字列が表示されているのですが、
他のActivityを起動したり、画面をOFFにしてしばらくすると表示されていた文字列が
消えてしまうのです。
また、文字列が消えてしまってから再びServiceのonStart()が呼ばれるようで、
Intentから文字列が取得できないと言われます。

わかりにくい説明だと思いますが、よろしくお願いします。

Re: [android]透明な画面を常時表示する

Posted: 2013年5月02日(木) 23:26
by ISLe
メンバに保持しておいたIntentの中から文字列が消えるということですか?

Intentは起動パラメータの受け渡しに使うものなので、参照を保持しておいてストレージのように使うことはできないのではないでしょうか。
調べてもそのへん公式に書かれたドキュメントは見付かりませんがわたしは引数で受け取ったメソッドの中でしか有効でないと考えます。

Serviceが再起動されるときにonStratの引数のIntentはnullなので、nullでなかったら文字列を取得すれば良いだけなのでは?

Re: [android]透明な画面を常時表示する

Posted: 2013年5月03日(金) 16:27
by ひよつこ
返信ありがとうございます。

調べてみたところServiceの再起動の時、onDestroy()は呼ばれず、
onCreate()、onStart()が呼ばれService内の全ての変数が初期化されていました。
そのため、必然的にServiceは表示するはずの文字列がわからなくなってしまうようです。

いったい、どこに問題があるのでしょうか。

Re: [android]透明な画面を常時表示する

Posted: 2013年5月03日(金) 17:26
by ISLe
AndroidはServiceにしろActivityにしろシステムの都合でインスタンスが破棄される仕様で基本的に考慮して作成すべきです。

調べたところ、onStartCommandでSTART_REDELIVER_INTENTを返すと再起動時にnullではなく前回と同じIntentを受け取れるらしいです。
この件に関してはIntentが取れれば良いのでこれで解決するかと思います。

onStratはAndroidバージョン2以降で非推奨(廃止予定)なのでonStartCommandを使いましょう。


Activityでもシステムの都合で破棄されるときonDestroyが呼ばれないことがあるそうです。
onDestroyは信用しないでデータ保存などの重要な処理は含めないようにしましょう。

Re: [android]透明な画面を常時表示する

Posted: 2013年5月07日(火) 18:57
by ひよつこ
返信ありがとうございます。

onStartCommand()の戻り値をSTART_REDELIVER_INTENTにしたら、
無事Intentから文字列を取得できました。

Serviceは再起動されることを前提に作るべきなのですね。
勉強になりました。
次回もよろしくお願いします。