Fixed android crash when process get killed

This commit is contained in:
hshristov
2015-11-06 10:04:56 +02:00
parent 3aed89ca89
commit c06b0681fa
3 changed files with 248 additions and 107 deletions

View File

@ -252,12 +252,13 @@
</TypeScriptCompile> </TypeScriptCompile>
<TypeScriptCompile Include="apps\ui-tests-app\pages\handlers.ts" /> <TypeScriptCompile Include="apps\ui-tests-app\pages\handlers.ts" />
<TypeScriptCompile Include="apps\ui-tests-app\segmented-bar\all.ts"> <TypeScriptCompile Include="apps\ui-tests-app\segmented-bar\all.ts">
<DependentUpon>all.xml</DependentUpon> <DependentUpon>all.xml</DependentUpon>
</TypeScriptCompile> </TypeScriptCompile>
<TypeScriptCompile Include="apps\ui-tests-app\segmented-bar\clean.ts"> <TypeScriptCompile Include="apps\ui-tests-app\segmented-bar\clean.ts">
<DependentUpon>clean.xml</DependentUpon> <DependentUpon>clean.xml</DependentUpon>
</TypeScriptCompile> </TypeScriptCompile>
<TypeScriptCompile Include="color\known-colors.d.ts" /> <TypeScriptCompile Include="color\known-colors.d.ts" />
<TypeScriptCompile Include="es6.d.ts" />
<TypeScriptCompile Include="ui\animation\animation.d.ts" /> <TypeScriptCompile Include="ui\animation\animation.d.ts" />
<TypeScriptCompile Include="ui\animation\animation-common.ts"> <TypeScriptCompile Include="ui\animation\animation-common.ts">
<DependentUpon>animation.d.ts</DependentUpon> <DependentUpon>animation.d.ts</DependentUpon>
@ -2092,7 +2093,7 @@
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties> </WebProjectProperties>
</FlavorProperties> </FlavorProperties>
<UserProperties ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" /> <UserProperties ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" />
</VisualStudio> </VisualStudio>
</ProjectExtensions> </ProjectExtensions>
</Project> </Project>

View File

