Fix concurrency bugs in MarkdownPresenter

This commit is contained in:
Billy Brawner 2019-02-08 20:09:28 -06:00 committed by William Brawner
parent 29fb166756
commit 6ca95063b9

View file

@ -20,13 +20,16 @@ import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
public class MarkdownPresenterImpl implements MarkdownPresenter { public class MarkdownPresenterImpl implements MarkdownPresenter {
private final Object fileLock = new Object();
private MarkdownFile file; private MarkdownFile file;
private MarkdownEditView editView; private volatile MarkdownEditView editView;
private MarkdownPreviewView previewView; private volatile MarkdownPreviewView previewView;
private Handler fileHandler = new Handler(); private Handler fileHandler = new Handler();
public MarkdownPresenterImpl(MarkdownFile file) { public MarkdownPresenterImpl(MarkdownFile file) {
this.file = file; synchronized (fileLock) {
this.file = file;
}
} }
@Override @Override
@ -37,11 +40,15 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
@Override @Override
public void loadMarkdown() { public void loadMarkdown() {
Runnable fileLoader = () -> { Runnable fileLoader = () -> {
boolean result = this.file.load(); boolean result;
synchronized (fileLock) {
result = this.file.load();
}
if (editView != null) { MarkdownEditView currentEditView = editView;
editView.onFileLoaded(result); if (currentEditView != null) {
editView.setMarkdown(getMarkdown()); currentEditView.onFileLoaded(result);
currentEditView.setMarkdown(getMarkdown());
onMarkdownEdited(); onMarkdownEdited();
} }
}; };
@ -77,12 +84,15 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
String html = generateHTML(tmpFile.getContent()); String html = generateHTML(tmpFile.getContent());
listener.onSuccess(html); listener.onSuccess(html);
} else { } else {
this.file = tmpFile; synchronized (fileLock) {
if (this.editView != null) { this.file = tmpFile;
editView.onFileLoaded(true); MarkdownEditView currentEditView = editView;
editView.setTitle(fileName); if (currentEditView != null) {
editView.setMarkdown(this.file.getContent()); currentEditView.onFileLoaded(true);
onMarkdownEdited(); currentEditView.setTitle(fileName);
currentEditView.setMarkdown(this.file.getContent());
onMarkdownEdited();
}
} }
} }
} else { } else {
@ -96,12 +106,15 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
@Override @Override
public void newFile(String newName) { public void newFile(String newName) {
if (this.editView != null) { synchronized (fileLock) {
this.file.setContent(this.editView.getMarkdown()); MarkdownEditView currentEditView = editView;
this.editView.setTitle(newName); if (currentEditView != null) {
this.editView.setMarkdown(""); file.setContent(currentEditView.getMarkdown());
currentEditView.setTitle(newName);
currentEditView.setMarkdown("");
}
file = new MarkdownFile(newName, "", "");
} }
this.file = new MarkdownFile(newName, "", "");
} }
@Override @Override
@ -117,13 +130,19 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
@Override @Override
public void saveMarkdown(MarkdownSavedListener listener, String filePath) { public void saveMarkdown(MarkdownSavedListener listener, String filePath) {
Runnable fileSaver = () -> { Runnable fileSaver = () -> {
boolean result = file.save(filePath); boolean result;
synchronized (fileLock) {
result = file.save(filePath);
}
if (listener != null) { if (listener != null) {
listener.saveComplete(result); listener.saveComplete(result);
} }
if (editView != null) { MarkdownEditView currentEditView = editView;
editView.setTitle(file.getName()); if (currentEditView != null) {
editView.onFileSaved(result); synchronized (fileLock) {
currentEditView.setTitle(file.getName());
}
currentEditView.onFileSaved(result);
} }
}; };
fileHandler.post(fileSaver); fileHandler.post(fileSaver);
@ -133,8 +152,9 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
public void onMarkdownEdited(String markdown) { public void onMarkdownEdited(String markdown) {
setMarkdown(markdown); setMarkdown(markdown);
Runnable generateMarkdown = () -> { Runnable generateMarkdown = () -> {
if (previewView != null) MarkdownPreviewView currentPreviewView = previewView;
previewView.updatePreview(generateHTML()); if (currentPreviewView != null)
currentPreviewView.updatePreview(generateHTML());
}; };
fileHandler.post(generateMarkdown); fileHandler.post(generateMarkdown);
} }
@ -160,12 +180,16 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
@Override @Override
public String getFileName() { public String getFileName() {
return file.getName(); synchronized (fileLock) {
return file.getName();
}
} }
@Override @Override
public void setFileName(String name) { public void setFileName(String name) {
file.setName(name); synchronized (fileLock) {
file.setName(name);
}
} }
@Override @Override
@ -175,12 +199,16 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
@Override @Override
public String getMarkdown() { public String getMarkdown() {
return file.getContent(); synchronized (fileLock) {
return file.getContent();
}
} }
@Override @Override
public void setMarkdown(String markdown) { public void setMarkdown(String markdown) {
file.setContent(markdown); synchronized (fileLock) {
file.setContent(markdown);
}
} }
@Override @Override
@ -189,7 +217,7 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
InputStream in = InputStream in =
context.getContentResolver().openInputStream(fileUri); context.getContentResolver().openInputStream(fileUri);
String fileName = null; String fileName = null;
if (fileUri.getScheme().equals("content")) { if ("content".equals(fileUri.getScheme())) {
Cursor retCur = context.getContentResolver() Cursor retCur = context.getContentResolver()
.query(fileUri, null, null, null, null); .query(fileUri, null, null, null, null);
if (retCur != null) { if (retCur != null) {
@ -199,7 +227,7 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
fileName = retCur.getString(nameIndex); fileName = retCur.getString(nameIndex);
retCur.close(); retCur.close();
} }
} else if (fileUri.getScheme().equals("file")) { } else if ("file".equals(fileUri.getScheme())) {
fileName = fileUri.getLastPathSegment(); fileName = fileUri.getLastPathSegment();
} }
if (fileName == null) { if (fileName == null) {
@ -208,8 +236,9 @@ public class MarkdownPresenterImpl implements MarkdownPresenter {
loadMarkdown(fileName, in); loadMarkdown(fileName, in);
} catch (Exception e) { } catch (Exception e) {
ACRA.getErrorReporter().handleException(e, false); ACRA.getErrorReporter().handleException(e, false);
if (editView != null) { MarkdownEditView currentEditView = editView;
editView.onFileLoaded(false); if (currentEditView != null) {
currentEditView.onFileLoaded(false);
} }
} }
} }