android開発　コルーチンの非同期スレッド実行中に、非同期スレッド内で取得したデータをディスプレイに表示する方法は？


android・コルーチンにおいて、非同期スレッドを実行中に、非同期スレッドで取得したデータをアンドロイドの画面に表示する方法をお教えください。

具体例として、jcifs-ng、コルーチンを使って、アンドロイド端末からSMBサーバーに接続してファイルをダウンロードする下記コードを書きました。  
このコードにおいて、SMBサーバーに接続した時点でサーバーのファイルの情報（ファイル名とかサイズとか）をアンドロイドの画面に表示するにはどうすればよいでしょうか？  
下記コードのconnectSmbDownload()関数内でのLogcat出力をアンドロイドの画面のTextView（tvInfo2）に表示させたいです。

[code]

    import android.os.Bundle
    import android.util.Log
    import android.view.View
    import android.widget.TextView
    import androidx.appcompat.app.AppCompatActivity
    import jcifs.CIFSContext
    import jcifs.config.PropertyConfiguration
    import jcifs.context.BaseContext
    import jcifs.smb.NtlmPasswordAuthentication
    import jcifs.smb.SmbFile
    import kotlinx.coroutines.*
    import java.io.File
    import java.io.FileOutputStream
    import java.util.*
    import kotlin.coroutines.CoroutineContext
    
    
    class MainActivity : AppCompatActivity(), CoroutineScope {
        // 認証情報
        //////////////////////////////////////////////
        // Please replace these values to your data //
        val user = "USER"
        val password = "PASS"
        val domain = "192.168.1.1"
        val smbroot = "smb://" + domain + "/SMB/SERVER/FILE/"
        //////////////////////////////////////////////
    
        val TAG: String = "MySMB"
    
        // coroutine準備
        private val job = Job()
        override val coroutineContext: CoroutineContext
            get() = Dispatchers.Main + job
    
        // 終了時のcoroutineのキャンセル設定
        override fun onDestroy() {
            job.cancel()
            super.onDestroy()
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            val tvInfo1 = findViewById<View>(R.id.txtVwInfo1) as TextView
            val tvInfo2 = findViewById<View>(R.id.txtVwInfo2) as TextView
            val tvInfo3 = findViewById<View>(R.id.txtVwInfo3) as TextView
    
            launch {
                // output start-message in display
                tvInfo1.setText("Start!")
    
                // connect SMB server and download a file
                val localFile: File? = connectSmbDownload(user, password, domain, smbroot)
    
                // output finish message in display
                if (localFile != null) {
                    tvInfo3.setText(localFile.length().toString() + "Byte downloaded.")
                } else {
                    tvInfo3.setText( "no file downloaded.")
                }
            }
        }
    
        private suspend fun connectSmbDownload(user: String, password: String, domain: String, smbroot: String): File? {
            return withContext(Dispatchers.IO) {
                // connect to SMB server
                val smb = connectSMB(user, password, domain, smbroot)
                Log.d(TAG, "Got SMB file: " + smb.path)
    
                // download a SMB file to android-device
                var downloadedFile: File? = null
                if (smb.isFile) {
                    downloadedFile = cpSmbFile2android(smb)
                } else {
                    Log.d(TAG, smb.path + " is not a file.")
                }
                downloadedFile
            }
        }
    
        private suspend fun connectSMB(user: String, password: String, domain: String, smbroot: String): SmbFile {
            return withContext(Dispatchers.IO) {
                val prop = Properties()
                prop.setProperty("jcifs.smb.client.minVersion", "SMB202")
                prop.setProperty("jcifs.smb.client.maxVersion", "SMB300")
                val bc = BaseContext(PropertyConfiguration(prop))
                val creds = NtlmPasswordAuthentication(bc, domain, user, password)
                val auth: CIFSContext = bc.withCredentials(creds)
                SmbFile(smbroot, auth)
            }
        }
    
        /*
         * リモートのSMBファイルをandroid端末にコピーする
         * 　コピー先は、android端末の外部ストレージのアプリキャッシュ領域
         *  smbFile  コピー元リモートのSMBファイル
         *  返り値　コピー先ファイル
         */
        private fun cpSmbFile2android(smbFile: SmbFile): File? {
            if ( !smbFile.isFile ) {
                return null
            }
            val fileName = smbFile.name
            val exterCacheFile = File(this.externalCacheDir!!.path + "/" + fileName)
            // copy remote smb-file to local
            val inStream = smbFile.openInputStream()
            val fileOutStream = FileOutputStream(exterCacheFile)
            val buf = ByteArray(1024)
            var len: Int = 0
            while (true) {
                len = inStream.read(buf)
                if (len < 0) break
                fileOutStream.write(buf)
            }
            fileOutStream.flush();
            fileOutStream.close();
            inStream.close();
            return exterCacheFile
        }
    }
    
