Как закрыть Unity, не закрывая все приложение при изменении фрагментов в Android Studio?

#java #android #unity3d #android-fragments

#java #Android #unity3d #android-фрагменты

Вопрос:

У меня есть приложение, в котором пользователь может просматривать разные фрагменты, используя BottomNavigationView, и один из этих фрагментов — приложение Unity3D. Итак, когда я открываю фрагмент Unity, он работает, но когда я открываю другой фрагмент и открываю фрагмент Unity, он вылетает, как мне это исправить, вот мой код.

MainActivity.java

 public class MainActivity extends AppCompatActivity {

BottomNavigationView mBottomNavigationView;
NavController mNavController;
NavDestination mDestination;
AppBarConfiguration appBarConfiguration;
String tab;
private boolean doubleBackToExitPressedOnce ;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    boolean b = this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    this.setContentView(R.layout.activity_main);

    ActionBar mActionBar = getSupportActionBar();
    mActionBar.setDisplayShowHomeEnabled(false);
    mActionBar.setDisplayShowTitleEnabled(false);
    LayoutInflater li = LayoutInflater.from(this);
    View customView = li.inflate(R.layout.top_menu_custom, null);
    mActionBar.setCustomView(customView);
    mActionBar.setDisplayShowCustomEnabled(true);


    mBottomNavigationView = (BottomNavigationView) findViewById(R.id.nav_view);

    ImageButton profileButton = (ImageButton) customView.findViewById(R.id.profile_button);
    ImageButton notificationButton = (ImageButton) customView.findViewById(R.id.noti_button);

    profileButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            ProfileFragment profileFragment = new ProfileFragment();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.nav_host_fragment,profileFragment)
                    .addToBackStack(tab)
                    .setReorderingAllowed(true)
                    .commit();
            mBottomNavigationView.setVisibility(View.GONE);
        }
    });

    notificationButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            NotificationFragment notificationFragment = new NotificationFragment();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.nav_host_fragment,notificationFragment)
                    .addToBackStack(tab)
                    .setReorderingAllowed(true)
                    .commit();
            mBottomNavigationView.setVisibility(View.GONE);
        }
    });

    mBottomNavigationView.setItemIconTintList(null);
    mBottomNavigationView.setItemTextColor(ColorStateList.valueOf(getColor(R.color.black)));

    mNavController = Navigation.findNavController(this, R.id.nav_host_fragment);

    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top level destinations.
    appBarConfiguration = new AppBarConfiguration.Builder(
            R.id.navigation_home, R.id.navigation_dashboard,R.id.navigation_map, R.id.navigation_card,R.id.navigation_deals)
            .build();

    NavigationUI.setupActionBarWithNavController(this, mNavController, appBarConfiguration);
    NavigationUI.setupWithNavController(mBottomNavigationView, mNavController);
    mNavController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {

        @Override
        public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
            Toast.makeText(getApplicationContext(),"hi",Toast.LENGTH_SHORT).show();
            mDestination = mNavController.getCurrentDestination();
            tab = mDestination.toString();
        }
    });


}

@Override
public void onBackPressed() {
    //Toast.makeText(getApplicationContext(), mDestination.toString(),Toast.LENGTH_SHORT).show();


    if (doubleBackToExitPressedOnce) {
        getSupportFragmentManager().popBackStackImmediate();
        mNavController.navigate(mDestination.getId());
        mBottomNavigationView.setVisibility(View.VISIBLE);
        super.onBackPressed();
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;
        }
    }, 2000);
}
 

UnityMapFragment

 public class MapFragment extends Fragment{

protected UnityPlayer mUnityPlayer;
FrameLayout frameLayoutForUnity;

public MapFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    mUnityPlayer = new UnityPlayer(getActivity());
    View view = inflater.inflate(R.layout.fragment_map, container, false);
    this.frameLayoutForUnity = (FrameLayout) view.findViewById(R.id.frameLayoutForUnity);
    this.frameLayoutForUnity.addView(mUnityPlayer.getView(),
            FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);

    mUnityPlayer.requestFocus();
    mUnityPlayer.windowFocusChanged(true);
    return view;
}

@Override
public void onPause() {
    super.onPause();
    mUnityPlayer.pause();
}

@Override
public void onResume() {
    super.onResume();
    mUnityPlayer.resume();
}

// Quit Unity
@Override
public void onDestroy ()
{
    mUnityPlayer.quit();
    super.onDestroy();
}
 

Комментарии:

1. it crashes how do i fix this не могли бы вы опубликовать свой stacktrace

Ответ №1:

Итак, мне удалось найти решение этой проблемы, не знаю, хорошо ли это делать таким образом или нет, но то, что я сделал, это создал экземпляр UnityPlayer в моей MainActivity, и в моем фрагменте я вызываю UnityPlayer, который был установлен в моей основной деятельности.

