Kotlin 可以片段触发活动的 onNewIntent

问题描述

我目前正在开发一个使用 Zebra SDK 的扫描仪应用。
在我找到的示例和文档中,onTouchListener 创建一个新的 Intent(扫描)并广播它。在重写的 onNewIntent 方法中,意图被解码并返回扫描值。

只要我使用 1 个活动且没有片段,这一切都很好,但是对于我正在创建的应用程序,我希望有 1 个活动和多个片段。 目前一切都发生在 1 个活动(和一个视图)中,但这有点混乱,而且不是理想的做事方式,所以我最终会拆分活动。

我尝试创建片段并使用安全参数在它们之间传递数据。但我不知道如何开始意图并从片段中捕获结果。我尝试在我的片段中添加一个 onTouchListener,其中

以下是活动中的当前代码。我没有任何碎片,因为到目前为止我所有的尝试都失败了。

 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 仅在 Activity 中可用,因此您需要使 Intent 可用于片段。

为此,您可以使用 MutableLiveData 和 ViewModel。

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

然后

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
    } 
}

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

    ... 
}

您可以使用生命周期所有者的 this 观察 onCreate 中的当前意图。

,

方法 onNewIntent 属于 Activity,因此您不能在片段中使用它。您可以做的是,在提供的 onNewIntent 调用时将数据传递给您的片段,您可以引用该片段。

import React,{useCallback,useEffect,useState} from 'react';
import {ActivityIndicator,Dimensions,Text,View} from 'react-native';
import firestore from '@react-native-firebase/firestore';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import FolloweringScreens from './FolloweringScreens';
import {TouchableOpacity} from 'react-native-gesture-handler';

const {width,height} = Dimensions.get('screen');

function Following({urlname,navigation}) {
  const [followingData,setfollowingData] = useState();
  const [loading,setLoading] = useState(true);

  // Following counts,displayname,image
  const fetchData = useCallback(() => {
    const dataRef = firestore().collection('usernames');

    dataRef
      .doc(urlname)
      .collection('Following')
      .limit(25)
      .onSnapshot((snapshot) => {
        let promises = [];
        snapshot.forEach((doc) => {
          const promise = dataRef
            .doc(doc.id.toLowerCase())
            .get()
            .then((followerDoc) => {
              const data = followerDoc.data();

              return {
                profileName: doc.id,displayName: data.displayName
                  ? data.displayName
                  : data.userName,followerCount:
                  data.followers !== undefined ? data.followers : 0,followingCount:
                  data.following !== undefined ? data.following : 0,image: data.imageUrl ? data.imageUrl : null,};
            });
          promises.push(promise);
        });
        Promise.all(promises)
          .then((res) => setfollowingData(res))
          .then(setLoading(false));
      });
  },[]);

  useEffect(() => {
  const dataRef = firestore().collection('usernames');

    const cleanup = dataRef
      .doc(urlname)
      .collection('Following')
      .limit(25)
      .onSnapshot(fetchData);

    return cleanup;

    // fetchData();
  },[urlname,fetchData]);

  return (
    <>
      <View
        style={styles}>
        <TouchableOpacity onPress={() => navigation.openDrawer()}>
          <Icon name="menu" color="#222" size={30} />
        </TouchableOpacity>
        <Text style={{left: width * 0.05}}>Following</Text>
          </View>

      {loading ? (
        <ActivityIndicator size="large" color="black" />
      ) : (
        <>
          <FolloweringScreens data={followingData} />
        </>
      )}
    </>
  );
}

export default Following;