为什么我在某些语句中的 onBackPressed 上获得空对象引用 (NullPointerException) 而在其他语句中却没有? (导航抽屉 - Android)
Why do I get a null object reference (NullPointerException) on onBackPressed in some statements and not in anothers? (Navigation Drawer - Android)
我正在管理导航抽屉中的片段 activity 并且我正在处理 onBackPressed 方法以获得逻辑 "back press" 按钮。该方法的代码是这样的:
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else if(getSupportFragmentManager().findFragmentByTag("Aprender").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Practicar").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Campo").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Examinar").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Materias").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Utilidades").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Info").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else {
moveTaskToBack(true);
}
}
这应该是有道理的,因为我有另一种方法可以在替换片段时存储标签:
private void displaySelectedScreen(int itemId) {
//creating fragment object
Fragment fragment = null;
//initializing the fragment object which is selected
switch (itemId) {
case R.id.nav_inicio:
fragment = new Inicio();
break;
case R.id.nav_aprender:
fragment = new Aprender();
break;
case R.id.nav_practicar:
fragment = new Practicar();
break;
case R.id.nav_examinar:
fragment = new Examinar();
break;
case R.id.nav_materias:
fragment = new Materias();
break;
case R.id.nav_utilidades:
fragment = new Utilidades();
break;
case R.id.nav_info:
fragment = new Info();
break;
}
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment, fragment.getClass().getCanonicalName().substring(44));
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
写成 fragment.getClass().getCanonicalName().substring(44) 的原因只是因为它是设置等于 class 名称的标签的方式(例如: "Aprender"),它是 44,因为它是我之前在包名称 (com.myname.myapp.) 中的字符数,事实上它适用于 "Aprender" 片段,因为我会解释:
当我 运行 应用程序时,问题就来了。如果我从我的主片段 (Inicio) 进入 "Aprender" 片段,然后按后退按钮,它完全没有问题,所以它会转到主片段 (Inicio)。但出于某种原因我无法理解,它不能与其他案例(Practicar、Examinar 等)一起正常工作。我 运行 激活了 logcat,这是错误:
E/InputEventSender: Exception dispatching finished signal.
E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
E/MessageQueue-JNI: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v4.app.Fragment.isVisible()' on a null object reference
我真的很感谢对此的任何澄清以及解决这种情况的适当解决方案。如有需要,请告诉我任何问题。
将您的每个 if 条件替换为以下内容。
Fragment fragment = getSupportFragmentManager().findFragmentByTag("Aprender");
if(fragment != null){
fragment.isVisible();
do your stuff
}
当您查找的片段已从内存中删除时,您得到的是空指针,因此每次使用 findFragmentByTag 方法搜索片段时都进行空指针检查
我正在管理导航抽屉中的片段 activity 并且我正在处理 onBackPressed 方法以获得逻辑 "back press" 按钮。该方法的代码是这样的:
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else if(getSupportFragmentManager().findFragmentByTag("Aprender").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Practicar").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Campo").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Examinar").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Materias").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Utilidades").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else if(getSupportFragmentManager().findFragmentByTag("Info").isVisible()){
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Inicio()).commit();
}
else {
moveTaskToBack(true);
}
}
这应该是有道理的,因为我有另一种方法可以在替换片段时存储标签:
private void displaySelectedScreen(int itemId) {
//creating fragment object
Fragment fragment = null;
//initializing the fragment object which is selected
switch (itemId) {
case R.id.nav_inicio:
fragment = new Inicio();
break;
case R.id.nav_aprender:
fragment = new Aprender();
break;
case R.id.nav_practicar:
fragment = new Practicar();
break;
case R.id.nav_examinar:
fragment = new Examinar();
break;
case R.id.nav_materias:
fragment = new Materias();
break;
case R.id.nav_utilidades:
fragment = new Utilidades();
break;
case R.id.nav_info:
fragment = new Info();
break;
}
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment, fragment.getClass().getCanonicalName().substring(44));
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
写成 fragment.getClass().getCanonicalName().substring(44) 的原因只是因为它是设置等于 class 名称的标签的方式(例如: "Aprender"),它是 44,因为它是我之前在包名称 (com.myname.myapp.) 中的字符数,事实上它适用于 "Aprender" 片段,因为我会解释:
当我 运行 应用程序时,问题就来了。如果我从我的主片段 (Inicio) 进入 "Aprender" 片段,然后按后退按钮,它完全没有问题,所以它会转到主片段 (Inicio)。但出于某种原因我无法理解,它不能与其他案例(Practicar、Examinar 等)一起正常工作。我 运行 激活了 logcat,这是错误:
E/InputEventSender: Exception dispatching finished signal.
E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
E/MessageQueue-JNI: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v4.app.Fragment.isVisible()' on a null object reference
我真的很感谢对此的任何澄清以及解决这种情况的适当解决方案。如有需要,请告诉我任何问题。
将您的每个 if 条件替换为以下内容。
Fragment fragment = getSupportFragmentManager().findFragmentByTag("Aprender");
if(fragment != null){
fragment.isVisible();
do your stuff
}
当您查找的片段已从内存中删除时,您得到的是空指针,因此每次使用 findFragmentByTag 方法搜索片段时都进行空指针检查