我正在尝试使用 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 ,这是较早调用的,然后是 fragments
onStart,因为 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/