MainActivity.java

 public class MainActivity extends AppCompatActivity {

public BottomNavigationView mBottomNavigationView;
public NavController mNavController;
public NavDestination mDestination;
AppBarConfiguration appBarConfiguration;
String tab;
int onBackTimes = 0;

public UnityPlayer mUnityPlayer; <----Call unity player

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    mUnityPlayer = new UnityPlayer(this); <----UNITY PLAYER HERE

    boolean b = this.requestWindowFeature(Window.FEATURE_NO_TITLE);

    this.setContentView(R.layout.activity_main);

    ActionBar mActionBar = getSupportActionBar();
    mActionBar.setDisplayShowHomeEnabled(false);
    mActionBar.setDisplayShowTitleEnabled(false);
    LayoutInflater li = LayoutInflater.from(this);
    View customView = li.inflate(R.layout.top_menu_custom, null);
    mActionBar.setCustomView(customView);
    mActionBar.setDisplayShowCustomEnabled(true);


    mBottomNavigationView = (BottomNavigationView) findViewById(R.id.nav_view);

    ImageButton profileButton = (ImageButton) customView.findViewById(R.id.profile_button);
    ImageButton notificationButton = (ImageButton) customView.findViewById(R.id.noti_button);

    profileButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            ProfileFragment profileFragment = new ProfileFragment();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.nav_host_fragment,profileFragment)
                    .addToBackStack(tab)
                    .setReorderingAllowed(true)
                    .commit();
            mBottomNavigationView.setVisibility(View.GONE);
        }
    });

    notificationButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            NotificationFragment notificationFragment = new NotificationFragment();
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.nav_host_fragment,notificationFragment)
                    .addToBackStack(tab)
                    .setReorderingAllowed(true)
                    .commit();
            mBottomNavigationView.setVisibility(View.GONE);
        }
    });

    mBottomNavigationView.setItemIconTintList(null);
    mBottomNavigationView.setItemTextColor(ColorStateList.valueOf(getColor(R.color.black)));

    mNavController = Navigation.findNavController(this, R.id.nav_host_fragment);

    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top level destinations.
    appBarConfiguration = new AppBarConfiguration.Builder(
            R.id.navigation_home, R.id.navigation_dashboard,R.id.navigation_map, R.id.navigation_card,R.id.navigation_deals)
            .build();

    NavigationUI.setupActionBarWithNavController(this, mNavController, appBarConfiguration);
    NavigationUI.setupWithNavController(mBottomNavigationView, mNavController);
    mNavController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {

        @Override
        public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
            mDestination = mNavController.getCurrentDestination();
            tab = mDestination.toString();
        }
    });


}

@Override
public void onBackPressed() {

    Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

    onBackTimes  =1;

    if(onBackTimes>1){
        LoginActivity.close.finish();
        finish();

    }
    else{
        getSupportFragmentManager().popBackStackImmediate();
        mBottomNavigationView.setVisibility(View.VISIBLE);
        super.onBackPressed();
        mNavController.navigate(mDestination.getId());
    }

    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            onBackTimes=0;
        }
    }, 2000);

}

@Override
protected void onStop() {
    super.onStop();
}


//UNITY STUFF OVER HERE

@Override
protected void onPause() {
    super.onPause();
    mUnityPlayer.pause();
}

@Override protected void onResume()
{
    super.onResume();
    mUnityPlayer.resume();
}

@Override
protected void onDestroy(){
    super.onDestroy();
}

}
 

UnityMapFragment

 public class MapFragment extends Fragment{

private MainActivity mUnityMainActivity;
private UnityPlayer mUnityPlayer;

public MapFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    //this code calls the UNITYPLAYER from MainActivity and return it here
    mUnityMainActivity = (MainActivity) getActivity();
    View unityPlayViewer = mUnityMainActivity.mUnityPlayer.getView();
    mUnityMainActivity.mUnityPlayer.requestFocus();
    mUnityMainActivity.mUnityPlayer.windowFocusChanged(true);

    return unityPlayViewer;
}

/** FOR UNITY **/
@Override
public void onPause() {
    super.onPause();
    mUnityMainActivity.mUnityPlayer.pause();
}

// Resume Unity
@Override public void onResume()
{
    super.onResume();
    mUnityMainActivity.mUnityPlayer.resume();
}
 

Я не знаю, почему я должен включать onPause, onResume и т. Д. В оба файла, Но если у одного из них его нет, это приведет к сбою.

Ответ №2:

Проблема в том, что каждый раз, когда мы переключаемся на фрагмент unity, создается новый UnityPlayer, и это приводит к сбою приложения. Итак, нам нужно создать UnityPlayer только в первый раз или только тогда, когда проигрыватель был остановлен. Это работает на моей стороне.

В классе UnityFragment мои глобальные переменные :

 protected UnityPlayer mUnityPlayer;
private View view;
private FrameLayout frameLayoutForUnity;
 

В onCreate новом UnityPlayer создается, который вызывается только в первый раз :

 @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mUnityPlayer = new UnityPlayer(getActivity()); // create Unity Player
}
 

В onCreateView мы обновляем представление для UnityPlayer :

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    if(mUnityPlayer.getParent() != null){
        ((ViewGroup)mUnityPlayer.getParent()).removeAllViews();
    }
    view = inflater.inflate(R.layout.fragment_unity, container, false);
    this.frameLayoutForUnity = (FrameLayout) view.findViewById(R.id.unityFragmentLayout);
    this.frameLayoutForUnity.addView(mUnityPlayer.getView(),
            FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);

    mUnityPlayer.requestFocus();
    mUnityPlayer.windowFocusChanged(true);
    return view;
}
 

Остальное остается прежним. Могут быть лучшие решения, чем это. Приветствия 🙂