java - Android fragment - 按下 fragment 中的文本后出现 "Activity has been destroyed"

标签 java android android-fragments

因此,我一直在尝试在我的应用程序中实现一项功能,当我从 searchBoxResultsFragment(显示搜索框用户结果的 fragment )中单击用户名时,它将转到用户的轮廓。

用户的个人资料将被放置在名为 UserFragment 的新 fragment 中。因此基本上 searchBoxResultsFragment 将被 UserFragment 替换。因此,我在调用函数中使用了 ft.replace() 来为 UserFragment 创建一个新实例,该实例位于 userFragment() 内部MainNavigation Activity 类的函数。

但是,我遇到了错误Activity has been destroy,导致我的应用程序崩溃。

我是 Android 开发新手,正在自学如何开发应用程序。

这些是我的代码:

MainNavigation.java

public class MainNavigation extends AppCompatActivity {

    private BottomNavigationView mBottomNav;

    // fix main layout of navigation
    ImageButton uProfileBtn, searchBox;

    GetSearchBoxResults getSearcResults;

    EditText searchBoxText;

    Fragment frag = null;


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

        // hide action bar
        if(this.getSupportActionBar()!=null) {
            this.getSupportActionBar().hide();
        }

        uProfileBtn = (ImageButton) findViewById(R.id.profileBtn);
        searchBox = (ImageButton) findViewById(R.id.searchFriendBtn);

        mBottomNav = (BottomNavigationView) findViewById(R.id.navigation);
        mBottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                selectFragment(item);
                return true;
            }
        });

        uProfileBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // goes to the Profile Fragment
                profileFragment();
            }
        });

        searchBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // goes to the Search Box Fragment
                searchBoxResultsFragment();
            }
        });
    }

    private void profileFragment() {
        frag = ProfileFragment.newInstance("test1", "test2");
        if (frag != null) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.fragmentContainer, frag, frag.getTag());
            ft.commit();
        }
    }

    private void searchBoxResultsFragment() {
        frag = SearchBoxFragment.newInstance("test1", "test2");
        if (frag != null) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.fragmentContainer, frag, frag.getTag());
            ft.commit();
        }
    }

    // so it can be called from the adapter
    public void userFragment() {
        frag = UserFragment.newInstance("test1", "test2");
        if (frag != null) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.fragmentContainer, frag, frag.getTag());
            ft.commit();
        }
    }

    private void selectFragment(MenuItem item) {
        // init corresponding fragment
        switch (item.getItemId()) {
            case R.id.nav_home_btn:
                frag = HomeFragment.newInstance("test1", "test2");
                break;
            case R.id.nav_message_btn:
                frag = MessagesFragment.newInstance("test1", "test2");
                break;
            case R.id.nav_notif_btn:
                frag = NotificationsFragment.newInstance("test1", "test2");
                break;
            case R.id.nav_settings_btn:
                frag = SettingsFragment.newInstance("test1", "test2");
                break;
        }

        // uncheck the other items
        for (int i = 0; i< mBottomNav.getMenu().size(); i++) {
            MenuItem menuItem = mBottomNav.getMenu().getItem(i);
            menuItem.setChecked(menuItem.getItemId() == item.getItemId());
        }

        // sets the fragment to show
        if (frag != null) {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.fragmentContainer, frag, frag.getTag());
            ft.commit();
        }
    }
}

SearchBoxFragment.java

public class SearchBoxFragment extends Fragment {
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    GetSearchBoxResults getSearcResults;

    Fragment frag;

    EditText searchBox;
    TextView uUsername;

    private OnFragmentInteractionListener mListener;

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

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment SearchBoxFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static SearchBoxFragment newInstance(String param1, String param2) {
        SearchBoxFragment fragment = new SearchBoxFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

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

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState){
        searchBox = (EditText) getActivity().findViewById(R.id.searchTopBar);
        //uUsername = (TextView) getActivity().findViewById(R.id.userUsername);
        getSearcResults = new GetSearchBoxResults(getContext(), getActivity());
        // combines the searched input with the API REST call
        getSearcResults.execute("http://192.168.1.4:8000/api/search/?search=" + searchBox.getText().toString());
    }

    // TODO: Rename method, update argument and hook method into UI event
    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();

        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        mListener = null;
    }

    // so it can be called from the adapter
    /*public void UserFragment() {
        frag = UserFragment.newInstance("test1", "test2");
        if (frag != null) {
            FragmentTransaction ft = frag.getFragmentManager().beginTransaction();
            ft.replace(R.id.fragmentContainer, frag, frag.getTag());
            ft.commit();
        }
    }*/

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}

