为什么在Activity中访问Fragment的TextView会抛出错误

时间:2016-10-07 00:31:18

标签: java android android-fragments android-viewpager textview

MainActivity上课:

/* all necessary imports */

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    /* Other variable initialized here... */
    FragOne fo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        fo.setTextViewText("This is added from Activity");

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);

        tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
    }


    private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(new FragOne(), "My Tracker");
        adapter.addFragment(new FragTwo(), "Team Tracker");
        viewPager.setAdapter(adapter);
    }

    class ViewPagerAdapter extends FragmentPagerAdapter {
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_manage) {

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }
}

Fragment上课:

/* all necessary imports */
public class FragOne extends Fragment {

    TextView tvCName;

    public FragOne() {
        // Required empty public constructor
    }


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

        return view;
        //return inflater.inflate(R.layout.fragment_frag_one, container, false);
    }

    @Override
    public void onViewCreated(View view , Bundle savedInstanceState) {
        tvCName = (TextView) view.findViewById(R.id.tvctq);
    }

    public void setTextViewText(String value){
        tvCName.setText(value);
    }

}

Fragment XML布局:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.mytip.FragOne">

        <TextView
            android:text="TextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/tvctq" />
</FrameLayout>

我正试图从TextView访问Fragment内的MainActivity,如下所示:

FragOne fo;
fo.setTextViewText("This is added from Activity");

我一直在NullPointerExceptionError。我看了所有的文章,看看如何访问,但没有一个帮助我。

有人可以告诉我我做错了什么以及如何解决它?

我还计划在我的View中添加其他Fragment,我将来需要访问它。

4 个答案:

答案 0 :(得分:1)

由于fo尚未在以下代码段中初始化:

FragOne fo;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    fo.setTextViewText("This is added from Activity");
    ...
}

fo.setTextViewText()合理地抛出NPE

答案 1 :(得分:1)

您必须注意Activity生命周期 - 您似乎正确地设置了所有内容,但在实际准备好的时候犯了一些错误来访问片段的正确实例。你应该做的事情

  1. ViewPager获取正确的片段实例,例如@ginomempin建议;
  2. 只是尝试不早些时候设置您的文字,然后调用您的活动onStart方法 - 我通常会使用onResume方法(如果您还没有,则可以覆盖它)。在活动中使用onResume方法执行此操作可确保您的片段已经过了它的生命周期,直到onResume,并且如果之前已将数据带到后台,则数据将刷新。
  3. 这是一个生命周期图供您参考: enter image description here

答案 2 :(得分:1)

在活动中创建Fragment时,您需要使用Fragment工厂方法。请参阅以下内容:

**

Back Stack

**

修改片段的事务可以放在拥有活动的内部后台。当用户按下活动时,后台堆栈上的任何事务都会在活动本身完成之前弹出。

例如,考虑使用整数参数实例化的这个简单片段,并在其UI中的TextView中显示:

public static class CountingFragment extends Fragment {
int mNum;

/**
 * Create a new instance of CountingFragment, providing "num"
 * as an argument.
 */
static CountingFragment newInstance(int num) {
    CountingFragment f = new CountingFragment();

    // Supply num input as an argument.
    Bundle args = new Bundle();
    args.putInt("num", num);
    f.setArguments(args);

    return f;
}

/**
 * When creating, retrieve this instance's number from its arguments.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mNum = getArguments() != null ? getArguments().getInt("num") : 1;
}

/**
 * The Fragment's UI is just a simple text view showing its
 * instance number.
 */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.hello_world, container, false);
    View tv = v.findViewById(R.id.text);
    ((TextView)tv).setText("Fragment #" + mNum);
    tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
    return v;
}
}

一个创建片段的新实例的函数,替换正在显示的当前片段实例,并将该更改推送到后栈可写为:

void addFragmentToStack() {
mStackLevel++;

// Instantiate a new fragment.
Fragment newFragment = CountingFragment.newInstance(mStackLevel);

// Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.simple_fragment, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}

每次调用此函数后,堆栈中都会有一个新条目,然后按回来会弹出该条目以使用户返回活动UI所处的先前状态。

来源:https://developer.android.com/reference/android/app/Fragment.html

答案 3 :(得分:0)

您需要从viewpager获取FragOne的相同实例。

首先,您只能在设置ViewPager后访问FragOne实例 然后,试试这个:

fo = adapter.getItem(0)

注意:
由于您已经有片段,最好让片段本身处理与UI相关的操作(例如设置textview)而不是Activity。