diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java index 39f02c6fb..5cec9c940 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java @@ -286,7 +286,7 @@ public void onPause() { _appSettings.setDocumentPreviewState(_document.path, _isPreviewVisible); _appSettings.setLastEditPosition(_document.path, TextViewUtils.getSelection(_hlEditor)[0]); - if(_document.path.equals(_appSettings.getTodoFile().getAbsolutePath())){ + if (_document.path.equals(_appSettings.getTodoFile().getAbsolutePath())) { TodoWidgetProvider.updateTodoWidgets(); } super.onPause(); @@ -862,7 +862,12 @@ private boolean isDisplayedAtMainActivity() { } public void updateViewModeText() { - _format.getConverter().convertMarkupShowInWebView(_document, getTextString(), getActivity(), _webView, _nextConvertToPrintMode, _hlEditor.isLineNumbersEnabled()); + // Don't let text to view mode crash app + try { + _format.getConverter().convertMarkupShowInWebView(_document, getTextString(), getActivity(), _webView, _nextConvertToPrintMode, _hlEditor.isLineNumbersEnabled()); + } catch (OutOfMemoryError e) { + _format.getConverter().convertMarkupShowInWebView(_document, "updateViewModeText getTextString(): OutOfMemory " + e, getActivity(), _webView, _nextConvertToPrintMode, _hlEditor.isLineNumbersEnabled()); + } } public void setViewModeVisibility(final boolean show) { diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java index 73c1a3e48..1e8f9469a 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java @@ -17,6 +17,7 @@ import android.os.Build; import android.os.Bundle; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import android.util.Patterns; import android.util.TypedValue; @@ -433,7 +434,9 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) { @Override public void onFsViewerSelected(final String request, final File sel, final Integer lineNumber) { - if (sel.isDirectory()) { + if (sel == null) { + Log.e(getClass().getName(), "onFsViewerSelected: selected file is null"); + } else if (sel.isDirectory()) { NewFileDialog.newInstance(sel, false, f -> { if (f.isFile()) { appendToExistingDocumentAndClose(f, true); diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java index 2c2fa794f..440627010 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java @@ -119,7 +119,11 @@ public void afterTextChanged(final Editable s) { @Override public boolean onPreDraw() { _lineNumbersDrawer.setTextSize(getTextSize()); - return super.onPreDraw(); + try { + return super.onPreDraw(); + } catch (OutOfMemoryError ignored) { + return false; // return false to cancel current drawing pass/round + } } @Override diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/SyntaxHighlighterBase.java b/app/src/main/java/net/gsantner/markor/frontend/textview/SyntaxHighlighterBase.java index fdd5a36ba..00756b5b2 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/SyntaxHighlighterBase.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/SyntaxHighlighterBase.java @@ -62,9 +62,9 @@ * Spans are further divided into two categories: dynamic and static. * - Dynamic spans are updated as one scrolls, as described above * - Static spans are applied once and never updated. These are typically used for - * spans which affect the text layout. - * - For example, a span which makes text bigger. - * - Updating these dynamically would make the text jump around as one scrolls + * spans which affect the text layout. + * - For example, a span which makes text bigger. + * - Updating these dynamically would make the text jump around as one scrolls *

* Fixup: * - As the user types we shift all spans to accomodate the changed text. @@ -75,19 +75,19 @@ * - Derived classes should override generateSpans() to generate all spans * - New spans are added by calling addSpanGroup() * - The HighlightingEditor will trigger the generation of spans when the text changes. - * - This is debounced so that changes are batched - * - Span generation is done on a background thread + * - This is debounced so that changes are batched + * - Span generation is done on a background thread *

* Other performance tips: * - Performance is heavily dependent on the number of spans applied to the text. * - Combine related spans into a single span if possible - * - HighlightSpan is a helper class which can be used to create a span with multiple attributes - * - For example, a span which makes text bold and italic + * - HighlightSpan is a helper class which can be used to create a span with multiple attributes + * - For example, a span which makes text bold and italic * - Absolutely minimize the number of spans implementing `UpdateLayout` - * - These spans trigger a text layout update when changed in any way - * - Instead consider using a span implementing `StaticSpan` - * - If StaticSpans are present, the text is reflowed after applying them - * - This happens once, and not for each span, which is much more efficient + * - These spans trigger a text layout update when changed in any way + * - Instead consider using a span implementing `StaticSpan` + * - If StaticSpans are present, the text is reflowed after applying them + * - This happens once, and not for each span, which is much more efficient */ public abstract class SyntaxHighlighterBase { @@ -230,7 +230,7 @@ public SyntaxHighlighterBase clearStatic() { boolean hasStatic = false; for (int i = _groups.size() - 1; i >= 0; i--) { final SpanGroup group = _groups.get(i); - if (group.isStatic) { + if (group != null && group.isStatic) { hasStatic = true; _spannable.removeSpan(group.span); } @@ -348,7 +348,7 @@ public SyntaxHighlighterBase applyDynamic(final int[] range) { for (int i = 0; i < _groups.size(); i++) { final SpanGroup group = _groups.get(i); - if (group.isStatic) { + if (group == null || group.isStatic) { continue; } @@ -368,7 +368,6 @@ public SyntaxHighlighterBase applyDynamic(final int[] range) { } - public SyntaxHighlighterBase applyStatic() { if (_spannable != null && !_staticApplied) { applyFixup(); diff --git a/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java b/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java index 8cccb2912..061548a7b 100644 --- a/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java +++ b/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java @@ -56,6 +56,7 @@ import java.util.Set; import java.util.Stack; import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -687,7 +688,10 @@ private void loadFolder(final File folder, final File show) { final File toShow = show == null ? _fileToShowAfterNextLoad : show; _fileToShowAfterNextLoad = null; - executorService.execute(() -> _loadFolder(toLoad, toShow)); + try { + executorService.execute(() -> _loadFolder(toLoad, toShow)); + } catch (RejectedExecutionException ignored) { // during exit + } } // This function is not called on the main thread, so post to the UI thread