SearchResultsAdapter.java

public class SearchResultsAdapter extends  RecyclerView.Adapter<SearchResultsAdapter.CustomViewHolder>{
    private List<User> users;

    MainNavigation mainNavHelper;

    public class CustomViewHolder extends RecyclerView.ViewHolder {
        public TextView userFN, userUN;

        public CustomViewHolder(View view) {
            super(view);
            userFN = (TextView) view.findViewById(R.id.userFullName);
            userUN = (TextView) view.findViewById(R.id.userUsername);

            // when userUN is clicked, then go to their profile
            userUN.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    userUN.setText("this text was clicked");

                    mainNavHelper = new MainNavigation();
                    mainNavHelper.userFragment();
                }
            });
        }
    }

    public SearchResultsAdapter(List<User> users){
        this.users = users;
    }

    @Override
    public SearchResultsAdapter.CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.users_list, parent, false);

        return new SearchResultsAdapter.CustomViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(SearchResultsAdapter.CustomViewHolder holder, int position) {
        User user = users.get(position);
        String uFN = user.getFirstName() + " " + user.getLastName();
        holder.userFN.setText(uFN);
        holder.userUN.setText(user.getUsername());
    }

    @Override
    public int getItemCount() {
        return users.size();
    }
}

UserFragment.java

public class UserFragment extends Fragment {
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    private OnFragmentInteractionListener mListener;

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

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment UserFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static UserFragment newInstance(String param1, String param2) {
        UserFragment fragment = new UserFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

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

    // TODO: Rename method, update argument and hook method into UI event
    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();

        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        mListener = null;
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        void onFragmentInteraction(Uri uri);
    }
}

这是我针对该问题的 logcat。

03-17 20:51:57.409 8879-8879/com.example.darkestmidnight.lykeyfoods E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.darkestmidnight.lykeyfoods, PID: 8879
    java.lang.IllegalStateException: Activity has been destroyed
        at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2114)
        at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:683)
        at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:637)
        at com.example.darkestmidnight.lykeyfoods.activities.main_navigation.MainNavigation.UserFragment(MainNavigation.java:101)
        at com.example.darkestmidnight.lykeyfoods.activities.main_navigation.adapters.SearchResultsAdapter$CustomViewHolder$1.onClick(SearchResultsAdapter.java:35)
        at android.view.View.performClick(View.java:6294)
        at android.view.View$PerformClick.run(View.java:24770)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

我将非常感谢任何帮助!

最佳答案

您做错的是您在这一行以编程方式创建 Activity 的新实例

mainNavHelper = new MainNavigation();

解决此问题的方法是将 MainNavigation 实例传递给适配器并使用它

public class SearchResultsAdapter extends  RecyclerView.Adapter<SearchResultsAdapter.CustomViewHolder>{
    private List<User> users;

    Context context;

    public class CustomViewHolder extends RecyclerView.ViewHolder {
        public TextView userFN, userUN;

        public CustomViewHolder(View view) {
            super(view);
            userFN = (TextView) view.findViewById(R.id.userFullName);
            userUN = (TextView) view.findViewById(R.id.userUsername);

            // when userUN is clicked, then go to their profile
            userUN.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    userUN.setText("this text was clicked");
                    if (context instanceOf MainNavigation) {
                        ((MainNavigation) context).userFragment();
                    }
                }
            });
        }
    }

    public SearchResultsAdapter(Context context, List<User> users){
        this.context = context;        
        this.users = users;
    }

    @Override
    public SearchResultsAdapter.CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.users_list, parent, false);

        return new SearchResultsAdapter.CustomViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(SearchResultsAdapter.CustomViewHolder holder, int position) {
        User user = users.get(position);
        String uFN = user.getFirstName() + " " + user.getLastName();
        holder.userFN.setText(uFN);
        holder.userUN.setText(user.getUsername());
    }

    @Override
    public int getItemCount() {
        return users.size();
    }
}

关于java - Android fragment - 按下 fragment 中的文本后出现 "Activity has been destroyed",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55214154/

相关文章:

java - 查找一个列表的对象是否存在于另一个列表中

JavaFX : How to fill a ComboBox with changing values and refrech it

android - gradle库中混淆的接口(interface)参数名称

android - 在包含 fragment 的主 Activity 中拉动刷新

java - 使用Gson将Json转换为Java Object

java - 在 Eclipse 中使用一个项目到另一个项目时出现 ClassNotFound

Android - 未调用 onNewIntent - 单顶 Activity

java - 文本出现在启动屏幕后

java - 单击按钮滑动到下一个 fragment

java - Android:语言更改后刷新当前 fragment