简体   繁体   English

Kotlin 可以一个片段触发一个活动的onNewIntent

[英]Kotlin can a fragment trigger an activity's onNewIntent

I'm currently developing a scanner app which uses the Zebra SDK.我目前正在开发一个使用 Zebra SDK 的扫描仪应用程序。
In the samples and documentations that I found, an onTouchListener creates a new Intent (the scan) and broadcasts it.在我找到的示例和文档中,onTouchListener 创建了一个新的 Intent(扫描)并广播它。 In the overridden onNewIntent method, the intent gets decoded and the scanned values are returned.在重写的 onNewIntent 方法中,意图被解码并返回扫描的值。

This all works great as long as I use 1 activity and no fragments, but for the app I'm creating I would like to have 1 activity and multiple fragments.只要我使用 1 个活动且没有片段,这一切都很好,但是对于我正在创建的应用程序,我希望有 1 个活动和多个片段。 At the moment everything happens in 1 activity (and one view), but this is getting a bit cluttered and isn't the ideal way to do things, so I would split up the activity eventually.目前,一切都发生在 1 个活动(和一个视图)中,但这有点混乱,不是做事的理想方式,所以我最终会拆分活动。

I tried creating the fragments and pass the data between them using safeargs.我尝试创建片段并使用安全参数在它们之间传递数据。 but I couldn't figure out how to start the intent and capture the result from within the fragments.但我不知道如何开始意图并从片段中捕获结果。 I tried adding an onTouchListener in my fragment, which我尝试在我的片段中添加一个 onTouchListener,它

Below is the current code in the activity.以下是活动中的当前代码。 I don't have any fragments because all my attempts failed so far.我没有任何碎片,因为到目前为止我所有的尝试都失败了。

 override fun onTouch(view: View?, motionEvent: MotionEvent?): Boolean {
        if (view?.getId() == R.id.btnScanner) {
            if (motionEvent?.getAction() == MotionEvent.ACTION_DOWN) {
                //  Button pressed, start scan
                val dwIntent = Intent()
                dwIntent.action = "com.symbol.datawedge.api.ACTION"
                dwIntent.putExtra("com.symbol.datawedge.api.SOFT_SCAN_TRIGGER", "START_SCANNING")
                dwIntent.putExtra("Type", "START")
                sendBroadcast(dwIntent)
            } else if (motionEvent?.getAction() == MotionEvent.ACTION_UP) {
                //  Button released, end scan
                val dwIntent = Intent()
                dwIntent.action = "com.symbol.datawedge.api.ACTION"
                dwIntent.putExtra("com.symbol.datawedge.api.SOFT_SCAN_TRIGGER", "STOP_SCANNING")
                dwIntent.putExtra("Type", "END")
                sendBroadcast(dwIntent)
            }
        }
        return true
    }

 override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        if (intent.getStringExtra("Type") != "START") {
           //This would be for the first fragment
            if (personId.text.toString().isEmpty()) {
                val id = decodeScan((intent))
                personId.text = id
                lockId()
            } else {
              //This would be in the second fragment, after the user signed in by scanning his personal barcode
                if (productId.hasFocus() || productId.text.isEmpty()) {
                    val res = decodeScan(intent)
                    productId.text = res
                } else if (locationId.hasFocus() || (locationId.text.isEmpty() && productId.text.isNotEmpty())) {
                    val res = decodeScan(intent)
                    val location = (locations.filter { x -> x.contains(res) }).first()
                    locationId.setText(location)
                }
            }
        }
    }

onNewIntent is only available in the Activity, so you need to make the intent available to the fragments. onNewIntent仅在 Activity 中可用,因此您需要使意图对 Fragment 可用。

To do that, you can use MutableLiveData and ViewModel.为此,您可以使用 MutableLiveData 和 ViewModel。

class MyViewModel: ViewModel() {
    val intent = MutableLiveData<Intent?>() 
}

Then然后

class MyActivity: AppCompatActivity() {
    private val  myViewModel by viewModels<MyViewModel>() 
    
    override fun onCreate( savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.my_activity)
        val myViewModel = myViewModel
        myViewModel.intent = intent
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        myViewModel.intent = intent
    } 
}

And

class MyFragment: Fragment() {
    private val MyViewModel by activityViewModels<MyViewModel>() 

    ... 
}

And you can observe the current intent in onCreate using this for lifecycle owner.您可以使用生命周期所有者在 onCreate 中观察this意图。

Method onNewIntent belongs to Activity so you cannot use it in your fragment.方法 onNewIntent 属于 Activity,因此您不能在片段中使用它。 What you can do is, pass the data to your fragment when it call in onNewIntent provided, you have the reference to the fragment.您可以做的是,在提供的 onNewIntent 调用时将数据传递给您的片段,您拥有对片段的引用。

var fragment; //assign default value to fragment

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// you can add fragment based checks in this method                                       
   to work as you want
 if (fragment is YourFragment) {

    if (intent.getStringExtra("Type") != "START") {
       //This would be for the first fragment
        if (personId.text.toString().isEmpty()) {
            val id = decodeScan((intent))
            personId.text = id
            lockId()
        }
     }
    }else if (fragment is YourSecondFragment) {{
            if (productId.hasFocus() || productId.text.isEmpty()) {
                val res = decodeScan(intent)
                productId.text = res
            } else if (locationId.hasFocus() || (locationId.text.isEmpty() && 
               productId.text.isNotEmpty())) {
                val res = decodeScan(intent)
                val location = (locations.filter { x -> x.contains(res) }).first()
                locationId.setText(location)
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM