【问题标题】:Android fragment, findViewById() returning null, but getView() returning correct viewAndroid片段,findViewById()返回null,但getView()返回正确视图
【发布时间】:2015-09-13 16:44:08
【问题描述】:

我正在学习 android 片段。我为大屏幕做了一个单独的布局。这是布局:

<?xml version="1.0" encoding="utf-8"?>
    <!-- Used in layout-large folder -->
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:baselineAligned="false"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <fragment android:name="com.muktadir.news.HeadlinesFragment"
                  android:id="@+id/headlines_fragment"
                  android:layout_weight="1"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />

        <fragment android:name="com.muktadir.news.ArticleFragment"
                  android:id="@+id/article_fragment"
                  android:layout_weight="2"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />

    </LinearLayout>

这是 article_view 布局。

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent" android:layout_height="match_parent"
        android:id="@+id/article"
        android:padding="@dimen/article_view_padding"
        android:textSize="@dimen/article_view_text_size"
        android:text="I should be here">

    </TextView>

现在我从MainActivity 调用updateArticleView(),这实际上是在更新由ArticleFragment 膨胀的TextView。我通过这一行得到NULL

 getActivity().findViewById(R.id.article);

但是 getView() 工作正常,我可以更新文本。我打印了视图层次结构,它有元素,但不知何故,活动的findViewById() 无法返回对象。能解释一下吗?

public class ArticleFragment extends Fragment{

final static String ARG_POSITION = "position";
final static String TAG = "ArticleFragment";

int mCurrentPosition = -1;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if(savedInstanceState != null){
        mCurrentPosition = savedInstanceState.getInt(ARG_POSITION);
    }
    return inflater.inflate(R.layout.article_view, container, false);
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt(ARG_POSITION, mCurrentPosition); //can save negative!
}

@Override
public void onStart() {
    super.onStart();
    Bundle args = getArguments(); // this is to get the position of article for the first instantiation.
    if(args != null){
        updateArticleView(args.getInt(ARG_POSITION));
    } else if(mCurrentPosition != -1) {
        updateArticleView(mCurrentPosition);
    }
}

public  void updateArticleView(int selectedArticle){ // this is also called from mainactivity

    Activity myActivity = getActivity();
    Log.d(TAG, myActivity.toString());
    ViewGroup view = (ViewGroup) myActivity.findViewById(android.R.id.content);

    //printViewHierarchy(view , "debug");

    Log.d(TAG, "article id " + String.valueOf(R.id.article));
    // TextView article = (TextView) getActivity().findViewById(R.id.article);

    TextView article = (TextView) getView();
    Log.d(TAG, article.toString());
    article.setText(IpSum.Articles[selectedArticle]);
    mCurrentPosition = selectedArticle;

}

public static void printViewHierarchy(ViewGroup $vg, String $prefix)
{
    for (int i = 0; i < $vg.getChildCount(); i++) {
        View v = $vg.getChildAt(i);
        String desc = $prefix + " | " + "[" + i + "/" + ($vg.getChildCount()-1) + "] "+ v.getClass().getSimpleName() + " " + v.getId();
        Log.v("x", desc);
        if (v instanceof ViewGroup) {
            printViewHierarchy((ViewGroup)v, desc);
        }
      }
   }
}

【问题讨论】:

  • 我相信因为 TextView 是布局中的顶级元素,所以它的 ID 会被片段的 ID 覆盖。如果您查找 R.id.article_fragment 它应该返回 TextView。在某些平台上,有时(不确定确切的条件)片段被包裹在 NoSaveStateFrameLayout 中。
  • @EugenPechanec:如果您打印活动的视图层次结构,您将看到元素存在并且当片段返回视图时,它附加到活动的线性布局。在活动的布局中还有另一个片段。那么,实际上覆盖了什么以及在哪里覆盖?
  • 顺便说一句,如果我动态添加片段(在活动布局中没有类名),它确实有效。
  • 你片段布局的根(也是唯一)元素是一个带有@id/article 的TextView。当您对提供的片段进行膨胀时,@id/headlines_fragment(或@id/article_fragment)会覆盖片段的根视图的 ID。您会发现带有@id/headlines_fragment 和@id/article_fragment 的视图,它们都是TextView。
  • 当您动态添加片段时,您需要提供一个容器的 ID,片段会膨胀到该容器中,因此不会覆盖任何内容。请注意,现在您在活动中实际上有两个带有@id/article 的 TextView,因此无论何时调用 activity.findViewById,您总是会得到第一个。 fragment.getView().findViewById 是要走的路。

标签: android android-fragments android-view


【解决方案1】:

在你的 updateArticleView 上试试这个

 ViewGroup view = (ViewGroup) myActivity.findViewById(R.id.article_view);

 TextView article = (TextView) view.findViewById(R.id.article);

但我相信你必须接受@Damian Kozlak 的建议。

【讨论】:

  • 我已经在代码 [TextView article = (TextView) getView()] 中给出了解决方案。当 myActivity.findViewById(R.id.article_view) 返回 null 时,将其转换为 View 或 ViewGroup 都没有关系!我会进一步调查。
【解决方案2】:

它返回您null,因为您的布局不包含带有android:id="@+id/article" 属性的TextView。它是片段 article_view.xml 布局的一部分。

所以当你在片段中调用getView() 时,你调用的是当前片段视图。另外,绑定应该在onCreateView方法中完成:

private TextView article;

public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.article_view, container, false);

    article = (TextView) view.findViewById(R.id.article);

    return view;
}

【讨论】:

    【解决方案3】:

    这里的问题是 findViewById() 的范围。http://developer.android.com/reference/android/app/Activity.html 的文档说:

    onCreate(Bundle) 是您初始化活动的地方。最重要的是,在这里您通常会调用 setContentView(int) 并使用定义 UI 的布局资源,并使用 findViewById(int) 来检索该 UI 中需要以编程方式与之交互的小部件。

    findViewById() 方法在http://developer.android.com/reference/android/app/Activity.html#findViewById(int) 有进一步解释

    从 onCreate(Bundle) 中处理的 XML 中查找由 id 属性标识的视图。

    退货 如果找到则为视图,否则为 null。

    因此,该方法只能获取对您的 LinearLayout 的引用以及使用 setContentView() 膨胀的 2 个片段。 通过在片段中膨胀 article_view.xml 创建的视图是片段的根,因此 getView() 是此处的适当方法

    【讨论】:

    • 对不起。它根本没有违反文档。首先,您可以在 onCreate 之后将视图附加到视图层次结构中,并通过活动视图组的 findViewById 获取它们。其次,在我在这里写的情况下,Fragment 项目确实在 Layout 中,这确实是在 Activity 的 onCreate 中处理的。顺便说一句,代码取自 Derek Banas 教程,在 2013 年他做这些时应该可以使用,而评论者并没有遇到问题。
    • 哦,我认为这可能是问题所在,那么您找到导致空视图的原因了吗?
    • 有一天我会深入研究的。顺便说一句,当我动态添加片段时,这两种方式都有效。我看到在活动布局中给出片段类名称时会出现问题!如果您只是在布局中没有片段名称的活动的 onCreate 中添加片段,则不会发生问题!调试这种东西需要一些时间:(我希望一些大师会帮助我。
    猜你喜欢
    • 2014-04-30
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多