質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

5386閲覧

KotlinでAndroidStudioのWindowManagerの使い方について質問です。

Amanokawa

総合スコア41

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2017/09/12 05:59

###前提・実現したいこと
オーバーレイのviewをServiceから起動するとてもシンプルなプログラムを作りたい。
言語はkotlinで作っています。オブジェクト指向型の勉強を始めたばかりなので、とても単純なことしか理解できていないが故の質問かと思います。

windowManager.addView(view, params)とwindowManager.removeView(view)の実装をどのようにすればいいのかがわかりません。
windowManagerのインスタンス化はonCreate()で行っているので、onDestroy()に書いたwindowManagerはスコープの関係で実行できない。なので、メソッドの外で一度nullのwindowManagerを定義すればいいと考え、以下のコードを書きました。
ですが、onCreate()内のwindowManager.addView(view, params)とonDestroy()内のwindowManager.removeView(view)にエラーが出てしまっています。
どのように書けばよいでしょうか?

###発生している問題・エラーメッセージ
(windowManager.addView(view, params)部分)
Smart cast to 'WindowManager' is impossible, because 'windowManager' is a mutable property that could have been changed by this time.

(onDestroy()内のwindowManager.removeView(view)部分)
Only are allowed on a nullable receiver of type WindowManager?

###Serviceのソースコード(kotlin)

kotlin

1class OverlayService : Service() { 2 3 private var windowManager: WindowManager? = null 4 private var view: View? = null 5 6 override fun onCreate() { 7 super.onCreate() 8 Log.d("hoge", "onCreate") 9 10 windowManager = getSystemService(Service.WINDOW_SERVICE) as WindowManager 11 val layoutinflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater 12 view = layoutinflater.inflate(R.layout.overlay_service, null) 13 14 val params = WindowManager.LayoutParams( 15 WindowManager.LayoutParams.WRAP_CONTENT, 16 WindowManager.LayoutParams.WRAP_CONTENT, 17 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 18 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or 19 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or 20 WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or 21 WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, 22 PixelFormat.TRANSLUCENT) 23 24 //viewを開く 25 windowManager.addView(view, params) 26 27 } 28 29 override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { 30 Log.d("hoge", "onStartCommand") 31 32 return START_STICKY 33 } 34 35 override fun onDestroy() { 36 super.onDestroy() 37 Log.d("hoge", "onDestroy") 38 //viweを閉じる 39 windowManager.removeView(view) 40 41 } 42 43 //バインドしないからnull 44 override fun onBind(intent: Intent): IBinder? { 45 return null 46 } 47}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

kotlinのオプショナル型についての理解をなされるといいかと思います。
わかりづらいところもあると思うので、サイトの記事を読むもしくはコメントで質問なさってください

オプショナル型について

冒頭で定義されている以下の二つの変数はオプショナル型であり、nullを許容する型である前提を忘れないでください。

kotlin

1 private var windowManager: WindowManager? = null 2 private var view: View? = null

まず、次の二つの型は別物です。

kotlin

1 var windowManager1:WindowManager? = null // オプショナル型なので、nullを代入することができる 2 // 下のコードはエラーが発生します。 3 var windowManager2:WindowManager = null // 非オプショナル型なので、nullを代入することはできない

?のついた型と、?のついていない型は別の型であるという認識を忘れないでください。
nullのインスタンスから関数を呼び出すことはできないので、オプショナル型からの関数呼び出しには下記の例のように一工夫必要になります。

kotlin

1 optional?.hogehoge() // 安全呼び出し。optionalがnullの時は?の関数は呼び出されません。 2 optional!!.hogehoge() // 強制アンラップ。optionalがnullの時は落ちます。

エラーメッセージについて

以上を踏まえて、エラーメッセージを読んで見ます。

エラーメッセージ1

kotlin

1 windowManager.addView(view, params) // optionalから関数はそのまま呼べない!!

Smart cast to 'WindowManager' is impossible, because 'windowManager' is a mutable property that could have been changed by this time.

簡単にいうと、冒頭でWindowManager?で定義された変数は、どこで非同期に変更されるかわからないので、たとえ直前のコードでnullではない値が代入されていてもWindowManagerとして扱えないよということです。kotlinのスマートキャストに関する公式ドキュメントを読むとわかりやすいかと思います。
下記のように書き換えることで対処できます。

kotlin

1 windowManager?.addView(view, params) // windowManagerは直前に代入した後にnullになっている可能性がある 2 windowManager!!.addView(view, params) // windowManagerは直前に代入した後にnullになる可能性はない

エラーメッセージ2

kotlin

1 windowManager.removeView(view)

Only are allowed on a nullable receiver of type WindowManager?

まずエラーメッセージでググと次のようなサイトが出てくるので、見てみると良いでしょう。
これも同様にして、次のように書くことで対処できます。

kotlin

1 windowManager?.removeView(view) // windowManagerはnullになっている可能性がある 2 windowManager!!.removeView(view) // windowManagerはnullになる可能性はない

投稿2017/09/13 16:53

編集2017/09/13 16:54
hiramekun

総合スコア428

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Amanokawa

2017/09/14 00:56

大変丁寧な回答ありがとうございます。 non-nullとnullableは別物だったからエラーが出ていたわけですね! 関数を呼び出すときの?と!!の違いまで記述してくださり勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問