java - 从 MainActivity 修改 Fragment 的 View

标签 java android android-fragments android-viewpager

我正在尝试使用 android 实现滑动 View 。我正在使用带有两个包含 fragment 的选项卡的 ViewPager。在我的 onCreate() 方法中,我试图从 sharedPreferences 中读取,并根据我得到的内容,我想将文本和可见性更改为第一个 fragment 的父 View 的某些 subview 。不幸的是,当我尝试访问 fragment View 时,我总是得到 NullPointerException。

下面给出了我来自两个 fragment 之一的示例代码。请你帮助我好吗 ?有更好的方法吗?

主要 Activity :

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

    actionBar = getActionBar();
    context = getApplicationContext();
    myTabPagerAdapter = new TabPagerAdapter(getSupportFragmentManager());

    myViewPager = (ViewPager) findViewById(R.id.pager);
    myViewPager.setAdapter(myTabPagerAdapter);
    myViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            Toast.makeText(MainActivity.this, "Selected page position: " + position, Toast.LENGTH_SHORT).show();
            getActionBar().setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    ActionBar.TabListener tabListener = new ActionBar.TabListener() {

        @Override
        public void onTabReselected(android.app.ActionBar.Tab tab, FragmentTransaction ft) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
            myViewPager.setCurrentItem(tab.getPosition());
        }

        @Override
        public void onTabUnselected(android.app.ActionBar.Tab tab, FragmentTransaction ft) {
            // TODO Auto-generated method stub
        }
    };
    actionBar.addTab(actionBar.newTab().setText("Spot Position").setTabListener(tabListener));
    actionBar.addTab(actionBar.newTab().setText("Track Vehicle").setTabListener(tabListener));


    //Get saved latitude and longitude from sharedPreferences
    sharedPref = context.getSharedPreferences("net.ddns.drimou.bachelorthesis", Context.MODE_PRIVATE);
    editor = sharedPref.edit();



}

@Override
protected void onStart() {
    super.onStart();
    getSharedPreferencesOnStart();
}

public void getSharedPreferencesOnStart() {

        String s = myTabPagerAdapter.makeFragmentName(myViewPager.getId(),myViewPager.getCurrentItem());
        SpotPosition sp =  (SpotPosition) myTabPagerAdapter.getItem(0);
        sp.setSettings();//In this call i am getting null pointer

...}

fragment A

public class SpotPosition extends Fragment {


TextView locationTextView;



@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View spotPosition = inflater.inflate(R.layout.spot_position, container, false);

    return spotPosition;


}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
}

