【问题标题】:Android GroupActivity Backpress trigger Fatal Exception / NullPointerExceptionAndroid GroupActivity Backpress 触发 Fatal Exception / NullPointerException
【发布时间】:2013-06-19 16:01:13
【问题描述】:

TabHost 下使用ActivityGroup 时,我在BackPressed 上遇到了一些问题。 为了说明,首先将代码分层钻取如下:

TabGroupActivity 类

以下TabGroupActivity.java引用自在线教程。

public class TabGroupActivity extends ActivityGroup 
{    
    private ArrayList<String> mIdList;

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);       
        if (mIdList == null) mIdList = new ArrayList<String>();
    }

    /**
     * This is called when a child activity of this one calls its finish method. 
     * This implementation calls {@link LocalActivityManager#destroyActivity} on the child activity
     * and starts the previous activity.
     * If the last child activity just called finish(),this activity (the parent),
     * calls finish to finish the entire group.
     */
  @Override
  public void finishFromChild(Activity child) 
  {
      LocalActivityManager manager = getLocalActivityManager();
      int index = mIdList.size()-1;

      if (index < 1) 
      {
          finish();
          return;
      }

      manager.destroyActivity(mIdList.get(index), true);
      mIdList.remove(index); index--;
      String lastId = mIdList.get(index);
      Activity a = manager.getActivity(lastId); 
      Intent lastIntent = a.getIntent();      // LINE 49
      Window newWindow = manager.startActivity(lastId, lastIntent);
      setContentView(newWindow.getDecorView());
  }

  /**
   * Starts an Activity as a child Activity to this.
   * @param Id Unique identifier of the activity to be started.
   * @param intent The Intent describing the activity to be started.
   * @throws android.content.ActivityNotFoundException.
   */
  public void startChildActivity(String Id, Intent intent) 
  {     
      Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
      if (window != null) 
      {
          mIdList.add(Id);
          setContentView(window.getDecorView()); 
      }    
  }

  /**
   * The primary purpose is to prevent systems before android.os.Build.VERSION_CODES.ECLAIR
   * from calling their default KeyEvent.KEYCODE_BACK during onKeyDown.
   */
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) 
  {
      if (keyCode == KeyEvent.KEYCODE_BACK) 
      {
          //preventing default implementation previous to android.os.Build.VERSION_CODES.ECLAIR
          return true;
      }
      return super.onKeyDown(keyCode, event);
  }

  /**
   * Overrides the default implementation for KeyEvent.KEYCODE_BACK 
   * so that all systems call onBackPressed().
   */
  @Override
  public boolean onKeyUp(int keyCode, KeyEvent event) 
  {
      if (keyCode == KeyEvent.KEYCODE_BACK) 
      {
          onBackPressed(); //LINE 88
          return true;
      }
      return super.onKeyUp(keyCode, event);
  }

  /**
   * If a Child Activity handles KeyEvent.KEYCODE_BACK.
   * Simply override and add this method.
   */
  @Override
  public void  onBackPressed  () 
  {
      int length = mIdList.size();
      if ( length > 1) 
      {
          Activity current = getLocalActivityManager().getActivity(mIdList.get(length-1));
          current.finish(); //LINE 103
      }  
  }
}

Tools_GroupActivity 类

public class Tools_GroupActivity extends TabGroupActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        startChildActivity("Tools_index", new Intent(this, Tools_index.class));
    }
}

Tools_index.class

这是一个有9个按钮的页面,例如当按下按钮1时,它会调用Tools_1_diamond类:

public void tools_button1_click (View view) 
{
    Intent edit = new Intent(getParent(), Tools_1_Diamond.class);
    TabGroupActivity parentActivity = (TabGroupActivity)getParent();
    parentActivity.startChildActivity("Tools_1_Diamond", edit);   
} 

Tools_1_diamond 类内

布局中有一个可以返回Tools_index页面的按钮,如下:

public void button_tools_subpage_back_click (View view)   
{  
    Intent edit = new Intent(getParent(), Tools_index.class);
    TabGroupActivity parentActivity = (TabGroupActivity)getParent();
    parentActivity.startChildActivity("Tools_index", edit); 
}   

@Override  
public void onBackPressed()   
{  
    Intent edit = new Intent(getParent(), Tools_index.class);
    TabGroupActivity parentActivity = (TabGroupActivity)getParent();
    parentActivity.startChildActivity("Tools_index", edit); 
}   

问题重现:

