[英]Single Activity With 3 Fragments Crashing
我创建了一个身份验证活动,该活动具有一个FrameLayout作为容器,在其中替换用户想要使用的相应片段。
容器中的第一个片段是WelcomeFragment ,它只是一个ConstraintLayout ,具有背景,用于徽标的ImageView和两个按钮以移至LoginFragment或SignUpFragment 。
问题是,当我从WelcomeFragment到LoginFragment去,回来的WelcomeFragment,转到SignUpFragment,并再次尝试翻盘的WelcomeFragment,应用程序崩溃,并且给了我以下错误:
错误的堆栈跟踪:
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:
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:
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:
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)
如您所见,replace()方法删除了所有先前的片段,因此不必在函数replaceFragmentInActivity()
使用popBackStackImmediate
方法。
我建议使用findFragmentByTag(String tag)
查找给定的片段是否存在,并跳过事务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.