簡體   English   中英

單個活動有3個碎片崩潰

[英]Single Activity With 3 Fragments Crashing

我創建了一個身份驗證活動,該活動具有一個FrameLayout作為容器,在其中替換用戶想要使用的相應片段。

容器中的第一個片段是WelcomeFragment ,它只是一個ConstraintLayout ,具有背景,用於徽標的ImageView和兩個按鈕以移至LoginFragmentSignUpFragment

問題是,當我從WelcomeFragmentLoginFragment去,回來的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM