iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
Mobile Development

花30天做個Android小專案系列 第 6

Day06 - Parsing Ptt(補充)

接續Day04,在確認連上Ptt後,會將頁面跳轉至Login頁,原本Day04應該要把這些都寫進去的,結果前幾天家人來找急著發文就忘了Orz

這篇預計先把Parsing的部分補充完,並加入Loading Layout供接下來登入流程使用。

Parsing

需先補充之前遺漏的部分。在透過PipedOutputStreamPipedInputStreamReader將Ptt Server回傳的byte array轉成二維的CharArray及字串後,我們需要一個方法來判斷目前的頁面到哪邊了。實作上是以PatternMatcher來判斷目前的頁面是否有符合我們需要的特徵。

fun <T> expect(patterns: Array<T>): Int {
    val list = ArrayList<Pattern>()
    patterns.forEach {
        when(it){
            is String ->{
                list.add(Pattern.compile(it))
            }
            is Pattern->{
                list.add(it)
            }
            else -> {
                list.add(Pattern.compile(Pattern.quote(it.toString())));
            }
        }

    }
    return expect(list)
}

private fun expect(list: List<Pattern>): Int {
    val endTime = System.currentTimeMillis() + defaultTimeout
    while (true) {
        val currentScreen: String = getScreen()
        for (i in list.indices) {
            val m: Matcher = list[i].matcher(currentScreen)
            if (m.find()) {
                return i
            }
        }
        Log.d(tag, "expect: no pattern match.")
        val waitTime = endTime - System.currentTimeMillis()
        if (waitTime <= 0) {
            return EXPECT_TIMEOUT
        }
        try {
            Thread.sleep(100)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }
}

expect方法會在設定的timeout到達前,每100毫秒檢查一次目前的頁面是否有符合我們需要的特徵,若有符合的話就回傳該特徵的index值,反之回傳EXPECT_TIMEOUT告知timeout。

以最初的Welcome跳轉至Login頁面為例,使用上方法如下:

PttClient.getInstance().start()
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
    if (PttClient.getInstance()
            .expect(arrayOf("請輸入代號,或以 guest 參觀,或以 new 註冊:")) == 0) {
        withContext(Dispatchers.Main) {
            NavHostFragment.findNavController(this@WelcomeFragment)
                .navigate(R.id.action_welcomeFragment_to_loginFragment)
        }
    }
}

也就是當畫面內容有顯示"請輸入代號,或以 guest 參觀,或以 new 註冊:"這個字串時,代表可以進行登入了,於是跳轉到下一頁的Login頁面讓使用者輸入帳密來做接續的登入。

Loading畫面

因為預期登入會是比較花時間的流程,所以決定先在MainActivity這邊加上一個Loading的Layout,在開始登入時顯示。

xml加入:

<!-- ... -->

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/loadingLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#66888888"
        android:clickable="true"
        android:focusable="true"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent"
            android:indeterminateTint="@color/white"
            app:layout_constraintBottom_toTopOf="@id/loadingMsg"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_chainStyle="packed" />

        <TextView
            android:id="@+id/loadingMsg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/transparent"
            android:textColor="@color/white"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/progress"
            tools:text="Loading..." />

    </androidx.constraintlayout.widget.ConstraintLayout>
    
<!-- ... -->

MainActivity加入:

public fun showLoading(msg: String) {
    loadingLayout.visibility = View.VISIBLE
    loadingMsg.text = msg
}

public fun showLoading(@StringRes msgId: Int) {
    loadingLayout.visibility = View.VISIBLE
    loadingMsg.setText(msgId)
}

public fun dismissLoading() {
    loadingLayout.visibility = View.GONE
    loadingMsg.text = ""
}

實際顯示如下:
loading

明天就是完成登入的部分了,也在這邊祝大家中秋節快樂~!


上一篇
Day05 - Android Jetpack: Navigation
下一篇
Day07 - Login to Ptt
系列文
花30天做個Android小專案30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言