Issue
I HAVE ALREADY LOOKED FOR ANY POSSIBLE SIMILAR QUESTIONS AND NONE OF THEM ARE RELATED TO THIS ONE AND DON'T PROVIDE A SOLUTION FOR THIS QUESTION.
I have a basic chat implementation design in which the user opens a BottomSheetDialogFragment
from the ChatFragment
.
This BottomSheetDialogFragment
is responsible for asking the user to confirm he wants to upload the selected file and shows the upload progress after confirmation.
After the upload is completed, the BottomSheetDialogFragment
dismisses itself automatically.
Everything works perfectly if the user does not rotated the screen when the upload is in progress.
The problem happens when the screen is rotated while the upload is under going.
While it is uploading, the screen is rotated and the upload is completed after that, the AsyncTask
invokes the Complete listener set by the BottomSheetDialogFragment
.
When the BottomSheetDialogFragment
Complete listener is called, it simply executes the dismiss()
method, but at this point a NPE is thrown because the BottomSheetDialogFragment
is no longer attached to any activity.
I am looking for a solution that does not involve using setRetainInstance(true)
(I loose the reference to the AsyncTask
) nor changing configChanges
options in the manifest.
So far I've tried as far as going to all the available fragment managers to try and pop the BottomSheetDialogFragment
from the stack, but since it is no longer attached to the activity all fragment managers are null. I also tried to dismiss it from the ChatFragment
since it holds a reference to the dialog, but the same problems exist. It feels as if the AsyncTask
"detached" context is passed down to all the Complete listeners causing all of them to be detached from the activity as well.
Here's the code requested in the comment:
ChatFragment
public class ChatFragment extends Fragment { // That's the v4.support fragment
(...)
@Override
public void onActivityResult(int requestCode, int resultCode, final Intent data) {
if (resultCode == RESULT_OK) {
final FragmentActivity activity;
if ((activity = getActivity()) != null) {
final BottomSheet BottomSheet = new BottomSheet();
final OnFileUploadCompleteListener onFileUploadCompleteListener = new OnFileUploadCompleteListener() {
@Override
public void onComplete() {
bottomSheet.dismiss(); // tried just dismiss(); as well, makes no difference if it is dismissed from this class or from the BottomSheet itself
}
};
bottomSheet
.setOnFileUploadCompleteListener(onFileUploadCompleteListener)
.show(activity.getSupportFragmentManager(), bottomSheet.getClass().toString());
}
}
}
(...)
}
BottomSheet
public class BottomSheet extends BottomSheetDialogFragment implements FileUploadTask.OnUploadCompleteListener {
// the file upload task is initiated when the user confirms the upload
(...)
@Override
public void onUploadComplete(String response) {
if (onFileUploadCompleteListener != null) {
onFileUploadCompleteListener.onComplete();
}
dismiss();
}
public BottomSheet setOnFileUploadCompleteListener(OnFileUploadCompleteListener onFileUploadCompleteListener) {
this.onFileUploadCompleteListener = onFileUploadCompleteListener;
return this;
}
public interface OnFileUploadCompleteListener {
void onComplete();
}
(...)
}
FileUploadTask
public class FileUploadTask extends AsyncTask<File, Integer, String> {
private OnUploadCompleteListener onUploadCompleteListener;
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(File... fileUploadDataParams) {
(miscellaneous file upload code)
return response;
}
@Override
protected void onPostExecute(String response) {
super.onPostExecute(response);
if (onUploadCompleteListener != null) {
onUploadCompleteListener.onUploadComplete(response);
}
}
public FileUploadTask setOnUploadCompleteListener(OnUploadCompleteListener listener) {
onUploadCompleteListener = listener;
return this;
}
public interface OnUploadCompleteListener {
void onUploadComplete(String response);
}
}
Solution
I've ended up abstracting the communication layer between the AsyncTask and the class attached to its listeners by moving them to LocalBroadcast receivers. This way the AsyncTask is no longer "leaking" an activity detached state to the listeners.
Moreover, I noticed the upload was one that could be a long running task, for that reason I completely dropped AsyncTask and moved to IntentService.
Answered By - Shadow
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.