在FragmentPagerAdapter中设置包含TextView的Fragment中的文本

9
这真是让我抓狂。基本上,我想创建一个 ViewPager 并向其中添加一些 Fragment。然后,我只想在其中一个 FragmentTextView 中设置一个值。我可以很好地添加这些 Fragment,并将它们连接起来,但当我尝试为第一个 Fragment 中的一个 TextView 使用 findViewById() 时,它会抛出一个 NullPointerException。我真的想不明白为什么。
这是迄今为止我的代码,请告诉我是否需要更多的内容。
public class SheetActivity extends FragmentActivity {

    // /////////////////////////////////////////////////////////////////////////
    // Variable Declaration
    // /////////////////////////////////////////////////////////////////////////
    private ViewPager               viewPager;
    private PagerTitleStrip         titleStrip;
    private String                  type;
    private FragmentPagerAdapter    fragmentPager;  //UPDATE

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

        viewPager = (ViewPager) findViewById(R.id.viewPager);
        titleStrip = (PagerTitleStrip) findViewById(R.id.viewPagerTitleStrip);

        // Determine which type of sheet to create
        Intent intent = getIntent();
        this.type = intent.getStringExtra("type");
        FragmentManager manager = getSupportFragmentManager();
        switch (type) {
            case "1":
                viewPager.setAdapter(new InstallAdapter(manager));
                break;
            case "2":
                viewPager.setAdapter(new InstallAdapter(manager));
                break;
        }
        fragmentPager = (FragmentPagerAdapter) viewPager.getAdapter();  //UPDATE
    }

    @Override
    public void onResume() {
        super.onResume();

        fragmentPager.getItem(0).setText("something"); //UPDATE
    }

    class MyAdapter extends FragmentPagerAdapter {

        private final String[]      TITLES      = { "Title1", "Title2" };
        private final int           PAGE_COUNT  = TITLES.length;
        private ArrayList<Fragment> FRAGMENTS   = null;

        public MyAdapter(FragmentManager fm) {
            super(fm);
            FRAGMENTS = new ArrayList<Fragment>();
            FRAGMENTS.add(new FragmentA());
            FRAGMENTS.add(new FragmentB());
        }

        @Override
        public Fragment getItem(int pos) {
            return FRAGMENTS.get(pos);
        }

        @Override
        public int getCount() {
            return PAGE_COUNT;
        }

        @Override
        public CharSequence getPageTitle(int pos) {
            return TITLES[pos];
        }
    }
}

我创建的所有片段只覆盖了onCreateView()方法,以便我可以显示正确的XML布局。除此之外,它们都是“默认”的。为什么我不能与任何片段中的元素交互?
更新:
所以像这样做?
public class FragmentA extends Fragment {

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

    public void setText(String text) {
        TextView t = (TextView) getView().findViewById(R.id.someTextView);  //UPDATE
        t.setText(text);
    }
}

片段 A 的 XML 布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/someTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="22sp" />

</LinearLayout>
4个回答

6

TextView 位于片段布局中,而不是ViewPagersPagerAdapter中,这导致了NPE。现在你有两个选项。

  • The first is the easiest, you should simple move your code for changing the text into the corresponding fragment's class, FragmentA in this case.
  • Secondly, you could make the TextView into FragmentA static, so it can be accessed by other classes. So your code would look something like this:

     ....
     TextView myText;
    
     @Override
     public View onCreateView(....) {
    
         myLayout = ....;
    
         myText = myLayout.findViewById(yourID);
    
         ....
    }
    
然后,如果有必要,您可以从其他地方更改文本:
   FragmentA.myText.setText("new text");

方法二解释

在您的Fragment中使用以下内容。

public static void setText(String text) {
    TextView t = (TextView) getView().findViewById(R.id.someTextView);
    t.setText(text);
}

然后将文本更改为:
FragmentA.setText("Lulz");

在onCreateView(..)中,你应该使用你分配给要填充的布局的变量,并从中获取ID,就像我上面展示的那样。无论如何,为了使第二种方法起作用,片段必须已经启动,否则你将收到另一个NPE。 - Aashir
你在哪里调用了 setText(..) 方法? - Aashir
你确定你要查找的TextView在片段的布局中吗?另外,setText(...)方法不是静态的,你是在什么地方调用它呢? - Aashir
已更新上述代码。我使用了FragmentPagerAdapter来获取片段并设置文本。 - mandelbug
你知道你没有改变文本吗?默认情况下它设置为“something”,然后你又试图将“something”再次设置为文本,但这是不起作用的。使用我的setText(..)代码,我已经更新了我的答案。 - Aashir
显示剩余6条评论

