【问题标题】:Handling onNewIntent in Fragment在 Fragment 中处理 onNewIntent
【发布时间】:2013-03-05 14:41:00
【问题描述】:

我正在编写一个使用 NFC 读取存储在其上的一些数据的应用程序。我的应用程序使用 Fragments 并且 Fragment 不附带 onNewIntent() 方法。因为,我正在读取的数据是通过处理 NFC 相关操作的单独类完成的,所以我唯一需要做的就是更新 Fragment 中的 TextView。但是,此实现也可用于将新 Intent 传递给 Fragment。

这是我当前使用接口的实现。在收到新的 Intent 并且 NFC 相关检查成功后,我正在调用侦听器。这是托管 Fragment 的 FragmentActivity。

public class Main extends FragmentActivity implements
    ActionBar.OnNavigationListener {

private Bundle myBalanceBundle;
private NFC nfcObj;
private NewBalanceListener newBlanceListener;

@Override
public void onNewIntent(Intent intent) {
    setIntent(intent);
}

@Override
protected void onResume() {
    getNFCState();
    super.onResume();
}

private void getNFCState() {
    //Other NFC related codes
    else if (nfc_state == NFC.NFC_STATE_ENABLED){
        readNFCTag();
    }
}

private void readNFCTag() {
    //Other NFC related codes
    if (getIntent().getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
        nfcObj.setTag((Tag) getIntent().getParcelableExtra(
                NfcAdapter.EXTRA_TAG));
        nfcObj.readQuickBalance();

        transitQuickReadFragment(nfcObj.getCurrentBalance());
    }
}

private void transitQuickReadFragment(String balance) {
    // Creates a balance bundle and calls to select MyBalance Fragment if it
    // is not visible. Calls listener is it is already visible.
    if (actionBar.getSelectedNavigationIndex() != 1) {
        if (myBalanceBundle == null)
            myBalanceBundle = new Bundle();

        myBalanceBundle.putString(Keys.BALANCE.toString(), balance);

        actionBar.setSelectedNavigationItem(1);
    } else {
        newBlanceListener.onNewBalanceRead(balance);
    }
}

@Override
public boolean onNavigationItemSelected(int position, long id) {
    // Other fragment related codes
    fragment = new MyBalance();
    fragment.setArguments(myBalanceBundle);
    newBlanceListener = (NewBalanceListener) fragment;
    // Other fragment related codes
}

// Interface callbacks. You can pass new Intent here if your application
// requires it.
public interface NewBalanceListener {
    public void onNewBalanceRead(String newBalance);

}
}

这是 MyBalance Fragment,其中包含在读取 NFC 时需要更新的 TextView:

public class MyBalance extends Fragment implements NewBalanceListener {

private TextView mybalance_value;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    //Other onCreateView related code

    Bundle bundle = this.getArguments();
    if (bundle != null)
        mybalance_value.setText(bundle.getString(Keys.BALANCE.toString(),
                "0.00"));
    else
        mybalance_value.setText("0.00");

    //Other onCreateView related code
}

@Override
public void onNewBalanceRead(String newBalance) {
    mybalance_value.setText(newBalance);
}
}

此代码的工作方式与我的应用程序的预期完全一样,但我想知道是否有更好的方法来处理来自 Fragments 的新 Intent?

【问题讨论】:

标签: android android-intent android-fragments


【解决方案1】:

不,没有更好的方法。片段可以比活动更长寿,并且根本不需要与它们绑定,因此提供新的意图是没有意义的。

顺便说一句,您的代码中有一些错误:)

if (actionBar.getSelectedNavigationIndex() != 1) {

魔术数字很糟糕!使用常量。

    if (myBalanceBundle == null)
        myBalanceBundle = new Bundle();

    myBalanceBundle.putString(Keys.BALANCE.toString(), balance);
    actionBar.setSelectedNavigationItem(1);

我们已经知道navigationitem设置为1

} else {
    newBlanceListener.onNewBalanceRead(balance);

添加空检查。用户可能从未选择过导航项。

【讨论】:

  • 这没有回答原来的问题!关于如何在 Fragment 中使用 onNewIntent
【解决方案2】:

这是一个老问题,但让我回答一下,以防有人碰到它。

首先你的代码中有一个错误:

您不能按照您的方式将Fragments 注册为Activity 内的侦听器。原因是ActivityFragments 可以被系统销毁并在以后从保存状态重新创建(请参阅Recreating an Activity 上的文档)。当这种情况发生时,ActivityFragment 的新实例将被创建,但是将Fragment 设置为侦听器的代码将不会运行,因此onNewBalanceRead() 将永远不会被调用。这是 Android 应用程序中非常常见的错误。

为了将事件从Activity 传递到Fragment,我看到至少有两种可能的方法:

基于接口:

an officially recommended approach for communication between Fragments。这种方法与您现在所做的类似,因为它使用由FragmentActivity 实现的回调接口,但它的缺点是耦合紧密并且有很多丑陋的代码。

基于事件总线:

更好的方法(恕我直言)是利用事件总线-“主组件”(在您的情况下为Activity)将“更新”事件发布到事件总线,而“从属组件”(在您的情况下为Fragment ) 在onStart() 中将自己注册到事件总线(在onStop() 中注销)以便接收这些事件。这是一种更简洁的方法,不会在通信组件之间增加任何耦合。

我所有的项目都使用Green Robot's EventBus,我不能高度推荐它。

【讨论】:

    【解决方案3】:

    至少有一种选择:来自Activity.onNewIntent documentation

    在接收到新意图之前,Activity 总是会暂停,因此您可以指望在此方法之后调用 onResume()。

    请注意,getIntent() 仍然返回原始 Intent。您可以使用 setIntent(Intent) 将其更新为这个新的 Intent。

    FragmentActivity.onNewIntent documentation 不同,但我不认为它与上述陈述相矛盾。我还假设Fragment.onResume 将在FragmentActivity.onResume 之后被调用,尽管文档对我来说似乎有点挑剔,尽管我的测试证实了这个假设。基于此,我像这样更新了活动中的 Intent(Kotlin 中的示例)

    override fun onNewIntent(intent: Intent?) {
        setIntent(intent)
        super.onNewIntent(intent)
    }
    

    在 Fragment.onResume 中,我可以像这样处理新意图

    override fun onResume() {
        super.onResume()
        doStuff(activity.intent)
    }
    

    这样 Activity 不需要知道它持有哪些片段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      • 2016-12-15
      • 1970-01-01
      相关资源
      最近更新 更多