[英]Single Activity With 3 Fragments Crashing
I have created an Authentication Activity, which has a FrameLayout as a container in which I replace the corresponding fragments the user wants to use. 我创建了一个身份验证活动,该活动具有一个FrameLayout作为容器,在其中替换用户想要使用的相应片段。
The first fragment in the container is the WelcomeFragment , which is just a ConstraintLayout with a background, an ImageView for the Logo and two buttons to move to the LoginFragment or SignUpFragment . 容器中的第一个片段是WelcomeFragment ,它只是一个ConstraintLayout ,具有背景,用于徽标的ImageView和两个按钮以移至LoginFragment或SignUpFragment 。
The issue is that, when I go from the WelcomeFragment to the LoginFragment , come back to the WelcomeFragment , go to the SignUpFragment , and try to comeback again to the WelcomeFragment , the App crashes, and gives me the following error: 问题是,当我从WelcomeFragment到LoginFragment去,回来的WelcomeFragment,转到SignUpFragment,并再次尝试翻盘的WelcomeFragment,应用程序崩溃,并且给了我以下错误:
Stack Trace of Error: 错误的堆栈跟踪:
12-31 18:44:45.558 4367-4367/com.nopeia.fitassistant E/MessageQueue-JNI: android.view.InflateException: Binary XML file line #0: Binary XML file line #0: Error inflating class
<unknown>
at android.view.LayoutInflater.inflate(LayoutInflater.java:539) at android.view.LayoutInflater.inflate(LayoutInflater.java:423) at com.nopeia.fitassistant.ui.authentication.welcome.WelcomeFragment.onCreateView(WelcomeFragment.java:50) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2354)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1419) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809)
at android.support.v4.app.BackStackRecord.executePopOps(BackStackRecord.java:857) at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2577) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322) at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:851) at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:794)
at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity.java:174) at android.app.Activity.onKeyUp(Activity.java:2482) at android.view.KeyEvent.dispatch(KeyEvent.java:2665) at android.app.Activity.dispatchKeyEvent(Activity.java:2735)
at android.support.v7.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:534) at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:58) at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:316)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2352) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4206) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4168)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3709)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3828)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3709) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3885) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3709) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3861) at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:4022) at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2257)
at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1878) at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1869) at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2234)
at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:1 12-31 18:44:45.559 4367-4367/com.nopeia.fitassistant E/AndroidRuntime: FATAL EXCEPTION: main Process: com.nopeia.fitassistant, PID: 4367 android.view.InflateException:
Binary XML file line #0: Binary XML file line #0: Error inflating class
<unknown>
at android.view.LayoutInflater.inflate(LayoutInflater.java:539) at android.view.LayoutInflater.inflate(LayoutInflater.java:423) at com.nopeia.fitassistant.ui.authentication.welcome.WelcomeFragment.onCreateView(WelcomeFragment.java:50) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2354)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1419) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809)
at android.support.v4.app.BackStackRecord.executePopOps(BackStackRecord.java:857) at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2577) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322) at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:851) at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:794)
at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity.java:174) at android.app.Activity.onKeyUp(Activity.java:2482) at android.view.KeyEvent.dispatch(KeyEvent.java:2665) at android.app.Activity.dispatchKeyEvent(Activity.java:2735)
at android.support.v7.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:534) at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:58) at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:316)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2352) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4206) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4168)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3709)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3828)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3709) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3885) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3709) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3682) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3735)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3701) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3861) at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:4022) at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2257)
at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1878) at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1869) at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2234)
at android.view.Inp
AuthenticationActivity.class : AuthenticationActivity.class:
package com.nopeia.fitassistant.ui.authentication;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.nopeia.fitassistant.R;
import com.nopeia.fitassistant.ui.authentication.login.LoginContract;
import com.nopeia.fitassistant.ui.authentication.login.LoginFragment;
import com.nopeia.fitassistant.ui.authentication.signup.SignUpContract;
import com.nopeia.fitassistant.ui.authentication.signup.SignUpFragment;
import com.nopeia.fitassistant.ui.authentication.welcome.WelcomeContract;
import com.nopeia.fitassistant.ui.authentication.welcome.WelcomeFragment;
import com.nopeia.fitassistant.ui.myzone.MyZoneActivity;
import com.nopeia.fitassistant.util.ActivityUtils;
import javax.inject.Inject;
import dagger.android.support.DaggerAppCompatActivity;
public class AuthenticationActivity extends DaggerAppCompatActivity
implements WelcomeContract.onWelcomeLoginClickListener,
WelcomeContract.onWelcomeSignUpClickListener,
LoginContract.View.onLoginButtonClickListener,
LoginContract.View.onSignupClickListener,
SignUpContract.View.onLoginClickListener,
SignUpContract.View.onSignupButtonClickListener, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = AuthenticationActivity.class.getSimpleName();
@Inject
WelcomeFragment mWelcomeFragmentProvider;
@Inject
LoginFragment mLoginFragmentProvider;
@Inject
SignUpFragment mSignUpFragmentProvider;
private GoogleApiClient mGoogleApiClient;
// Firebase
@Inject
FirebaseAuth mFirebaseAuth;
FirebaseUser mFirebaseUser;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
WelcomeFragment welcomeFragment = (WelcomeFragment) getSupportFragmentManager()
.findFragmentById(R.id.authenticationActivity_fragment);
if(welcomeFragment == null){
welcomeFragment = mWelcomeFragmentProvider;
Log.d("AuthActivity", mWelcomeFragmentProvider.toString());
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
welcomeFragment, R.id.authenticationActivity_fragment);
}
GoogleSignInOptions googleSignInOptions = new GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, googleSignInOptions)
.build();
// Load previously saved state, if available.
if (savedInstanceState != null) {
// TasksFilterType currentFiltering =
// (TasksFilterType) savedInstanceState.getSerializable(CURRENT_FILTERING_KEY);
// mTasksPresenter.setFiltering(currentFiltering);
}
}
@Override
public void onWelcomeSignUpButtonClicked() {
SignUpFragment signUpFragment = mSignUpFragmentProvider;
ActivityUtils.replaceFragmentInActivity(getSupportFragmentManager(),
signUpFragment, R.id.authenticationActivity_fragment);
}
@Override
public void onWelcomeLoginButtonClicked() {
LoginFragment loginFragment = mLoginFragmentProvider;
ActivityUtils.replaceFragmentInActivity(getSupportFragmentManager(),
loginFragment, R.id.authenticationActivity_fragment);
}
@Override
public void onLoginButtonClicked() {
}
@Override
public void onSignupTextViewClicked() {
onWelcomeSignUpButtonClicked();
}
@Override
public void onSignupButtonClicked() {
}
@Override
public void onLoginTextViewClicked() {
onWelcomeLoginButtonClicked();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed:" + connectionResult);
}
public GoogleApiClient getmGoogleApiClient() {
return mGoogleApiClient;
}
public void setmGoogleApiClient(GoogleApiClient mGoogleApiClient) {
this.mGoogleApiClient = mGoogleApiClient;
}
@Override
protected void onStart() {
super.onStart();
// Check if user is signed in.
mFirebaseAuth = FirebaseAuth.getInstance();
mFirebaseUser = mFirebaseAuth.getCurrentUser();
if (mFirebaseUser != null) {
//Not signed in launch the Sign In activity
startActivity(new Intent(this, MyZoneActivity.class));
finish();
}
}
}
WelcomeFragment.java : WelcomeFragment.java:
package com.nopeia.fitassistant.ui.authentication.welcome;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.nopeia.fitassistant.R;
import com.nopeia.fitassistant.ui.authentication.login.LoginContract;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import dagger.android.support.DaggerFragment;
public class WelcomeFragment extends DaggerFragment {
@BindView(R.id.welcome_activity_login_ButtonView)
Button mLoginButtonView;
@BindView(R.id.welcome_activity_signup_ButtonView)
Button mSignUpButtonView;
private WelcomeContract.onWelcomeSignUpClickListener mSignupCallback;
private WelcomeContract.onWelcomeLoginClickListener mLoginCallback;
@Inject
public WelcomeFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_welcome, container, false);
ButterKnife.bind(this, rootView);
mLoginButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mLoginCallback.onWelcomeLoginButtonClicked();
}
});
mSignUpButtonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mSignupCallback.onWelcomeSignUpButtonClicked();
}
});
return rootView;
}
@Override
public void onAttach(Context context) {
try {
mSignupCallback = (WelcomeContract.onWelcomeSignUpClickListener) context;
} catch (ClassCastException e){
throw new ClassCastException(context.toString()
+ " must implement onSignupButtonClickListener"
);
}
// Get login callback activity
try {
mLoginCallback = (WelcomeContract.onWelcomeLoginClickListener) context;
} catch (ClassCastException e){
throw new ClassCastException(context.toString()
+ " must implement onLoginClickListener"
);
}
super.onAttach(context);
}
@Override
public void onDetach() {
mSignupCallback = null;
mLoginCallback = null;
super.onDetach();
}
}
ActivityUtil.java: ActivityUtil.java:
package com.nopeia.fitassistant.util;
import android.annotation.SuppressLint;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import com.nopeia.fitassistant.R;
import static android.support.v4.util.Preconditions.checkNotNull;
/**
* Created by Pujolsluis on 12/7/2017.
*/
public class ActivityUtils {
@SuppressLint("RestrictedApi")
public static void addFragmentToActivity (@NonNull FragmentManager fragmentManager,
@NonNull Fragment fragment, int frameId) {
checkNotNull(fragmentManager);
checkNotNull(fragment);
String backStateName = fragment.getClass().getName();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(frameId, fragment, backStateName);
transaction.commit();
}
public static void replaceFragmentInActivity(@NonNull FragmentManager fragmentManager,
@NonNull Fragment fragment, int frameId){
//Avoid Fragments stacking up in the backstack if they already exist in it
String backStateName = fragment.getClass().getName();
boolean fragmentPopped = fragmentManager.popBackStackImmediate (backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction transaction = fragmentManager.beginTransaction();
// Replace fragment, with fade in and fadeout animation
// and add transaction to backstack to allow the user to undo
// the action he just did and recover the last fragment state
transaction.setCustomAnimations(
android.R.anim.slide_in_left,
android.R.anim.slide_out_right,
android.R.anim.slide_in_left,
android.R.anim.slide_out_right
);
transaction.replace(frameId, fragment);
transaction.addToBackStack(backStateName);
transaction.commit();
}
}
}
/**
* Replace an existing fragment that was added to a container. This is
* essentially the same as calling {@link #remove(Fragment)} for all
* currently added fragments that were added with the same containerViewId
* and then {@link #add(int, Fragment, String)} with the same arguments
* given here.
**/
public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment,
String tag)
As you can see the replace() method removes all previous fragments, its unnecessary to use popBackStackImmediate
method in your function replaceFragmentInActivity()
如您所见,replace()方法删除了所有先前的片段,因此不必在函数
replaceFragmentInActivity()
使用popBackStackImmediate
方法。
I would recommend using findFragmentByTag(String tag)
to find if the the given fragment is present and skip the transaction. 我建议使用
findFragmentByTag(String tag)
查找给定的片段是否存在,并跳过事务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.