【问题标题】:getActivity in Fragment is null after change of orientation (single and one pane layout)改变方向后片段中的getActivity为空(单窗格布局)
【发布时间】:2015-07-10 09:56:01
【问题描述】:

我有一个问题,我找到的解决方案对我不起作用(检查 null 等)。

我有一个简单的活动,它在横向模式下托管 2 个片段,在纵向模式下托管 1 个框架布局。当我更改设备的方向然后将其更改回来时,单击处理程序不起作用(DetailFragment 中的 getActivity() 为空)。

到目前为止,这是我的代码:

//UserListActivity.java
public class UserListActivity extends AppCompatActivity implements UserListFragment.OnUserListSelectedListener {

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

        // Check whether the activity is using the layout version with
        // the fragment_container FrameLayout. If so, we must add the first fragment
        if (findViewById(R.id.fragment_container) != null) {

            // However, if we're being restored from a previous state,
            // then we don't need to do anything and should return or else
            // we could end up with overlapping fragments.
            if (savedInstanceState != null) {
                return;
            }

            UserListFragment fragment = new UserListFragment();

            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.add(R.id.fragment_container, fragment, "");
            fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            fragmentTransaction.commit();
        }
    }   

    @Override
    public void onUserListSelected(User selectedUser) {
        UserDetailFragment userDetailFragment = (UserDetailFragment) getSupportFragmentManager().findFragmentById(R.id.user_detail_fragment);

        if (userDetailFragment != null) {
            // If detail frag is available, we're in two-pane layout...

            userDetailFragment.updateSelectedView(selectedUser);
        } else {
            // Otherwise, we're in the one-pane layout and must swap frags...

            //create detailFragment
            UserDetailFragment newFragment = new UserDetailFragment();
            Bundle args = new Bundle();
            args.putString(UserDetailFragment.ARG_SELECTED_USER, new Gson().toJson(selectedUser));
            newFragment.setArguments(args);

            //replace fragment
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.replace(R.id.fragment_container, newFragment, "");
            fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            fragmentTransaction.addToBackStack(null);
            fragmentTransaction.commit();
        }
    }
}

//UserListFragment.java
public class UserListFragment extends ListFragment implements AdapterView.OnItemClickListener {    

    private OnUserListSelectedListener mCallback;
    private User[] users;   

    public interface OnUserListSelectedListener {
        void onUserListSelected(User selectedUser);
    }

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

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

        if (users == null) {
            getAllUsers();
        } else {
            setAdapter();
        }

        getListView().setOnItemClickListener(this);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnUserListSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnUserListSelectedListener");
        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        mCallback.onUserListSelected(users[position]);
    }

    private void setAdapter() {
        setListAdapter(new UserListAdapter(getActivity(), R.layout.user_list_row, users));
    }

    private void getAllUsers() {
        try {
            //...
            //Async webCall using volley
            //...
            users = tmp.getUsers().toArray(new User[tmp.getUsers().size()]);
            setAdapter();
            //...
    }
}

//UserDetailFragment.java
public class UserDetailFragment extends Fragment {
    final public static String ARG_SELECTED_USER = "selectedUser";
    private User mSelectedUser;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            mSelectedUser = new Gson().fromJson(savedInstanceState.getString(ARG_SELECTED_USER), User.class);
        }

        return inflater.inflate(R.layout.user_detail_fragment, container, false);
    }    

    @Override
    public void onStart() {
        super.onStart();
        Bundle args = getArguments();
        if (args != null) {
            updateSelectedView(new Gson().fromJson(args.getString(ARG_SELECTED_USER), User.class));
        } else {
            updateSelectedView(null);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putString(ARG_SELECTED_USER, new Gson().toJson(mSelectedUser));
    }

    public void updateSelectedView(User selectedUser) {
        //??? WHY IS GETACTIVITY() AFTER CHANGE OF ORIENTATION NULL ???
        if (getActivity() != null) {
            TextView textUserName = (TextView) getActivity().findViewById(R.id.textUserName);
            TextView textUserEmail = (TextView) getActivity().findViewById(R.id.textUserEmail);

            if (selectedUser != null) {
                textUserName.setText(selectedUser.getName());
                textUserEmail.setText(selectedUser.getEmail());
                mSelectedUser = selectedUser;
            } else {
                textUserName.setText(null);
            }
        }
    }
}

【问题讨论】:

  • 你确定吗? getActivity() 为空或getActivity().findViewById(R.id.textUserName) 为空?为什么要触摸当前 Fragment 之外的 UI?

标签: java android android-fragments


【解决方案1】:
UserDetailFragment userDetailFragment = (UserDetailFragment) getSupportFragmentManager().findFragmentById(R.id.user_detail_fragment);

创建一个新的片段实例。

 if (findViewById(R.id.fragment_container) != null) {

            // However, if we're being restored from a previous state, 
            // then we don't need to do anything and should return or else 
            // we could end up with overlapping fragments. 
            if (savedInstanceState != null) {
                return; 
            } 

            UserListFragment fragment = new UserListFragment();

            FragmentManager fragmentManager = getSupportFragmentManager(); 
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 
            fragmentTransaction.add(R.id.fragment_container, fragment, "");
            fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 
            fragmentTransaction.commit(); 
        } 

正在重用片段的旧实例。

因此,在调用 .add 时,使用 getFragmentByTag() 并且不要将标签保持为空字符串(“”)

【讨论】:

  • 好的,我使用了 findFragmentByTag,但是现在当我在两个窗格布局中时,userDetailFragment 始终为空。那么如何检查我现在是否处于两个窗格模式?
  • 让我检查一下,但首先,getActivity() 是否仍然为空?
  • 不,不是。谢谢你!我为detailFragment 设置了一个标签,为listFragment 设置了一个标签。我还在相应片段的两个窗格布局中设置了这些标签。现在,当我切换方向时,出现了一个新错误:java.lang.RuntimeException: Unable to start activity ComponentInfo{packageName/packageName.UserListActivity}: android.view.InflateException: Binary XML file line #12: Error inflating class fragment 这发生在 Activity 中的 onCreate 处
  • 为了确保流畅的流程,您应该将清单 configchanges 标记放在清单中并覆盖活动中的函数或处理回调流程。同时,您能否针对上述错误提出一个新问题或在此处更新代码!
猜你喜欢
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多