我应该设置片段根视图的 ID 吗?

bry*_*yan 2 android android-fragments

我遇到了一个问题,即片段的根 ID 在被活动扩展时会发生变化。我能够解决这个问题,但我试图弄清楚是否应该始终避免将 ID 放在根视图上,以便在用户通过 XML 将其附加到活动的情况下不会重命名.

这是我的activity_main.xml

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragment"
    android:name="com.example.fragmenttest.MainActivityFragment"
    tools:layout="@layout/fragment_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
Run Code Online (Sandbox Code Playgroud)

这是我的 fragment_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mylayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivityFragment">

    <TextView
        android:text="@string/hello_world"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

现在,如果我想在片段的 onCreateView 期间引用 RelativeLayout,我可以调用 findViewById(R.id.mylayout) 并且它可以工作。但是,如果我稍后调用它,则无法使用

rl = getView().findViewById(R.id.mylayout);
Run Code Online (Sandbox Code Playgroud)

因为根视图的 ID 已更改为 R.id.fragment(我可以使用它来获取 RelativeLayout)。

所以我想知道我是否应该设置片段根视图的 ID,以防下一个开发人员直接在 XML 中使用它。

主要活动:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {

            MainActivityFragment fragment = (MainActivityFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.fragment);
            fragment.doIdTest();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
Run Code Online (Sandbox Code Playgroud)

和 MainActivityFragment:

public class MainActivityFragment extends Fragment {

    public MainActivityFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    public void doIdTest() {
        View rl = getView().findViewById(R.id.mylayout);

        if (rl == null) {
            Log.wtf("Ack!", "Can't find the RelativeLayout!");
        }

        rl = getView().findViewById(R.id.fragment);

        if (rl != null && rl instanceof RelativeLayout) {
            Log.wtf("Ack!", "ID of the relative layout is fragment!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可以在此处查看演示该问题的完整项目:https : //www.dropbox.com/s/08xu4bxi84rsms3/FragmentTest.tar.gz?dl=0

Dar*_*ind 5

我试过你的代码,恐怕我看到的东西和你一样 - Idrootview 的RelativeLayout实际上是从R.id.myLayoutR.id.fragment. :O

我做了一点挖掘,发现在Activity#setContentView它内部实际上调用了FragmentManager,作为回报,它将调用所有Fragment添加到Activity. 然后FragmentManager#onCreateView在被调用时Fragment#onCreateView被调用。

Fragment#onCreateView被称为随后的的rootviewFragment仍然是R.id.myLayout,但之后FragmentManager#onCreateView一直呼吁,由于某种原因,这种方法改变了IdmViewmInnerViewFragment在这部分代码:

if (id != 0) {
    fragment.mView.setId(id);
}
Run Code Online (Sandbox Code Playgroud)

此时fragment.mView已经有了Id一套—— R.id.myLayout.

代码中没有解释为什么会发生这种情况以及为什么需要它,但事实是它会发生。

作为参考,这里是该方法的PastebinFragmentManager#onCreateView

现在我要做的就是忘记Id R.id.myLayout你的RelativeLayout

您将始终能够RelativeLayout通过这样做从Activity例如:

MainActivityFragment fragment = (MainActivityFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
RelativeLayout rootView = (RelativeLayout) fragment.getView();
Run Code Online (Sandbox Code Playgroud)

getView将始终返回rootview,它可以转换的RelativeLayout。这并不漂亮,但我认为它应该是这样工作的。

如果您想获得RelativeLayout来自内部的Fragment,只需要调用getView直接丢在一个RelativeLayout或作出一个全局变量里面的rootview Fragment-这至少是我们在我的工作做在我们的代码:-)

此外,如果您删除IdFragment内部activity_main.xmlFragmentManager#onCreateView还是会覆盖当前Id你的RelativeLayout,你将无法使用View#findViewById依然。

至于为什么谷歌会覆盖这个Id我无法回答,但Fragment在我看来整个系统有点不稳定。

我希望这至少能说明实际发生的事情:-)