4

除非你计划在运行时更改值,否则你可以将值作为参数传递到片段中。使用 Bundle 并将其作为 args 传递给 Fragment,然后从 args 中检索它即可完成。 更多信息请点击此处。如果你实施了这个方法,你创建新片段的方式可能看起来像这样:

public InstallAdapter(FragmentManager fm) {
            super(fm);
            FRAGMENTS = new ArrayList<Fragment>();
            FRAGMENTS.add(FragmentA.newInstance("<text to set to the TextView>"));
            FRAGMENTS.add(FragmentB.newInstance("<text to set to the TextView>"));
        }

如果您计划在运行应用程序时更新值(它会随着用户使用应用程序而变化),则需要使用接口作为片段和活动之间通信的渠道。详情请参见此处。下面是示例:
//Declare your values for activity;
    ISetTextInFragment setText;
    ISetTextInFragment setText2;
...
//Add interface
public interface ISetTextInFragment{
    public abstract void showText(String testToShow);
}
...
//your new InstallAdapter
public InstallAdapter(FragmentManager fm) {
        super(fm);

        FRAGMENTS = new ArrayList<Fragment>();

        Fragment fragA = new FragmentA();
        setText= (ISetTextInFragment)fragA;
        FRAGMENTS.add(fragA);

        Fragment fragB = new FragmentB();
        setText2= (ISetTextInFragment)fragB;
        FRAGMENTS.add(fragB);
}

//then, you can do this from your activity:
...
setText.showText("text to show");
...

它将更新片段中的文本视图。

虽然有更简单的方法可以实现,但推荐使用这些方法,因为它们可以减少错误的机会并使代码更易于阅读和维护。

编辑:这是你的片段应该看起来像的(修改了你的代码):

public class FragmentA extends Fragment implements ISetTextInFragment {

    TextView myTextView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle inState) {
        View v = inflater.inflate(R.layout.fragment_a, container, false);
        myTextView = (TextView)v.findViewbyId(R.id.someTextView)
        return v;
    }

    @Override
    public void showText(String text) {
        myTextView.setText(text);
    }
}

如果您仍然收到空指针异常,则说明您的TextView没有被定位在需要它的地方,即R.layout.fragment_a文件中,并且它需要被定位在那里。当然,除非您在片段加载完成之前调用了接口方法。

当您创建文本视图时(在onCreateView()中),您希望实例化它,然后在接口覆盖方法中设置它。 - C0D3LIC1OU5
在片段中调用 getView().findViewById() 时出现另一个 NPE。 - mandelbug
抱歉,我查看了你的代码 - 按照我的建议实现一个接口,我认为这将解决你的问题。 - C0D3LIC1OU5
添加了它,但仍然出现了NPE。我真的不明白。我试图在FragmentAsetText方法中获取getActivity()以用于Toast,但甚至这也会抛出NPE。就像Fragment没有保留任何东西一样。 - mandelbug
你能帮我处理一下这个问题吗?http://stackoverflow.com/questions/39907625/why-is-accessing-textview-of-a-fragment-inside-activity-throwing-an-error - Si8
显示剩余7条评论

1

This line:

TextView t = (TextView) findViewById(R.id.someTextViewInFragmentA);

代码在你的ParentActivity中查找视图。当然,它找不到它,这就是你得到空指针异常的原因。

尝试类似这样的东西:

  1. 在添加片段时为它们添加一个“标签”

  2. 使用someFragment = getSupportFragmentManager().findFragmentByTag("your_fragment_tag")

  3. 获取片段的视图fragmentView = someFragment.getView();

  4. 最后找到你的TextView并设置文本

    TextView t = (TextView) fragmentView.findViewById(R.id.someTextViewInFragmentA); t.setText("some text");


这通常是我会做的事情,但是MyAdapter添加了Fragments,所以我无法对它们进行标记。 - mandelbug
你能发布 MyAdapter 的代码吗?我认为在那里有一种方法可以添加标签。 - Carlos J
@Aashir 也说得有道理。你不能从你的 Fragment 类中更新 TextView 吗?那不是更容易吗? - Carlos J
我更新了上面的问题。类似这样?那也给了我一个NPE。 - mandelbug
我需要这样做吗?还是类似于我最新的更新就可以了? - mandelbug
显示剩余3条评论

0

这一行怎么改呢?

TextView t = (TextView) getView().findViewById(R.id.someTextView);  //UPDATE

TextView t = (TextView) getActivity().findViewById(R.id.someTextView);  //UPDATE

然后你可以在“SheetActivity”中使用.setText("some_string")来更新“t”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接