[/code]




自己レスです。  
下記コードのように、非同期スレッドでの作業を1つのブロックにせず、メインスレッドにデータを渡したい場所の前後をそれぞれ別の関数とすることで非同期スレッド内のデータをメイスレッドに渡せました。  
今回の例で言えば、SMBサーバーへの接続とファイルダウンロードを1つの関数にしていたのを、SMBサーバー接続関数とファイルダウンロード関数に分け、SMBサーバー接続関数実行後にサーバーファイルのパスをアンドロイド画面に表示し、次にファイルダウンロード関数を実行することで解決しました。  
非同期スレッドの作業状況をプログレスバーで表示するようなことはどうすればよいか未だわかりませんので、お教えくだされば助かります。  
  

[code]

    import android.os.Bundle
    import android.view.View
    import android.widget.TextView
    import androidx.appcompat.app.AppCompatActivity
    import jcifs.CIFSContext
    import jcifs.config.PropertyConfiguration
    import jcifs.context.BaseContext
    import jcifs.smb.NtlmPasswordAuthentication
    import jcifs.smb.SmbFile
    import kotlinx.coroutines.*
    import java.io.File
    import java.io.FileOutputStream
    import java.util.*
    import kotlin.coroutines.CoroutineContext
    
    
    class MainActivity : AppCompatActivity(), CoroutineScope {
        // 認証情報
        //////////////////////////////////////////////
        // Please replace these values to your data //
        val user = "USER"
        val password = "PASS"
        val domain = "192.168.1.1"
        val smbroot = "smb://" + domain + "/SMB/SERVER/FILE/"
        //////////////////////////////////////////////
    
        val TAG: String = "MySMB"
        var tmpStr: String = ""
    
        // coroutine準備
        private val job = Job()
        override val coroutineContext: CoroutineContext
            get() = Dispatchers.Main + job
    
        // 終了時のcoroutineのキャンセル設定
        override fun onDestroy() {
            job.cancel()
            super.onDestroy()
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            val tvInfo1 = findViewById<View>(R.id.txtVwInfo1) as TextView
            val tvInfo2 = findViewById<View>(R.id.txtVwInfo2) as TextView
            val tvInfo3 = findViewById<View>(R.id.txtVwInfo3) as TextView
    
            launch {
                // output start-message in display
                tvInfo1.setText("Start!")
    
                withContext(Dispatchers.IO) {
                    // connect SMB
                    val smb: SmbFile = connectSmb(user, password, domain, smbroot)
                    tmpStr = java.lang.String.format("Got SMB file: %s", smb.path)
                    tvInfo2.setText(tmpStr)
    
                    // download a file from SMB to android
                    val localFile: File? = cpSmbFile2android(smb)
                    if ( null == localFile ) {
                        tmpStr = java.lang.String.format("Can't download: %s", smb.path)
                        tvInfo3.setText(tmpStr)
                    } else {
                        tmpStr = java.lang.String.format("Downloaded %s. %sByte", smb.path, localFile.length())
                        tvInfo3.setText(tmpStr)
                    }
                }
            }
        }
    
        private suspend fun connectSmb(user: String, password: String, domain: String, smbroot: String): SmbFile {
            return withContext(Dispatchers.IO) {
                val prop = Properties()
                prop.setProperty("jcifs.smb.client.minVersion", "SMB202")
                prop.setProperty("jcifs.smb.client.maxVersion", "SMB300")
                val bc = BaseContext(PropertyConfiguration(prop))
                val creds = NtlmPasswordAuthentication(bc, domain, user, password)
                val auth: CIFSContext = bc.withCredentials(creds)
                SmbFile(smbroot, auth)
            }
        }
    
        /*
         * リモートのSMBファイルをandroid端末にコピーする
         * 　コピー先は、android端末の外部ストレージのアプリキャッシュ領域
         *  smbFile  コピー元リモートのSMBファイル
         *  返り値　コピー先ファイル
         */
        private fun cpSmbFile2android(smbFile: SmbFile): File? {
            if ( !smbFile.isFile ) {
                return null
            }
            val fileName = smbFile.name
            val exterCacheFile = File(this.externalCacheDir!!.path + "/" + fileName)
            // copy remote smb-file to local
            val inStream = smbFile.openInputStream()
            val fileOutStream = FileOutputStream(exterCacheFile)
            val buf = ByteArray(1024)
            var len: Int = 0
            while (true) {
                len = inStream.read(buf)
                if (len < 0) break
                fileOutStream.write(buf)
            }
            fileOutStream.flush();
            fileOutStream.close();
            inStream.close();
            return exterCacheFile
        }
    }
    
[/code]

