【问题标题】:Cannot access Textview inside fragment无法访问片段内的 Textview
【发布时间】:2017-05-19 13:40:59
【问题描述】:

我有一个活动,上面有一个片段,里面有一个 TextView。在 CourseFragment.java 中,我做了一个简单的方法来更改 TextView 的文本。但是,当我尝试从 Activity 调用片段的方法时,它说 TextView 对象为空。这是我的一些代码:

CourseFragment.java

public class CourseFragment extends Fragment {

private Subject subject;
View rootView;
private TextView title;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    rootView = inflater.inflate(R.layout.fragment_course, container,
            false);

    title = (TextView) rootView.findViewById(R.id.course_title);

    return rootView;
}

public void setTitle() {
    title.setText("My Title");
}

}

这是我的活动中的代码,用于制作新片段并放置在正确的位置:

CourseFragment fragment = new CourseFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.course1, fragment);
fragment.setTitle();
ft.addToBackStack(null);
ft.commit();

来自片段内部的 setTitle() 方法的错误

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference

这似乎很简单,但我不明白为什么我不断收到 NPE。我查看了有关此的类似问题并尝试了所有可接受的解决方案,但无济于事。有什么想法吗?

提前致谢

编辑:这里是根据要求的更多代码:

fragment_course.xml

的开头
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/course_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.stagenda.stagenda.CourseFragment"
    android:padding="16dp"
    android:orientation="vertical"
    android:background="@android:color/background_light">

    <RelativeLayout
        android:layout_width="match_parent"
        tools:ignore="UselessParent"
        android:background="@color/colorAccent"
        android:padding="16dp"
        android:layout_height="wrap_content"
        android:id="@+id/course_container">
<TextView
        android:text="Course Given Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/course_given_title"
        android:textColor="@android:color/background_light"
        android:textSize="18sp" />

    <TextView
    android:text="Course Title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/course_title"
    android:layout_below="@+id/course_given_title"
    android:textColor="@android:color/background_light" />

    <TextView
        android:text="Course Code"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/course_code"
        android:textColor="@android:color/background_light"
        android:layout_toRightOf="@+id/course_title"
        android:layout_below="@+id/course_given_title"
        android:layout_alignParentEnd="false"
        android:layout_marginStart="10dp" />

完全错误:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.stagenda.stagenda, PID: 1654
                  java.lang.IllegalStateException: Could not execute method for android:onClick
                      at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
                      at android.view.View.performClick(View.java:5639)
                      at android.view.View$PerformClick.run(View.java:22387)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6088)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                   Caused by: java.lang.reflect.InvocationTargetException
                      at java.lang.reflect.Method.invoke(Native Method)
                      at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
                      at android.view.View.performClick(View.java:5639) 
                      at android.view.View$PerformClick.run(View.java:22387) 
                      at android.os.Handler.handleCallback(Handler.java:751) 
                      at android.os.Handler.dispatchMessage(Handler.java:95) 
                      at android.os.Looper.loop(Looper.java:154) 
                      at android.app.ActivityThread.main(ActivityThread.java:6088) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
                   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
                      at com.stagenda.stagenda.CourseFragment.setTitle(CourseFragment.java:34)
                      at com.stagenda.stagenda.MainPage.confirmAddCourse(MainPage.java:435)
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288) 
                      at android.view.View.performClick(View.java:5639) 
                      at android.view.View$PerformClick.run(View.java:22387) 
                      at android.os.Handler.handleCallback(Handler.java:751) 
                      at android.os.Handler.dispatchMessage(Handler.java:95) 
                      at android.os.Looper.loop(Looper.java:154) 
                      at android.app.ActivityThread.main(ActivityThread.java:6088) 
                      at java.lang.reflect.Method.invoke(Native Method) 
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
I/Process: Sending signal. PID: 1654 SIG: 9
Disconnected from the target VM, address: 'localhost:8612', transport: 'socket'

explanation of layout (image)

【问题讨论】:

  • 尝试在commit方法后设置title。
  • 最好在 putExtra 中传递文本。所以这个片段没有被绑定。
  • 如果我在提交后设置标题没有区别。感谢您的快速回复
  • 您可以在fragment.setArgumanet(bundle) 中传递title 并在onCreateView 上获取title。
  • 为什么活动调用片段上的方法?这似乎是一个糟糕的设计。

标签: android android-layout android-studio android-fragments textview


【解决方案1】:

