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

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

ただいまの
回答率

90.39%

  • Android

    7504questions

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

  • Kotlin

    641questions

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

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 501

Michy

score 6

やりたいこと・課題

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

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

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

実行時のコード

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //レイアウト呼出
        setContentView(R.layout.activity_emoji_list)

        //重い処理結果を表示するViewIDを取得
        val view=findViewById<FrameLayout>(R.id.viewID)

        // 別スレッドを準備
        Thread(Runnable {
            // Handlerを使用して負荷の高い処理を投げる
            handler.post {

                function(xxxxxxx)//ここで重い処理を実行し、viewへ反映を行う。

            }
        }).start()

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

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

        // 別スレッドを準備
        thread {
            function()  // 重い処理
        }

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

    fun function() {

        runOnUiThread {
            view.text = "hogehoge"  // 例え
        }

    }

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/12 13:25

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

    キャンセル

  • 2019/01/12 13:32

    typoではないです。回答中に書いた通り、Kotlinで提供されている関数です。startプロパティがデフォルトならばインスタンス生成と共に開始されるので、start()の呼び出しも必要ないものです。
    https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/thread.html

    キャンセル

  • 2019/01/12 13:46 編集

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

    キャンセル

  • 2019/01/12 21:09

    ご教示いただきありがとうございます!

    コメント頂いた内容で解決できました。推測頂いたとおりhandlerはActivityのHandlerとなります。

    キャンセル

+2

原因

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

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

こうなっているとこのハンドラーへの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をわざわざ定義せずとも(イ)や(ウ)でよい気がします。

class MainActivity : AppCompatActivity() {
    val handler = Handler(Looper.getMainLooper())

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val view = findViewById<...>(...)

        Thread {
            // 重い処理
            ...
            view.post {
                // viewへ計算結果を反映
                view.なんたらかんたら
            }
        }.start()
    }

    ...
}

余談

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/12 21:14

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

    キャンセル

  • 2019/01/13 13:42

    横入りすみません。余談についてコメントさせていただきます。

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

    キャンセル

  • 2019/01/13 13:54

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

    キャンセル

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

  • ただいまの回答率 90.39%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Android

    7504questions

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

  • Kotlin

    641questions

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