1
0
Fork 0
mirror of https://github.com/M66B/FairEmail.git synced 2025-02-23 22:51:02 +00:00

Close boundary on destroy

This commit is contained in:
M66B 2019-08-09 19:29:17 +02:00
parent e09bd95cc6
commit 47da32aa97
3 changed files with 84 additions and 82 deletions

View file

@ -71,15 +71,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
private Handler handler;
private ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory);
private boolean destroyed = false;
private boolean error = false;
private int index = 0;
private List<Long> messages = null;
private MailService iservice = null;
private IMAPFolder ifolder = null;
private Message[] imessages = null;
private State state;
interface IBoundaryCallbackMessages {
void onLoading();
@ -100,11 +92,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
void setCallback(IBoundaryCallbackMessages intf) {
this.handler = new Handler();
this.intf = intf;
if (imessages == null)
index = 0;
else
index = imessages.length - 1;
this.state = new State();
}
@Override
@ -114,19 +102,21 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
}
@Override
public void onItemAtEndLoaded(final TupleMessageEx itemAtEnd) {
public void onItemAtEndLoaded(@NonNull final TupleMessageEx itemAtEnd) {
Log.i("Boundary at end");
queue_load(false);
}
private void queue_load(final boolean zero) {
final State state = this.state;
executor.submit(new Runnable() {
private int fetched;
@Override
public void run() {
try {
if (destroyed || error)
if (state.destroyed || state.error)
return;
fetched = 0;
@ -138,9 +128,9 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
}
});
if (server)
fetched = load_server();
fetched = load_server(state);
else
fetched = load_device();
fetched = load_device(state);
} catch (final Throwable ex) {
Log.e("Boundary", ex);
if (intf != null)
@ -163,12 +153,12 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
});
}
private int load_device() {
private int load_device(State state) {
DB db = DB.getInstance(context);
if (messages == null) {
messages = db.message().getMessageIdsByFolder(folder);
Log.i("Boundary device folder=" + folder + " query=" + query + " messages=" + messages.size());
if (state.messages == null) {
state.messages = db.message().getMessageIdsByFolder(folder);
Log.i("Boundary device folder=" + folder + " query=" + query + " messages=" + state.messages.size());
}
int found = 0;
@ -176,10 +166,10 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
db.beginTransaction();
String find = (TextUtils.isEmpty(query) ? null : query.toLowerCase());
for (int i = index; i < messages.size() && found < pageSize && !destroyed; i++) {
index = i + 1;
for (int i = state.index; i < state.messages.size() && found < pageSize && !state.destroyed; i++) {
state.index = i + 1;
EntityMessage message = db.message().getMessage(messages.get(i));
EntityMessage message = db.message().getMessage(state.messages.get(i));
if (message == null)
continue;
@ -243,7 +233,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
return found;
}
private int load_server() throws MessagingException, IOException {
private int load_server(State state) throws MessagingException, IOException {
DB db = DB.getInstance(context);
final EntityFolder browsable = db.folder().getBrowsableFolder(folder, query != null);
@ -254,7 +244,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
if (account == null)
return 0;
if (imessages == null)
if (state.imessages == null)
try {
// Check connectivity
if (!ConnectionHelper.getNetworkState(context).isSuitable())
@ -264,28 +254,28 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
boolean debug = (prefs.getBoolean("debug", false) || BuildConfig.BETA_RELEASE);
Log.i("Boundary server connecting account=" + account.name);
iservice = new MailService(context, account.getProtocol(), account.realm, account.insecure, debug);
iservice.setPartialFetch(account.partial_fetch);
iservice.setSeparateStoreConnection();
iservice.connect(account);
state.iservice = new MailService(context, account.getProtocol(), account.realm, account.insecure, debug);
state.iservice.setPartialFetch(account.partial_fetch);
state.iservice.setSeparateStoreConnection();
state.iservice.connect(account);
Log.i("Boundary server opening folder=" + browsable.name);
ifolder = (IMAPFolder) iservice.getStore().getFolder(browsable.name);
ifolder.open(Folder.READ_WRITE);
state.ifolder = (IMAPFolder) state.iservice.getStore().getFolder(browsable.name);
state.ifolder.open(Folder.READ_WRITE);
Log.i("Boundary server query=" + query);
if (query == null)
imessages = ifolder.getMessages();
state.imessages = state.ifolder.getMessages();
else if (query.startsWith(context.getString(R.string.title_search_special_prefix) + ":")) {
String special = query.split(":")[1];
if (context.getString(R.string.title_search_special_unseen).equals(special))
imessages = ifolder.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));
state.imessages = state.ifolder.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));
else if (context.getString(R.string.title_search_special_flagged).equals(special))
imessages = ifolder.search(new FlagTerm(new Flags(Flags.Flag.FLAGGED), true));
state.imessages = state.ifolder.search(new FlagTerm(new Flags(Flags.Flag.FLAGGED), true));
else
imessages = new Message[0];
state.imessages = new Message[0];
} else {
Object result = ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
Object result = state.ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
@Override
public Object doCommand(IMAPProtocol protocol) {
// Yahoo! does not support keyword search, but uses the flags $Forwarded $Junk $NotJunk
@ -299,7 +289,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
try {
// https://tools.ietf.org/html/rfc3501#section-6.4.4
Argument arg = new Argument();
if (query.startsWith("raw:") && iservice.getStore().hasCapability("X-GM-EXT-1")) {
if (query.startsWith("raw:") && state.iservice.getStore().hasCapability("X-GM-EXT-1")) {
// https://support.google.com/mail/answer/7190
// https://developers.google.com/gmail/imap/imap-extensions#extension_of_the_search_command_x-gm-raw
arg.writeAtom("X-GM-RAW");
@ -342,7 +332,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
Message[] imessages = new Message[msgnums.size()];
for (int i = 0; i < msgnums.size(); i++)
imessages[i] = ifolder.getMessage(msgnums.get(i));
imessages[i] = state.ifolder.getMessage(msgnums.get(i));
return imessages;
} else {
@ -367,7 +357,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
term = new OrTerm(term, new FlagTerm(
new Flags(Helper.sanitizeKeyword(search)), true));
return ifolder.search(term);
return state.ifolder.search(term);
}
} catch (MessagingException ex) {
@ -380,13 +370,13 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
if (result instanceof MessagingException)
throw (MessagingException) result;
imessages = (Message[]) result;
state.imessages = (Message[]) result;
}
Log.i("Boundary server found messages=" + imessages.length);
Log.i("Boundary server found messages=" + state.imessages.length);
index = imessages.length - 1;
state.index = state.imessages.length - 1;
} catch (Throwable ex) {
error = true;
state.error = true;
if (ex instanceof FolderClosedException)
Log.w("Search", ex);
else
@ -397,11 +387,11 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
List<EntityRule> rules = db.rule().getEnabledRules(browsable.id);
int found = 0;
while (index >= 0 && found < pageSize && !destroyed) {
Log.i("Boundary server index=" + index);
int from = Math.max(0, index - (pageSize - found) + 1);
Message[] isub = Arrays.copyOfRange(imessages, from, index + 1);
index -= (pageSize - found);
while (state.index >= 0 && found < pageSize && !state.destroyed) {
Log.i("Boundary server index=" + state.index);
int from = Math.max(0, state.index - (pageSize - found) + 1);
Message[] isub = Arrays.copyOfRange(state.imessages, from, state.index + 1);
state.index -= (pageSize - found);
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
@ -411,20 +401,20 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
fp.add(IMAPFolder.FetchProfileItem.HEADERS);
fp.add(FetchProfile.Item.SIZE);
fp.add(IMAPFolder.FetchProfileItem.INTERNALDATE);
ifolder.fetch(isub, fp);
state.ifolder.fetch(isub, fp);
try {
db.beginTransaction();
for (int j = isub.length - 1; j >= 0 && found < pageSize && !destroyed; j--)
for (int j = isub.length - 1; j >= 0 && found < pageSize && !state.destroyed; j--)
try {
long uid = ifolder.getUID(isub[j]);
long uid = state.ifolder.getUID(isub[j]);
Log.i("Boundary server sync uid=" + uid);
EntityMessage message = db.message().getMessageByUid(browsable.id, uid);
if (message == null) {
message = Core.synchronizeMessage(context,
account, browsable,
ifolder, (IMAPMessage) isub[j],
state.ifolder, (IMAPMessage) isub[j],
true, true,
rules, null);
found++;
@ -457,20 +447,39 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
return found;
}
void clear() {
destroyed = true;
void close() {
final State state = this.state;
this.state = new State();
state.destroyed = true;
executor.submit(new Runnable() {
@Override
public void run() {
Log.i("Boundary destroy");
Log.i("Boundary close");
try {
if (iservice != null)
iservice.close();
if (state.ifolder != null)
state.ifolder.close();
} catch (Throwable ex) {
Log.e("Boundary", ex);
}
try {
if (state.iservice != null)
state.iservice.close();
} catch (Throwable ex) {
Log.e("Boundary", ex);
}
}
});
}
private class State {
boolean destroyed = false;
boolean error = false;
int index = 0;
List<Long> messages = null;
MailService iservice = null;
IMAPFolder ifolder = null;
Message[] imessages = null;
}
}

View file

@ -2779,7 +2779,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
getContext(), getViewLifecycleOwner(),
viewType, type, account, folder, thread, id, query, server);
vmodel.setCallback(callback);
vmodel.setCallback(getViewLifecycleOwner(), callback);
vmodel.setObserver(getViewLifecycleOwner(), observer);
}

View file

@ -71,10 +71,8 @@ public class ViewModelMessages extends ViewModel {
if (model == null || !model.args.equals(args)) {
Log.i("Creating model=" + viewType + " replace=" + (model != null));
if (model != null) {
if (model != null)
model.list.removeObservers(owner);
model.clear();
}
DB db = DB.getInstance(context);
@ -174,7 +172,7 @@ public class ViewModelMessages extends ViewModel {
if (viewType == AdapterMessage.ViewType.THREAD || lowmem) {
Log.i("Remove model=" + viewType);
remove(viewType);
models.remove(viewType);
}
dump();
@ -182,10 +180,10 @@ public class ViewModelMessages extends ViewModel {
});
if (viewType == AdapterMessage.ViewType.UNIFIED) {
remove(AdapterMessage.ViewType.FOLDER);
remove(AdapterMessage.ViewType.SEARCH);
models.remove(AdapterMessage.ViewType.FOLDER);
models.remove(AdapterMessage.ViewType.SEARCH);
} else if (viewType == AdapterMessage.ViewType.FOLDER)
remove(AdapterMessage.ViewType.SEARCH);
models.remove(AdapterMessage.ViewType.SEARCH);
if (viewType != AdapterMessage.ViewType.THREAD) {
last = viewType;
@ -201,15 +199,7 @@ public class ViewModelMessages extends ViewModel {
@Override
protected void onCleared() {
for (AdapterMessage.ViewType viewType : new ArrayList<>(models.keySet()))
remove(viewType);
}
private void remove(AdapterMessage.ViewType viewType) {
Model model = models.get(viewType);
if (model != null) {
model.clear();
models.remove(viewType);
}
}
void observePrevNext(LifecycleOwner owner, final long id, final IPrevNext intf) {
@ -385,20 +375,23 @@ public class ViewModelMessages extends ViewModel {
this.boundary = boundary;
}
void setCallback(BoundaryCallbackMessages.IBoundaryCallbackMessages callback) {
if (boundary != null)
void setCallback(LifecycleOwner owner, BoundaryCallbackMessages.IBoundaryCallbackMessages callback) {
if (boundary != null) {
boundary.setCallback(callback);
owner.getLifecycle().addObserver(new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroyed() {
boundary.close();
}
});
}
}
void setObserver(LifecycleOwner owner, @NonNull Observer<PagedList<TupleMessageEx>> observer) {
//list.removeObservers(owner);
list.observe(owner, observer);
}
private void clear() {
if (this.boundary != null)
this.boundary.clear();
}
}
interface IPrevNext {