onCreateView() 方法在fragmentTransaction.commit() 之后调用。 由于您在fragmentTransaction.commit() 之前调用setTitle(),因此TextView 实例title 未实例化,因此为空。 在fragmentTransaction.commit() 之后添加行fragment.setTitle()

【讨论】:

    【解决方案2】:

    我自己想通了。问题出在这里:

    CourseFragment fragment = new CourseFragment();
    FragmentManager fm = getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.course1, fragment);
    fragment.setTitle();
    ft.addToBackStack(null);
    ft.commit();
    

    问题是我在没有创建视图的片段上调用 ​​setTitle()。相反,当我执行以下操作时,问题得到了解决:

    CourseFragment fragment = new CourseFragment();
    FragmentManager fm = getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.course1, fragment);
    ft.addToBackStack(null);
    ft.commit();
    
    CourseFragment frag = fm.findFragmentById(R.id.course1);
    frag.setTitle();
    

    我最终更改了很多代码,但我希望这对某人有所帮助。谢谢大家的回答

    【讨论】:

      【解决方案3】:

      通过使用 Framgnet 回调 解决了这个问题,如http://developer.android.com/training/basics/fragments/communicating.html 中所述,我相信最好的方法是在创建片段 TextViews 后将其传递到我的活动中。

      【讨论】:

        【解决方案4】:

        您可以做的一件事是将数据作为参数传递:

        CourseFragment fragment = new CourseFragment(Your title);
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.course1, fragment);
        ft.addToBackStack(null);
        ft.commit();
        

        您也可以使用 Bundle 来传递您的数据。

        【讨论】:

        • 问题是没有传递数据。问题是告诉片段更新其 TextView
        • @krz。传递数据并在onCreateView 更新片段的标题。 (如果您在片段之间或从活动到片段动态传递数据,请考虑侦听器(接口)。
        【解决方案5】:

        标签布局:

        <?xml version="1.0" encoding="utf-8"?>
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:background="#ffffff">
        
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_scrollFlags="scroll|enterAlways"
                    app:layout_collapseMode="pin"
                    android:background="#000000"
                    app:titleTextColor="#ffffff"
        
                    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                    app:popupTheme="@style/PopupMenuStyle">
        
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="?attr/actionBarSize"
                        android:id="@+id/textview"
                        android:textColor="@color/colorTrueWhite"/>
        
                </android.support.v7.widget.Toolbar>
        
                <!-- our tablayout to display tabs  -->
                <android.support.design.widget.TabLayout
                    android:id="@+id/tabLayout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/colorBlack"
                    android:minHeight="?attr/actionBarSize"
        
                    app:tabIndicatorColor="@color/colorTrueWhite"
                    app:tabIndicatorHeight="5dp"
                    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
        
                <!-- View pager to swipe views -->
        
        
                <android.support.v4.view.ViewPager
                    android:id="@+id/pager"
                    android:layout_width="match_parent"
                    android:layout_height="fill_parent"/>
        
        
            </LinearLayout>
        

        使用该布局的活动:

        public class Main2Activity extends AppCompatActivity implements TabLayout.OnTabSelectedListener {
        
            private TabLayout tabLayout;
            public static ViewPager viewPager;
            public static Context ctx;
            Pager adapter;
            public static int expired, paid;
            Boolean isConnection;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main2);
        
                Toolbar tb = (Toolbar) findViewById(R.id.toolbar);
                setSupportActionBar(tb);
        
                TextView tv = (TextView) findViewById(R.id.textview);
        
                //getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        
        
                ctx = getApplicationContext();
        
        
                StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
                StrictMode.setThreadPolicy(policy);
        
        
                tabLayout = (TabLayout) findViewById(R.id.tabLayout);
                viewPager = (ViewPager) findViewById(R.id.pager);
        
        
                tabLayout.addTab(tabLayout.newTab().setText("title1"));
                tabLayout.addTab(tabLayout.newTab().setText("title2"));
                tabLayout.addTab(tabLayout.newTab().setText("title3"));
                tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
                tabLayout.setupWithViewPager(viewPager);
        
                adapter = new Pager(getSupportFragmentManager(), tabLayout.getTabCount(), ctx);
                viewPager.setAdapter(adapter);
        
        
                if(some condition)
                {
                    viewPager.setCurrentItem(2);
                }
                else
                {
                    viewPager.setCurrentItem(1);
                }
                viewPager.setOffscreenPageLimit(2);
        
                tabLayout.addOnTabSelectedListener(this);
        
                ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
                int tabsCount = vg.getChildCount();
                for (int j = 0; j < tabsCount; j++) {
                    ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
                    int tabChildsCount = vgTab.getChildCount();
                    for (int i = 0; i < tabChildsCount; i++) {
                        View tabViewChild = vgTab.getChildAt(i);
                        if (tabViewChild instanceof TextView) {
                            ((TextView) tabViewChild).setTypeface(Typeface.DEFAULT, Typeface.BOLD);
                        }
                    }
                }
            }
        
        
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
            }
        
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }
        
        
        }
        

        寻呼机代码:

        public class Pager extends FragmentStatePagerAdapter
        {
            int tabcount;
            Context ctx;
            private String [] Titles = {"title1", "title2", "title3"};
        
            public Pager(FragmentManager fm, int tabcount, Context ctx)
            {
                super(fm);
                this.tabcount = tabcount;
                this.ctx = ctx;
            }
        
            @Override
            public int getCount() {
                return tabcount;
            }
        
            @Override
            public CharSequence getPageTitle(int position) {
                return Titles[position];
            }
        
            @Override
            public Fragment getItem(int position) {
        
                switch (position) {
        
                    case 0:
                        Tab1 tab1 = new Tab1();
                        return tab1;
        
                    case 1:
                        Tab2 tab2 = new Tab2();
                        return tab2;
        
                    case 2:
                        Tab3 tab3 = new Tab3();
                        return tab3;
        
                    default:
                        return null;
                }
            }
        
        
        }
        

        【讨论】:

          【解决方案6】:

          片段事务不是同步的。当你添加一个事务时,它可以在主循环器有机会运行它时执行(它会排队等待稍后)。

          这意味着在当前方法结束之前,片段会被附加。检查CourseFragment.setTitle()onCreateView()的执行顺序。

          查看 FragmentTransaction.commit() 的文档:commit

          如果适合您,请考虑使用commitNow()

          另外,考虑将标题作为参数传递给片段,以便可以使用getArguments()onCreateView 中读取它。

          【讨论】:

          • 我认为片段将为可从活动访问的每个控件提供一个方法。从我对 android 片段如何工作的研究中,我了解到这是在片段中更改控件的正确方法。我误会了吗?
          • 考虑当设备旋转并且活动和片段都被重新创建时会发生什么。对CourseFragment.setTitle() 的调用会再次运行吗?我无法从您发布的示例代码中看出。理想情况是不需要。片段应该有信息知道要在 TextView 中显示什么文本。这是通过将其作为参数传递来完成的。我仍然建议您检查两个函数的调用顺序;订单不应耦合。
          【解决方案7】:

          采用这种方法。

           Bundle bundle = new Bundle();
              bundle.putString("title", "whatever you want to pass");
          
                  CourseFragment fragment = new CourseFragment();
                  fragment.setArguments(bundle);
                  FragmentManager fm = getFragmentManager();
                  FragmentTransaction ft = fm.beginTransaction();
                  ft.replace(R.id.course1, fragment);
                  ft.addToBackStack(null);
                  ft.commit();
          
          
          
              public class CourseFragment extends Fragment {
          
              private Subject subject;
              View rootView;
              private TextView title;
              Bundle bundle;
          
                @Override
                  public void onCreate(@Nullable Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
          
                      bundle = getArguments();
                   }
          
              @Override
              public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                       Bundle savedInstanceState) {
                  // Inflate the layout for this fragment
                  rootView = inflater.inflate(R.layout.fragment_course, container,
                          false);
          
                  title = (TextView) rootView.findViewById(R.id.course_title);
          
                  String text = bundle.getString("title");
                  title.setText(text);
          
                  return rootView;
              }
          
          
              }
          

          【讨论】:

          • @krz 如果这不起作用,请检查您的 xml 文件 course_title id 是否存在。
          • 我添加了部分 xml 文件。 course_title 在那里
          • 在主要活动上有一个名为 CoursesFragment(课程列表)的片段。在 CoursesFragment 内有另一个 id 为 course1(第一门课程)的片段。 CourseFragment 被放入 course1。
          • 为了清楚起见,这里有两张截图:snag.gy/SJnyFv.jpgsnag.gy/1JdfOV.jpg
          • 这种方法对于在活动和片段之间传递参数很有意义,但我仍然在线获得 NPE:title.setText(text);
          猜你喜欢
          • 1970-01-01
          • 2020-06-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多