Closed Lakedaemon closed 8 years ago
I did another experiment : I added a loging command to the commented line : if (context.getSystemService("PATH_CONTEXT") == null) { L.info("not a path context $context ${(context as? ContextWrapper)?.getBaseContext()}") throw Exception("not a path context $context ${(context as? ContextWrapper)?.getBaseContext()}") }
And I got interesting results : 1) getContext() of both views are actualy NOT wrapped with a PathContext (the 2 lines appeared in logcat) 2) adding an exception with the commented line must have trigger a catch block somewhere that swallows my exception and that makes the code work (bad luck, I was hoping to find where the problem was coming from that way)
Another experiment with print debug statements. It looks like the error comes from this part of the code : val context = PathContext.create(oldPath, to, contextFactory) val layout = getLayout(to) val newView = LayoutInflater.from(context).cloneInContext(context).inflate(layout, containerView, false)
My print statements tell me that context is able to deliver a PathContext but not newView.getContext() Which is weird as I guess that the cloneInContext part was all about using a layoutInflater set with the good PathContexted context... Let's now grep LayoutInflater
I looked into the chains of ContextWrapper. newView.getContext() has : org.lakedaemon.android.flow.MyFlowActivity@427b02c8 android.app.ContextImpl@42807fe0
context has : flow.path.PathContext@428fc308 flow.path.Path$LocalPathWrapper@428fc2c8 org.lakedaemon.android.flow.MyFlowActivity@427b02c8 ...
Also I checked LayoutInflater.from(context).cloneInContext(context) the Context it holds is identityEquals to context So the issue certainly comes from inflate(layout, containerView, false)
When I grepped the LayoutInflater code, it seemed to me that there might be a possibility the context could be changed (when a view uses a theme...)
@Lakedaemon Do you use AppCompatActivity
from 22.1.+
? If so, there is a know issues with misusing context during inflation (see workaround inside): #88 (dig into mortar
issue)
Yes I'm using AppCompatActivity (to get support for the api range 9 to 22) and I believe that I suffer from this exact issue. Thanks for the pointer.
To fix this, just use LayoutInflater.from(context.getApplication()).cloneInContext(context).inflate(...)
And you also need to initialize your container view group like this
PathContext pathContext = PathContext.root(this);
framePathContainerView = (MortarScreenSwitcherFrame) LayoutInflater.from(this)
.cloneInContext(pathContext)
.inflate(R.layout.activity_main, null);
setContentView(framePathContainerView);
Thanks for the tip. It really helped.
See also #91
I am in the process to convert on of my project to dagger2 + mortar + flow + kotlin. I mostly copied code from the mortar HelloDagger2 samples, flow samples and kotlin+dagger samples
I manage to display a "Search" screen through flowSupport = FlowDelegate.onCreate(nonConfig, getIntent(), savedInstanceState, parceler, History.single(Search()), this)
Then I click on a button to display a "Build" screen through Flow.get(this@FlowActivity).set(Build()) and I get the exception : java.lang.NullPointerException: Expected to find a PathContext but did not.
I guess that the offending view got inflated from a Context that has not been wrapped in a PathContext though it should have been.
To understand why the exception happened I added a logging line to see if both views where instanciated with a PathContext (they are)
The weird thing is that : without the logging line on the Search view, the exception happens, with the logging line, it doesn't happen... (timing/thread issue ? o.O)
public class SearchView(context: Context, attrs: AttributeSet) : DrawerLayout(context, attrs) { var searchPresenter: SearchPresenter? = null [Inject] set
....
}
The complete stack trace (first line helps me track which view is the offender--> the first View)
05-17 15:10:43.120 14120-14707/org.lakedaemon.japanese.dictionary.pro E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: org.lakedaemon.japanese.dictionary.pro, PID: 14120 java.lang.RuntimeException: org.lakedaemon.android.flow.pathview.FramePathContainerView{4287e228 V.E..... ........ 0,0-720,1118 #7f0e00c4 app:id/container} org.lakedaemon.android.flow.view.BuildView{42dbb758 VFE..... ........ 0,0-720,1118 #1020012 android:id/tabhost} java.lang.NullPointerException: Expected to find a PathContext but did not. at org.lakedaemon.android.flow.pathview.SimplePathContainer.performTraversal(SimplePathContainer.kt:55) at flow.path.PathContainer.executeTraversal(PathContainer.java:89) at org.lakedaemon.android.flow.pathview.FramePathContainerView.dispatch(FramePathContainerView.kt:51) at org.lakedaemon.android.flow.FlowActivity.dispatch(FlowActivity.kt:163) at flow.Flow$PendingTraversal.dispatch(Flow.java:315) at flow.Flow$2.doExecute(Flow.java:197) at flow.Flow$PendingTraversal.execute(Flow.java:323) at flow.Flow.move(Flow.java:232) at flow.Flow.set(Flow.java:162) at org.lakedaemon.android.flow.FlowActivity$onCreateOptionsMenu$1.onMenuItemClick(FlowActivity.kt:132) at android.support.v7.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:149) at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:949) at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:939) at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:598) at android.support.v7.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:139) at android.view.View.performClick(View.java:4741) at android.view.View$PerformClick.run(View.java:19384) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:146) at android.app.ActivityThread.main(ActivityThread.java:5679) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException: Expected to find a PathContext but did not. at flow.path.Preconditions.checkNotNull(Preconditions.java:30) at flow.path.PathContext.get(PathContext.java:100) at org.lakedaemon.android.flow.pathview.SimplePathContainer.performTraversal(SimplePathContainer.kt:50) at flow.path.PathContainer.executeTraversal(PathContainer.java:89) at org.lakedaemon.android.flow.pathview.FramePathContainerView.dispatch(FramePathContainerView.kt:51) at org.lakedaemon.android.flow.FlowActivity.dispatch(FlowActivity.kt:163) at flow.Flow$PendingTraversal.dispatch(Flow.java:315) at flow.Flow$2.doExecute(Flow.java:197) at flow.Flow$PendingTraversal.execute(Flow.java:323) at flow.Flow.move(Flow.java:232) at flow.Flow.set(Flow.java:162) at org.lakedaemon.android.flow.FlowActivity$onCreateOptionsMenu$1.onMenuItemClick(FlowActivity.kt:132) at android.support.v7.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:149) at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:949) at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:939) at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:598) at android.support.v7.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:139) at android.view.View.performClick(View.java:4741) at android.view.View$PerformClick.run(View.java:19384) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:146) at android.app.ActivityThread.main(ActivityThread.java:5679) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107) at dalvik.system.NativeStart.main(Native Method)