public void setSettings(){
    locationTextView = (TextView) myView.findViewById(R.id.mainTextView);//NullPointerException here
    locationTextView.setVisibility(View.VISIBLE);
    locationTextView.setText("Hello");
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public void onDestroyView() {
    super.onDestroyView();
}

TabPagerAdapter

public class TabPagerAdapter extends FragmentPagerAdapter {

SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
private View mCurrentView;
private SpotPosition sp = null;
private static int NUM_ITEMS = 2;

public TabPagerAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public Fragment getItem(int i) {
    switch (i) {
        case 0:
            //Fragment for SpotPosition myViewPager
            return new SpotPosition();
        case 1:
            //Fragment for TrackVehicle myViewPager
            return new TrackVehicle();
    }
    return null;

}

@Override
public int getCount() {
    return NUM_ITEMS; //Number of Tabs
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment fragment = (Fragment) super.instantiateItem(container, position);
    registeredFragments.put(position, fragment);
    return fragment;
}

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    sp = (SpotPosition)object;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    registeredFragments.remove(position);
    super.destroyItem(container, position, object);
}

@Override
public CharSequence getPageTitle(int position) {
    switch(position) {
        case 0:
            return "Spot Position";
        case 1:
            return "Track Vehicle";
        default:
            return null;
    }
}

public String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

public Fragment getRegisteredFragment(int position) {
    return registeredFragments.get(position);
}

@Override
public int getItemPosition(Object object) {
    return POSITION_NONE;
}

public View getCurrentView(){
    return this.mCurrentView;
}

public SpotPosition getCurrentSpotPosition(){
    return this.sp;
}

有什么不明白的地方欢迎提问。谢谢

最佳答案

据我了解,您从 Activity 中调用 setSettings 来更改 fragment 中的 View 。您没有提供堆栈跟踪,我认为您有问题 - 在 offcreen fragment 中调用 onPause 后尝试更改 View 。有几种方法可以处理它。 首先不要直接调用 View 。
关于 Activity

    public void getSharedPreferencesOnStart() {

            String s = myTabPagerAdapter.makeFragmentName(myViewPager.getId(),myViewPager.getCurrentItem());
            SpotPosition sp =  (SpotPosition) myTabPagerAdapter.getItem(0);

            // sp.setSettings();//In this call i am getting null pointer
            SharedPreferences prefs = getSharedPreferences("message",MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putBoolean("say_hello",true")
editor.commit();
    ...}

fragment 化

@Override
    public void onResume(){
        super.onResume();
        SharedPreferences prefs =
            getActivity().getSharedPreferences("message", Context.MODE_PRIVATE);
        {
            //this block is used for offsreen fragment, it will get update, when it go to forescreen
            boolean sayHello = prefs.getBoolean("say_hello", false);
            if(sayHello){
                locationTextView =
                    (TextView) myView.findViewById(R.id.mainTextView);//NullPointerException here
                locationTextView.setVisibility(View.VISIBLE);
                locationTextView.setText("Hello");
            }else{
                // say something elese
            }
        }
        {
            //this listener is for forescreen fragment, as soon as shared preferences will be updated,
            // listerner willbe called  and you can update your view depending on changed parameters
            prefs.registerOnSharedPreferenceChangeListener(
                new OnSharedPreferenceChangeListener(){

                    @Override
                    public void onSharedPreferenceChanged(
                        SharedPreferences sharedPreferences, String key
                    ){
                        if(key.equals("say_hello")){
                            boolean sayHello = sharedPreferences.getBoolean("say_hello", false);
                            if(sayHello){
                                locationTextView =
                                    (TextView) myView.findViewById(R.id.mainTextView);//NullPointerException here
                                locationTextView.setVisibility(View.VISIBLE);
                                locationTextView.setText("Hello");
                            }else{
                                // say something elese

                            }
                        }
                    }
                }
            );
        }
    }

您也可以使用 Otto bus activity 与 fragment 的通信仍然是不合适的,因为 fragment 可以处于 !isResumed 状态,但它对 fragment -activity 通信很有用。
如果您需要分别对每个 fragment 和 Activity 进行一些复杂的状态跟踪,我建议使用 sqlDatabase and CursorLoaders .它将使您能够很好地控制状态和即时通信。

编辑:
这并不是说您不能使用 getter 将 View 从 fragment 传递到 Activity 。
问题 - 你不能保证你完全了解 fragment 和 View 的状态。您尝试在 Activity 的 onStart 上更新 View ,这是较早调用的,然后是 fragmentsonStart,因为 fragment 必须由适配器生成并经过附加过程. (要查找 fragment 是否附加到 Activity ,您必须在 Activity 中设置监听器并在 fragment 的 onActivityAttached` 上调用它。请参阅带有 fragment 模板的 android studio Activity )。因此,当您调用更改 View 时, fragment 和 View 可能不存在。
此外,您应该阅读有关 fragment 和 Activity 生命周期的信息并阅读有关上下文的信息(尤其是为什么不相关的上下文持有者中的强引用 View 会导致严重的内存泄漏和 lificle 错误

关于java - 从 MainActivity 修改 Fragment 的 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32897430/

相关文章:

java - 注释如何防止数组参数的突变?

java - Java 中的 AWS DynamoDbMapper FilterExpression 分页

java - 当我将 Retrofit2.0 与 POST 一起使用时, body 为 null ,但响应代码为 5xx?

android - 模拟 Google Analytics v4

Android Fragments - 多个 Activity 还是一个?

java - 问题 - 即使在成功处理后,Weblogic JMS 持久消息仍重新传递到 MDB

java - 无法启动 Activity ,行读取器中的 ArrayIndexOutOfBounds

java - ListView 中滚动时使用的重用项目?

java - 在 scrollview 和 viewpager 之间触摸

android - 如何从 DialogFragment 获取数据到 Fragment?