处理片段中的新内容

时间:2013-03-17 02:10:39

标签: android android-intent android-fragments

我正在编写一个使用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);
}
}

这段代码完全像我的应用程序预期的那样,但是,我想知道是否有更好的方法来处理碎片中的新Intent?

3 个答案:

答案 0 :(得分:2)

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

首先,您的代码中存在错误:

您无法像Fragments那样在Activity内注册Activity作为听众。原因是系统可以销毁FragmentsActivity,然后从保存的状态重新创建(请参阅Recreating an Activity上的文档)。发生这种情况时,将创建FragmentFragment的新实例,但将onNewBalanceRead()设置为侦听器的代码将无法运行,因此Activity将永远不会被打电话这是Android应用程序中非常常见的错误。

为了传达从FragmentFragment的事件,我发现至少有两种可能的方法:

基于界面:

an officially recommended approach for communication between Fragments。这种方法与您现在使用的方法类似,它使用ActivityActivity实现的回调接口,但它的缺点是紧密耦合和许多丑陋的代码。

基于事件总线:

更好的方法(恕我直言)是利用事件总线 - "主要组件" (在您的情况下为Fragment)帖子"更新"事件到事件总线,而"从属组件" (在您的情况下为onStart())将自己注册到onStop()中的事件总线({{1}}中的注销)以接收这些事件。这是一种更清洁的方法,它不会在通信组件之间添加任何耦合。

我的所有项目都使用Green Robot's EventBus,但我无法推荐它。

答案 1 :(得分:0)

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

  

在接收新意图之前,活动将始终暂停,因此您可以指望在此方法之后调用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)
}

通过这种方式,活动不需要知道它所拥有的片段。

答案 2 :(得分:-2)

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

顺便说一下,你的代码中有一些错误:)

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

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

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

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

我们已经知道导航项目设置为1

} else {
    newBlanceListener.onNewBalanceRead(balance);

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