Day24 - 回到预览页

今天要做的是从悬浮视窗还到预览页。

Day22中当我们启动ObserveService时会把MainActivity给终止掉,因此今天要做的内容事实上就是重启MainActivity後能直接回到PreviewFragment的过程。

nav_main.xml

启动时会在WelcomeFragment,由於已经是在Ptt内的状态,可以直接跳过LoginFragment到後面。另外为了达到PreviewFramgnet点击返回後能顺利回到SearchArticleFragment的路线,我新加的Navigation Action会是WelcomeFragmentSearchArticleFragment的路线,接着再另外回到PreviewFragment

在welcomeFragment下加入Action

<action
    android:id="@+id/action_welcomeFragment_to_searchArticleFragment"
    app:destination="@id/searchArticleFragment"
    app:popUpTo="@id/welcomeFragment"
    app:popUpToInclusive="true">
    <argument
        android:name="toPreview"
        android:defaultValue="true"
        app:argType="boolean"
        app:nullable="false" />
</action>

可以看到我加入的是一个带有argument的Action,这部份请参考Pass data between destinations

在searchArticleFragment下加入Argument

<argument
    android:name="toPreview"
    android:defaultValue="false"
    app:argType="boolean"
    app:nullable="false" />

这是与welcomeFragment的argument对应的,但是在这边的defaultValue设为false,这是为了避免从LoginFragment进来时被这个argument影响到。

searchArticleFragment_to_previewFragment加入argument

<argument
    android:name="isInArticle"
    android:defaultValue="false"
    app:argType="boolean"
    app:nullable="false" />

previewFragment中也加入一样的Argument,这是因为从悬浮视窗回来时Ptt本来就已在文章里面,不需要做原本PreviewFragmentDay16~Day17的内容中做的前置动作。

路线规划好後就是处理程序码的判断了。

ObserveService

主要就是在点击back时取消注册updateRunnable并开启新的MainActivity

binding.back.setOnClickListener {
    updateHandler.removeCallbacks(updateRunnable)
    val intent = Intent(this, MainActivity::class.java)
    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
    startActivity(intent)
}

WelcomeFragment

首先需要判断目前ObserviceService是否正在启动中。
ObserviceService加入:

class ObserveService : Service() {

    companion object {
        public var isRunning = false
    }
    
    override fun onCreate() {
        super.onCreate()
        isRunning = true
        // ...
    }
    
    override fun onDestroy() {
        super.onDestroy()
        isRunning = false
        // ...
    }
}

接着就能直接判断了:

class WelcomeFragment : Fragment() {
    //...
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        if (ObserveService.isRunning) {
            requireActivity().stopService(
                Intent(requireActivity(), ObserveService::class.java)
            )
            NavHostFragment.findNavController(this@WelcomeFragment)
                .navigate(R.id.action_welcomeFragment_to_searchArticleFragment)
            return
        }

        // ...
    }
}

ObserveService关闭并且使用刚刚新增的Action直接进到SearchArticleFragment,由於这个ActiontoPreview argument预设值为true,这边就不需要做另外的操作了。

SearchArticleFragment

判断若toPreviewtrue的话直接进入PreviewFragment。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    arguments?.run {
        if (SearchArticleFragmentArgs.fromBundle(this).toPreview) {
            this.clear()
            NavHostFragment.findNavController(this@SearchArticleFragment)
                .navigate(
                    SearchArticleFragmentDirections
                        .actionSearchArticleFragmentToPreviewFragment(
                            true
                        )
                )

            return@onViewCreated
        }
    }
    
    // ...
}

进入时记得要把isInArticle argument设为true

PreviewFragment

针对isInArticle做判断即可。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // ...
    arguments?.run {
        if (PreviewFragmentArgs.fromBundle(this).isInArticle) {
            updateHandler.post(updateRunnable)
        } else {
            viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
                PttClient.getInstance().send("G")
                delay(100L)
                parseComments(PttClient.getInstance().getScreen())

                updateHandler.postDelayed(updateRunnable, updateInterval)
            }
        }
    }
}

PttClient

先讲结论就是可能明後天会针对这个Class做修改了,具体要改成什麽样子我还在思考中。这边会提到是因为从PreviewFragment回到SearchArticleFragment时,我需要保留先前的搜寻状态,否则当进入ObserveService、把MainActivity退出後,原本存在SearchArticleFragment内的searchTitleSetsearchAuthorSetcurrentBoard都会被清掉。为了保留这些状态我是先把几个变数放到PttClient这个singleton class中了。

    public var currentBoard = ""
    public val searchTitleSet = mutableSetOf<String>()
    public val searchAuthorSet = mutableSetOf<String>()

接着在SearchArticleFragment开启时将值重新放入。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // ...
    binding.searchBoardInput.setText(PttClient.getInstance().currentBoard)
    // ...
    if ((PttClient.getInstance().searchAuthorSet.isNotEmpty()
                || PttClient.getInstance().searchTitleSet.isNotEmpty())
    ) {
        (requireActivity() as MainActivity).showLoading("")
        PttClient.getInstance().searchAuthorSet.forEach { addAuthorChip(it) }
        PttClient.getInstance().searchTitleSet.forEach { addTitleChip(it) }
        refreshSearch()
    }
}

最後就是如一开始所说的,PttClient的修改(or 重做)已经是势在必行了,毕竟目前使用上也不少别扭的地方。

目前画面

https://imgur.com/BdCjWjS.gif

到目前为止基本上App的主要画面和流程都已经出来了,接下来的几天应该就是针对现有内容做修改/优化了。


<<:  #23-用Canvas做Google恐龙游戏(都市老妹生存记!能击退经痛加班和渣男吗?)

>>:  DAY 27『 使用相机拍照 』 ImagePicker - Part1

成员 14 人:如何养好一池鲨鱼水族箱

「干部不强,我身上尽是汗水味;  干部太强,我身旁满是血腥味。」 年轻时候 待过的公司,共有三个部门...

Mysql执行成本-Part2(连接查询的成本、调节成本常数)

方便後续解释概念,我们在创建一个跟原先single_table一样的表,叫single_table2...

OpenCart + Journal 版型 = 地球表面最强的电商版型

如果您的电商网站,需要有个很多样化的首页,来应付不同档期的活动需求,不只是换换 Banner 而已,...

[JS] You Don't Know JavaScript [this & Object Prototypes] - Prototypes [上]

前言 我们在Object [上]与Object [下]中多次提到[[Prototype]],但是都没...

Day 6:建立口罩地图APP专案

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...