案例 A: 1.在Tools_1_Diamond类中按下自行设计的按钮时,(而不是后按)应用可以正常返回Tools_index页面。

  1. 那么,在Tools_index页面内部,如果此时用户按下BackPressed Button,应用程序会回到Tools_1_Diamond页面,

  2. 再按BackPress按钮,就会出现错误FATAL EXCEPTION: main java.lang.NullPointerException

案例 B: 一路只用BackPress,不碰自行设计的后退键,一切顺利。

问题/意图:

我觉得问题应该是自己设计的按钮并没有减少类似于BackPress方法的ArrayList...但是...

如何解决?我想告诉用户,当按下自行设计的后退按钮或 BackPress 方法时,将返回到 Tools_index 页面,并且在 Tools_index 页面中进一步按下 BackPress 将没有反应,甚至更好,弹出一个alertDialog 询问用户是否要退出应用程序。

Logcat:

06-19 22:40:03.570: D/webviewglue(23395): nativeDestroy view: 0x51909960
06-19 22:40:06.585: D/AndroidRuntime(23395): Shutting down VM
06-19 22:40:06.585: W/dalvikvm(23395): threadid=1: thread exiting with uncaught exception (group=0x40fe72a0)
06-19 22:40:06.670: E/AndroidRuntime(23395): FATAL EXCEPTION: main
06-19 22:40:06.670: E/AndroidRuntime(23395): java.lang.NullPointerException
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.abc.abc_v1.TabGroupActivity.finishFromChild(TabGroupActivity.java:49)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.app.Activity.finish(Activity.java:4215)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.abc.abc_v1.TabGroupActivity.onBackPressed(TabGroupActivity.java:103)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.abc.abc_v1.TabGroupActivity.onKeyUp(TabGroupActivity.java:88)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.KeyEvent.dispatch(KeyEvent.java:2729)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.app.Activity.dispatchKeyEvent(Activity.java:2431)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2033)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1363)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1363)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1363)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.widget.TabHost.dispatchKeyEvent(TabHost.java:309)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1363)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1363)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1363)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:2106)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1466)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.app.Activity.dispatchKeyEvent(Activity.java:2426)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2033)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3852)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewRootImpl.handleImeFinishedEvent(ViewRootImpl.java:3800)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:2935)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.os.Handler.dispatchMessage(Handler.java:99)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.os.Looper.loop(Looper.java:137)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at android.app.ActivityThread.main(ActivityThread.java:4921)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at java.lang.reflect.Method.invokeNative(Native Method)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at java.lang.reflect.Method.invoke(Method.java:511)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
06-19 22:40:06.670: E/AndroidRuntime(23395):    at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

  • 您能突出显示 TabGroupActivity 的第 49 行吗?
  • 抱歉丢失,现已添加。谢谢!

标签: android nullpointerexception activitygroup


【解决方案1】:

第一

问题可能出在TabGroupActivity,在你完成之后:

mIdList.remove(index);

您没有检查索引是否仍然有效,即大于或等于一。下面的代码大概应该是:

if (index > 0) {
     index--;
     String lastId = mIdList.get(index);
     Intent lastIntent = manager.getActivity(lastId).getIntent(); //LINE49
     Window newWindow = manager.startActivity(lastId, lastIntent);
     setContentView(newWindow.getDecorView());
}
else {
    // Handle case where there are no children left.
}

第二

值得注意的是,LocalActivityManager 在 API 级别 13 中已被弃用,因此,除非您仅针对 13 之前的设备,否则不应使用它。

即使您决定继续使用它,在某些情况下它实际上也不会启动新的Activity。见here

【讨论】:

  • 感谢您的及时回复!我已经尝试使用您上面显示的建议,但失败了,出现了同样的错误。从这样的事实来看,如果只按下 BackPressed 按钮,整个代码可以毫无错误地实现。因此我不知道是不是因为按下自己设计的返回按钮与按下 BackPress 不同,如果是,有没有办法让系统知道用户是否按下了自己设计的返回按钮,以执行将由 OnBackPressed 执行的 onKeyUp 方法?
  • 您是否尝试将第 49 行拆分为两行,看看哪一行失败:Activity a = manager.getActivity(lastId); 然后Intent lastIntent = a.getIntent();
  • 所以,a 为空,所以lastId 没有返回活动。我会考虑的。
猜你喜欢
  • 1970-01-01
  • 2014-11-07
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
相关资源
最近更新 更多