alibaba / atlas

A powerful Android Dynamic Component Framework.
Apache License 2.0
8.13k stars 1.47k forks source link

[user]:使用RemoteFragment上线后,概率报空指针异常 #272

Open fushiming1983 opened 6 years ago

fushiming1983 commented 6 years ago

Atlas版本:atlas_core:5.0.8.5-rc2 atlasplugin:2.3.3.rc41 使用场景: 新增了一个bundle,这个bundle需要使用app里的一个Fragment,就改造了这个Fragment为RemoteFragment,并在新增bundle的mainifest里注册了这个remoteFragment,这样在新bundle就可以使用这个RemoteFragment,具体调用方法:RemoteFactory.requestRemote(RemoteFragment.class, this, dataIntent,new RemoteFactory.OnRemoteStateListener()) 就是Demo里方法,现在上线后,偶现如下异常: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference at android.taobao.atlas.hack.AndroidHack.findField(AndroidHack.java:538) at android.taobao.atlas.remote.fragment.RemoteFragment.onAttach(RemoteFragment.java:154) ... 26 more java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference at android.taobao.atlas.hack.AndroidHack.findField(AndroidHack.java:538) at android.taobao.atlas.remote.fragment.RemoteFragment.onAttach(RemoteFragment.java:154) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1231) at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595) at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2893) at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:190) at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:353) at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:85) at me.yokeyword.fragmentation.SupportActivity.onCreate(SupportActivity.java:38) at me.yokeyword.fragmentation_swipeback.SwipeBackActivity.onCreate(SwipeBackActivity.java:23) at com..base.BaseActivity.onCreate(BaseActivity.java:80) at com..onCreate(InfoVideoPlayActivity.java:317) at android.app.Activity.performCreate(Activity.java:6163) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) at android.taobao.atlas.runtime.InstrumentationHook.callActivityOnCreate(InstrumentationHook.java:671) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2457) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2576) at android.app.ActivityThread.access$1000(ActivityThread.java:163) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1461) at android.taobao.atlas.runtime.ActivityThreadHook.handleMessage(ActivityThreadHook.java:285) at android.os.Handler.dispatchMessage(Handler.java:98)

请帮忙定位下这个问题,谢谢!

hwjump commented 6 years ago

targetFragment 为空了,所以基本上就是出问题在创建fragment那里。 因为是偶现,所以我怀疑的是你那个remotefragment没有安装成功,导致去loadClass失败。可以看一下,出问题前面时候的一些异常log,分析下。

相关代码:https://github.com/alibaba/atlas/blob/master/atlas-core/src/main/java/android/taobao/atlas/remote/fragment/RemoteFragment.java#L51

fushiming1983 commented 6 years ago

应该不是bundle安装不成功的原因,这个RemoteFragment所在的bundle中其他的Activity都能打开的

fushiming1983 commented 6 years ago

public static RemoteFragment createRemoteFragment(Activity activity, String key,String bundleName) throws Exception{ RemoteFragment remoteFragment = new RemoteFragment(); remoteFragment.targetBundleName = bundleName; remoteFragment.remoteActivity = RemoteActivityManager.obtain(activity).getRemoteHost(remoteFragment); final BundleListing.BundleInfo bi = AtlasBundleInfoManager.instance().getBundleInfo(bundleName); String fragmentClazzName = bi.remoteFragments.get(key); remoteFragment.targetFragment = (Fragment)remoteFragment.remoteActivity.getClassLoader().loadClass(fragmentClazzName).newInstance(); if(!(remoteFragment.targetFragment instanceof IRemote)){ throw new RuntimeException("Fragment for remote use must implements IRemote"); } return remoteFragment; }

这段是createRemoteFragment代码,如果classLoader失败的话,应该会抛RuntimeException,就不会走接下来的Fragment.onAttach, 我这边RemoteFactory.OnRemoteStateListener.onFailed是不会处理的,只是报个错,所以这边有疑问,请帮忙解答一下,谢谢!

hwjump commented 6 years ago
  1. 出异常的的前面的一些logcat有么? 因为只有创建的地方设置了remoteFragment,如果不是创建失败,那我只能猜这个时候attach的不是你原来创建的remoteFragment或者是被系统回收了。 你是否可以模拟内存紧张的时候,看能不能复现
  2. 另一个解法,那就是不改造remotefragment,将这个fragment放在公共lib里。这样所有bundle都能访问了。
fushiming1983 commented 6 years ago

日志中:FragmentActivity.onCreate -》RemoteFragment.onAttach整个过程,这种场景下,跟了系统的源码,整个过程只有一种情况,此Activity在某个时刻被回收,还原Activity时,onCreate中的savedInstanceState不为空,然后在FragmentActivity.onCreate的mFragments.restoreAllState进行还原,这时还原的RemoteFragment中targetFragment为空,在attach时所以报了日志中RemoteFragment.onAttach空指针异常。

跟了整个流程的源码,以上描述的可能性特别大,请问下Atlas的RemoteFragment在还原时,会不会出现这样的问题,如果是这个问题,上层应该怎么规避?

fushiming1983 commented 6 years ago

RemoteFragment正常使用时,RemoteFragment.onAttach是不会出现在Activity.onCreate调用流程里的,因为FragmentManager.mActive还没有创建,而且RemoteFragment也没有add到FM里,所以更不会走到RemoteFragment.onAttach里

hwjump commented 6 years ago

恩,我有种可能。 我试下看能不能复现?

fushiming1983 commented 6 years ago

我已经模拟出这个场景了,而且是100%复现。我是这样复现的:关闭横竖屏切换,让activity可以横竖屏自由切换,这样在横竖屏切换时,onCreate中的savedInstanceState不为空,查看这个savedInstanceState是有fragments信息的,这个时候必现我帖子里描述的崩溃。

我认为Atlas在这个场景时,RemoteFragment还原是有问题的,麻烦及时查看下实现方案,请给与及时反馈,谢谢!

zhangfeifeilz commented 6 years ago

我想问下这个解决了么?我们也有这种现象!