因此,我一直在尝试在我的应用程序中实现一项功能,当我从searchBoxResultsFragment
单击用户名时,该用户名是一个片段,显示搜索框的用户结果,它将转到用户的个人资料。
用户的个人资料将放置在名为UserFragment
的新片段中。因此,基本上searchBoxResultsFragment
将由UserFragment
代替。因此,我在调用函数中使用ft.replace()
来为UserFragment
创建新实例,该实例位于userFragment()
活动类的MainNavigation
函数内部。
但是,我遇到的错误Activity has been destroyed
使我的应用程序崩溃。
我是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);
}
}
这是我对此问题的看法。
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();
}
}