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

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

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

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

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

Q&A

解決済

2回答

13957閲覧

Activity内での重い処理を別スレッドで実行してUIに反映させる方法

Michy

総合スコア13

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

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

1グッド

1クリップ

投稿2019/01/11 17:55

##やりたいこと・課題
Androidアプリを開発中なのですが、重い処理が必要なActivityを起動する際に重い処理部分のみ別スレッドで行いたいと考えています。

onCreate内で重い処理に関係ないViewの呼び出しを行い、その後Thread内で重い処理+処理結果のViewへの反映を行いたいと思っているのですが、実装してもうまくいかず重い処理が完了するまでonCreateが完了しないように見えています。

実行時のコードは以下の通りなのですが、間違っている点や考え方のヒントでも良いので教えていただけないでしょうか。

##実行時のコード

kotlin

1 override fun onCreate(savedInstanceState: Bundle?) { 2 super.onCreate(savedInstanceState) 3 4 //レイアウト呼出 5 setContentView(R.layout.activity_emoji_list) 6 7 //重い処理結果を表示するViewIDを取得 8 val view=findViewById<FrameLayout>(R.id.viewID) 9 10 // 別スレッドを準備 11 Thread(Runnable { 12 // Handlerを使用して負荷の高い処理を投げる 13 handler.post { 14 15 function(xxxxxxx)//ここで重い処理を実行し、viewへ反映を行う。 16 17 } 18 }).start() 19 20 }
keicha_hrs👍を押しています

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

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

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

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

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

guest

回答2

0

原因

おそらくhandlerは次のような定義をしておられるだろうと思います。

Kotlin

1class MainActivity : AppCompatActivity() { 2 // (A) 3 val handler = Handler(Looper.getMainLooper()) // コンストラクター引数を省略しているかも 4 ... 5}

こうなっているとこのハンドラーへのpostはUIスレッドで実行されます。つまり

重い処理が完了するまでonCreateが完了しないように見えています

という質問者さんの推測どおりの動きになっていると思います。

本件のように「1回こっきりのバックグランド処理」にThreadを用いるのは理にかなっていると思いますが、単なるThreadに対してHandler#postでバックグラウンド処理を頼むことはできません。なぜならHandler#postは実行すべき処理をスレッドに結び付いたメッセージキューに繋げることで機能を実装しており、単なるTheadはこのメッセージキューを持っていないからです。
(HandlerThreadならばメッセージキューを持ってますのでHandler#postが行えますが、1回こっきりのバックグラウンド処理にHandlerThreadは合わないと思います。)

対処

Threadを用いるとき、そのスレッド上で動作する処理をどこに指定すればよいかというと以下のどちらかとするのが普通です。

  • コンストラクターの引数
  • Threadのrunメソッド本体

またUIスレッド以外のスレッドからviewへのアクセスには

  • (ア) 前述の(A)のような定義のhandlerへのpostによる
  • (イ) Viewインスタンスのpostメソッドによる
  • (ウ) ActivityインスタンスのrunOnUiThreadメソッドによる

などの方法があるようです。本件ですとhandlerをわざわざ定義せずとも(イ)や(ウ)でよい気がします。

Kotlin

1class MainActivity : AppCompatActivity() { 2 val handler = Handler(Looper.getMainLooper()) 3 4 override fun onCreate(savedInstanceState: Bundle?) { 5 ... 6 val view = findViewById<...>(...) 7 8 Thread { 9 // 重い処理 10 ... 11 view.post { 12 // viewへ計算結果を反映 13 view.なんたらかんたら 14 } 15 }.start() 16 } 17 18 ... 19}

余談

回答を書いていて自分にわからない点がありました。
onCreateが終わった後にユーザー操作やシステムの状態の変化などでこのActivityの状態が休止(pause)状態や停止(stop)状態になることを想定すべきと思うのですがそれってどうやるんでしょう・・・
onPause/onStopなどでバックグラウンド処理中だったら割り込みによりバックグラウンド処理を速やかに中断し、onResumeで再度開始なんて筋書きにするのでしょうか・・・
残念ながらAndroidに暗いのではっきりした方法がわかりませんでした。

投稿2019/01/12 04:14

KSwordOfHaste

総合スコア18392

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

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

KSwordOfHaste

2019/01/12 12:14

対処の冒頭に「2つの方法が普通です」と書きましたが、keicha_hrsさん回答にあるKotlinのconvenience functionがとても便利なのを知り「それがKotlinでの最も普通の方法」と思いました!
kakajika

2019/01/13 04:42

横入りすみません。余談についてコメントさせていただきます。 非同期タスクの完了時にUIを更新するような処理を書く場合、アプリのライフサイクルの状態によってはエラーを発生させる可能性があるのでその辺を考慮する必要がありますね。 最近では、Android Architecture ComponentsのLifecycleやRxLifecycleといったライブラリを使って非同期タスクの生存期間をライフサイクルにバインドしたりするのが主流になってきています。 詳しく書くと長くなるので省きますが、ご参考までに。
KSwordOfHaste

2019/01/13 04:54

> 非同期タスクの生存期間をライフサイクルにバインド なるほどそういう方式だとスッキリした設計ができそうですね。補足いただきありがとうございました!
guest

0

ベストアンサー

handlerの宣言が記されていませんが、多分ActivityのHandlerなのだろうと思います。このコードだと、「重い処理」がhandlerの指すスレッド、即ちActivityと同じスレッドで実行されてしまうでしょうから、別スレッドを作った意味がないでしょう。

kotlin

1 // 別スレッドを準備 2 thread { 3 function() // 重い処理 4 } 5

のように作成したthread(頭小文字のthreadはKotlinで提供される関数)上で直接function()を実行し、function()の中では

kotlin

1 fun function() { 2 3 runOnUiThread { 4 view.text = "hogehoge" // 例え 5 } 6 7 }

のような感じでViewを操作する箇所だけrunOnUiThread{}で囲めばいいのではないか(メッセージ渡すなど、Handlerである必要がないのであれば)と思います。

投稿2019/01/12 03:52

編集2019/01/12 03:56
keicha_hrs

総合スコア6766

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

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

KSwordOfHaste

2019/01/12 04:25

回答つかないなぁと思いつつHandlerのあやふやな記憶をネットで確認しつつコメント書いてたらかぶってしまいました... ところで最初のコードで`thread`はクラス名`Thread`のtypoのような気がしますがいかがでしょう?(Kotlinにあまり自信ないので自分にも確信がありません)
KSwordOfHaste

2019/01/12 11:52 編集

なるほど、そんな便利なものがあるんですね! 失礼しました&参考になりました! --- &回答中の説明を読み落としてました。スミマセンでした
Michy

2019/01/12 12:09

ご教示いただきありがとうございます! コメント頂いた内容で解決できました。推測頂いたとおりhandlerはActivityのHandlerとなります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問