@ -28,6 +28,23 @@ function buildEntryFromArgs(arg: any): definition.NavigationEntry {
return entry; return entry;
} }
export function reloadPage(): void {
let frame = topmost();
if (frame) {
let currentEntry = frame._currentEntry.entry;
let newEntry: definition.NavigationEntry = {
animated: false,
clearHistory: true,
context: currentEntry.context,
create: currentEntry.create,
moduleName: currentEntry.moduleName,
backstackVisible: currentEntry.backstackVisible
}
frame.navigate(newEntry);
}
}
export function resolvePageFromEntry(entry: definition.NavigationEntry): pages.Page { export function resolvePageFromEntry(entry: definition.NavigationEntry): pages.Page {
var page: pages.Page; var page: pages.Page;
@ -230,6 +247,7 @@ export class Frame extends view.CustomLayoutView implements definition.Frame {
var navContext = navigationContext.entry; var navContext = navigationContext.entry;
this._onNavigatingTo(navContext, navigationContext.isBackNavigation); this._onNavigatingTo(navContext, navigationContext.isBackNavigation);
// TODO: This should happen once navigation is completed.
if (navigationContext.entry.entry.clearHistory) { if (navigationContext.entry.entry.clearHistory) {
this._backStack.length = 0; this._backStack.length = 0;
} }

View File

@ -16,138 +16,247 @@ var ANDROID_FRAME = "android_frame";
var BACKSTACK_TAG = "_backstackTag"; var BACKSTACK_TAG = "_backstackTag";
var NAV_DEPTH = "_navDepth"; var NAV_DEPTH = "_navDepth";
var CLEARING_HISTORY = "_clearingHistory"; var CLEARING_HISTORY = "_clearingHistory";
var activityInitialized = false;
var navDepth = -1; var navDepth = -1;
class PageFragmentBody extends android.app.Fragment { var PageFragmentBody = (<any>android.app.Fragment).extend({
public frame: Frame;
public entry: definition.BackstackEntry; onAttach: function (activity: android.app.Activity) {
console.log("PageFragmentBody onAttach called");
this.super.onAttach(activity);
console.log("PageFragmentBody onAttach ended");
},
constructor(frame: Frame, entry: definition.BackstackEntry) { onCreate: function (savedInstanceState: android.os.Bundle) {
super(); console.log("PageFragmentBody onCreate called");
this.super.onCreate(savedInstanceState);
this.frame = frame; this.super.setHasOptionsMenu(true);
this.entry = entry; },
return global.__native(this);
}
onAttach(activity: android.app.Activity) {
super.onAttach(activity);
trace.write(this.toString() + ".onAttach();", trace.categories.NativeLifecycle);
}
onCreate(savedInstanceState: android.os.Bundle) {
super.onCreate(savedInstanceState);
trace.write(this.toString() + ".onCreate(); savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle);
super.setHasOptionsMenu(true);
}
onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View {
trace.write(this.toString() + ".onCreateView(); container: " + container + "; savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle);
if (this[CLEARING_HISTORY]) {
trace.write(`${this.toString() } wants to create a view, but we are currently clearing history. Returning null.`, trace.categories.NativeLifecycle);
return null;
}
var entry: definition.BackstackEntry = this.entry;
var page: pages.Page = entry.resolvedPage;
onCreateView: function (inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View {
console.log("PageFragmentBody onCreateView called");
var entry = this.entry;
var page = entry.resolvedPage;
if (savedInstanceState && savedInstanceState.getBoolean(HIDDEN, false)) { if (savedInstanceState && savedInstanceState.getBoolean(HIDDEN, false)) {
// Manually hide the fragment if it was hidden before as Android will not do this every time. this.super.getFragmentManager().beginTransaction().hide(this).commit();
super.getFragmentManager().beginTransaction().hide(this).commit();
// As the page will not be added to the frame it won't be attached
// We should attach it manually so that it creates its nativeView
page._onAttached(this.getActivity()); page._onAttached(this.getActivity());
} }
else { else {
onFragmentShown(this); onFragmentShown(this);
} }
console.log("PageFragmentBody onCreateView ended");
trace.write(this.toString() + ".onCreateView(); nativeView: " + page._nativeView, trace.categories.NativeLifecycle);
return page._nativeView; return page._nativeView;
} },
onHiddenChanged(hidden: boolean) {
super.onHiddenChanged(hidden);
trace.write(this.toString() + ".onHiddenChanged(); hidden: " + hidden, trace.categories.NativeLifecycle);
onHiddenChanged: function (hidden: boolean) {
console.log("PageFragmentBody onHiddenChanged called");
this.super.onHiddenChanged(hidden);
if (hidden) { if (hidden) {
onFragmentHidden(this); onFragmentHidden(this);
} }
else { else {
onFragmentShown(this); onFragmentShown(this);
} }
} console.log("PageFragmentBody onHiddenChanged ended");
},
onActivityCreated(savedInstanceState: android.os.Bundle) { onActivityCreated: function (savedInstanceState: android.os.Bundle) {
super.onActivityCreated(savedInstanceState); console.log("PageFragmentBody onActivityCreated called");
trace.write(this.toString() + ".onActivityCreated(); savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle); this.super.onActivityCreated(savedInstanceState);
} console.log("PageFragmentBody onActivityCreated ended");
},
onSaveInstanceState(outState: android.os.Bundle) {
super.onSaveInstanceState(outState);
trace.write(this.toString() + ".onSaveInstanceState();", trace.categories.NativeLifecycle);
onSaveInstanceState: function (outState: android.os.Bundle) {
console.log("PageFragmentBody onSaveInstanceState called");
this.super.onSaveInstanceState(outState);
if (this.isHidden()) { if (this.isHidden()) {
outState.putBoolean(HIDDEN, true); outState.putBoolean(HIDDEN, true);
} }
} console.log("PageFragmentBody onSaveInstanceState ended");
},
onViewStateRestored(savedInstanceState: android.os.Bundle) { onViewStateRestored: function (savedInstanceState: android.os.Bundle) {
super.onViewStateRestored(savedInstanceState); console.log("PageFragmentBody onViewStateRestored called");
trace.write(this.toString() + ".onViewStateRestored(); savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle); this.super.onViewStateRestored(savedInstanceState);
} trace.write(this.getTag() + ".onViewStateRestored(); savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle);
console.log("PageFragmentBody onViewStateRestored ended");
},
onStart() { onStart: function () {
super.onStart(); console.log("PageFragmentBody onStart called");
trace.write(this.toString() + ".onStart();", trace.categories.NativeLifecycle); this.super.onStart();
} console.log("PageFragmentBody onStart ended");
},
onResume() { onResume: function () {
super.onResume(); console.log("PageFragmentBody onResume called");
trace.write(this.toString() + ".onResume();", trace.categories.NativeLifecycle); this.super.onResume();
} console.log("PageFragmentBody onResume ended");
},
onPause() { onPause: function () {
super.onPause(); console.log("PageFragmentBody onPause called");
trace.write(this.toString() + ".onPause();", trace.categories.NativeLifecycle); this.super.onPause();
} console.log("PageFragmentBody onPause ended");
},
onStop() { onStop: function () {
super.onStop(); console.log("PageFragmentBody onStop called");
trace.write(this.toString() + ".onStop();", trace.categories.NativeLifecycle); this.super.onStop();
} console.log("PageFragmentBody onStop ended");
},
onDestroyView() {
super.onDestroyView();
trace.write(this.toString() + ".onDestroyView();", trace.categories.NativeLifecycle);
onDestroyView: function () {
console.log("PageFragmentBody onDestroyView called");
this.super.onDestroyView();
onFragmentHidden(this); onFragmentHidden(this);
} console.log("PageFragmentBody onDestroyView ended");
},
onDestroy() { onDestroy: function () {
super.onDestroy(); console.log("PageFragmentBody onDestroy called");
trace.write(this.toString() + ".onDestroy();", trace.categories.NativeLifecycle); this.super.onDestroy();
// Explicitly free resources to allow Java Garbage collector to release resources associated with JavaScript implementations - e.g. large image files.
// Although we hint the V8 with the externally allocated memory, synchronization between the two GCs is not deterministic without an explicit call.
// TODO: Revisit this explicit Garbage Collector call when possible.
utils.GC(); utils.GC();
} console.log("PageFragmentBody onDestroy ended");
},
onDetach() { onDetach: function () {
super.onDetach(); console.log("PageFragmentBody onDetach called");
trace.write(this.toString() + ".onDetach();", trace.categories.NativeLifecycle); this.super.onDetach();
console.log("PageFragmentBody onDetach ended");
} }
});
public toString() { //class PageFragmentBody extends android.app.Fragment {
return `${this.getTag() }[${this.entry.resolvedPage.id}]`; // public frame: Frame;
} // public entry: definition.BackstackEntry;
}
function onFragmentShown(fragment: PageFragmentBody) { // constructor(frame: Frame, entry: definition.BackstackEntry) {
// super();
// this.frame = frame;
// this.entry = entry;
// return global.__native(this);
// }
// onAttach(activity: android.app.Activity) {
// super.onAttach(activity);
// trace.write(this.toString() + ".onAttach();", trace.categories.NativeLifecycle);
// }
// onCreate(savedInstanceState: android.os.Bundle) {
// super.onCreate(savedInstanceState);
// trace.write(this.toString() + ".onCreate(); savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle);
// super.setHasOptionsMenu(true);
// }
// onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View {
// trace.write(this.toString() + ".onCreateView(); container: " + container + "; savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle);
// if (this[CLEARING_HISTORY]) {
// trace.write(`${this.toString() } wants to create a view, but we are currently clearing history. Returning null.`, trace.categories.NativeLifecycle);
// return null;
// }
// var entry: definition.BackstackEntry = this.entry;
// var page: pages.Page = entry.resolvedPage;
// if (savedInstanceState && savedInstanceState.getBoolean(HIDDEN, false)) {
// // Manually hide the fragment if it was hidden before as Android will not do this every time.
// super.getFragmentManager().beginTransaction().hide(this).commit();
// // As the page will not be added to the frame it won't be attached
// // We should attach it manually so that it creates its nativeView
// page._onAttached(this.getActivity());
// }
// else {
// onFragmentShown(this);
// }
// trace.write(this.toString() + ".onCreateView(); nativeView: " + page._nativeView, trace.categories.NativeLifecycle);
// return page._nativeView;
// }
// onHiddenChanged(hidden: boolean) {
// super.onHiddenChanged(hidden);
// trace.write(this.toString() + ".onHiddenChanged(); hidden: " + hidden, trace.categories.NativeLifecycle);
// if (hidden) {
// onFragmentHidden(this);
// }
// else {
// onFragmentShown(this);
// }
// }
// onActivityCreated(savedInstanceState: android.os.Bundle) {
// super.onActivityCreated(savedInstanceState);
// trace.write(this.toString() + ".onActivityCreated(); savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle);
// }
// onSaveInstanceState(outState: android.os.Bundle) {
// super.onSaveInstanceState(outState);
// trace.write(this.toString() + ".onSaveInstanceState();", trace.categories.NativeLifecycle);
// if (this.isHidden()) {
// outState.putBoolean(HIDDEN, true);
// }
// }
// onViewStateRestored(savedInstanceState: android.os.Bundle) {
// super.onViewStateRestored(savedInstanceState);
// trace.write(this.toString() + ".onViewStateRestored(); savedInstanceState: " + savedInstanceState, trace.categories.NativeLifecycle);
// }
// onStart() {
// super.onStart();
// trace.write(this.toString() + ".onStart();", trace.categories.NativeLifecycle);
// }
// onResume() {
// super.onResume();
// trace.write(this.toString() + ".onResume();", trace.categories.NativeLifecycle);
// }
// onPause() {
// super.onPause();
// trace.write(this.toString() + ".onPause();", trace.categories.NativeLifecycle);
// }
// onStop() {
// super.onStop();
// trace.write(this.toString() + ".onStop();", trace.categories.NativeLifecycle);
// }
// onDestroyView() {
// super.onDestroyView();
// trace.write(this.toString() + ".onDestroyView();", trace.categories.NativeLifecycle);
// onFragmentHidden(this);
// }
// onDestroy() {
// super.onDestroy();
// trace.write(this.toString() + ".onDestroy();", trace.categories.NativeLifecycle);
// // Explicitly free resources to allow Java Garbage collector to release resources associated with JavaScript implementations - e.g. large image files.
// // Although we hint the V8 with the externally allocated memory, synchronization between the two GCs is not deterministic without an explicit call.
// // TODO: Revisit this explicit Garbage Collector call when possible.
// utils.GC();
// }
// onDetach() {
// super.onDetach();
// trace.write(this.toString() + ".onDetach();", trace.categories.NativeLifecycle);
// }
// public toString() {
// return `${this.getTag() }[${this.entry.resolvedPage.id}]`;
// }
//}
function onFragmentShown(fragment) {
if (fragment[CLEARING_HISTORY]) { if (fragment[CLEARING_HISTORY]) {
trace.write(`${fragment.toString() } has been shown, but we are currently clearing history. Returning.`, trace.categories.NativeLifecycle); trace.write(`${fragment.toString() } has been shown, but we are currently clearing history. Returning.`, trace.categories.NativeLifecycle);
return null; return null;
@ -183,7 +292,7 @@ function onFragmentShown(fragment: PageFragmentBody) {
frame._processNavigationQueue(page); frame._processNavigationQueue(page);
} }
function onFragmentHidden(fragment: PageFragmentBody) { function onFragmentHidden(fragment) {
if (fragment[CLEARING_HISTORY]) { if (fragment[CLEARING_HISTORY]) {
trace.write(`${fragment.toString() } has been hidden, but we are currently clearing history. Returning.`, trace.categories.NativeLifecycle); trace.write(`${fragment.toString() } has been hidden, but we are currently clearing history. Returning.`, trace.categories.NativeLifecycle);
return null; return null;
@ -282,7 +391,16 @@ export class Frame extends frameCommon.Frame {
var fragmentTransaction = manager.beginTransaction(); var fragmentTransaction = manager.beginTransaction();
var newFragmentTag = "fragment" + navDepth; var newFragmentTag = "fragment" + navDepth;
var newFragment = new PageFragmentBody(this, backstackEntry); //var newFragment = new PageFragmentBody(this, backstackEntry);
var newFragment = new PageFragmentBody();
var args = new android.os.Bundle();
args.putInt("num", num);
newFragment.setArguments(args);
newFragment.frame = this;
newFragment.entry = backstackEntry;
backstackEntry[BACKSTACK_TAG] = newFragmentTag; backstackEntry[BACKSTACK_TAG] = newFragmentTag;
backstackEntry[NAV_DEPTH] = navDepth; backstackEntry[NAV_DEPTH] = navDepth;
@ -404,7 +522,7 @@ export class Frame extends frameCommon.Frame {
console.log("---------------------------"); console.log("---------------------------");
console.log("Fragment Manager Back Stack (" + length + ")"); console.log("Fragment Manager Back Stack (" + length + ")");
while (i >= 0) { while (i >= 0) {
var fragment = <PageFragmentBody>manager.findFragmentByTag(manager.getBackStackEntryAt(i--).getName()); var fragment = <any>manager.findFragmentByTag(manager.getBackStackEntryAt(i--).getName());
console.log("[ " + fragment.toString() + " ]"); console.log("[ " + fragment.toString() + " ]");
} }
} }
@ -457,7 +575,11 @@ var NativeActivity = {
// If there is savedInstanceState this call will recreate all fragments that were previously in the navigation. // If there is savedInstanceState this call will recreate all fragments that were previously in the navigation.
// We take care of associating them with a Page from our backstack in the onAttachFragment callback. // We take care of associating them with a Page from our backstack in the onAttachFragment callback.
this.super.onCreate(savedInstanceState); // If there is savedInstanceState and activityInitialized is false we are restarted but process was killed.
// For now we treat it like first run (e.g. we are not passing savedInstanceState so no fragments are being restored).
// When we add support for applicatioin save/load state - revise this logic.
var isRestart = !!savedInstanceState && activityInitialized;
this.super.onCreate(isRestart ? savedInstanceState : null);
this.androidFrame.setActivity(this); this.androidFrame.setActivity(this);
@ -469,7 +591,8 @@ var NativeActivity = {
this.setContentView(this.androidFrame.rootViewGroup, new org.nativescript.widgets.CommonLayoutParams()); this.setContentView(this.androidFrame.rootViewGroup, new org.nativescript.widgets.CommonLayoutParams());
// If there is no instance state - we call navigateCore from here since Activity is created AFTER the navigate call and navigateCore will fail. // If there is no instance state - we call navigateCore from here since Activity is created AFTER the navigate call and navigateCore will fail.
var isRestart = !!savedInstanceState;
activityInitialized = true;
this.frame._onActivityCreated(isRestart); this.frame._onActivityCreated(isRestart);
}, },
@ -496,7 +619,7 @@ var NativeActivity = {
trace.write("NativeScriptActivity.onAttachFragment() : " + fragment.getTag(), trace.categories.NativeLifecycle); trace.write("NativeScriptActivity.onAttachFragment() : " + fragment.getTag(), trace.categories.NativeLifecycle);
this.super.onAttachFragment(fragment); this.super.onAttachFragment(fragment);
if (!(<PageFragmentBody>fragment).entry) { if (!(<any>fragment).entry) {
// There is no entry set to the fragment, so this must be destroyed fragment that was recreated by Android. // There is no entry set to the fragment, so this must be destroyed fragment that was recreated by Android.
// We should find its corresponding page in our backstack and set it manually. // We should find its corresponding page in our backstack and set it manually.
findPageForFragment(fragment, this.frame); findPageForFragment(fragment, this.frame);
@ -738,8 +861,8 @@ function findPageForFragment(fragment: android.app.Fragment, frame: Frame) {
} }
} }
if (page) { if (page) {
(<PageFragmentBody>fragment).frame = frame; (<any>fragment).frame = frame;
(<PageFragmentBody>fragment).entry = entry; (<any>fragment).entry = entry;
page[TAG] = fragmentTag; page[TAG] = fragmentTag;
} }
@ -753,5 +876,4 @@ function startActivity(activity: android.app.Activity, entry: definition.Navigat
intent.setAction(android.content.Intent.ACTION_DEFAULT); intent.setAction(android.content.Intent.ACTION_DEFAULT);
// TODO: Put the navigation context (if any) in the intent // TODO: Put the navigation context (if any) in the intent
activity.startActivity(intent); activity.startActivity(intent);
} }