Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass post id instead of post model within intents and extras #5856

Merged
merged 9 commits into from
Jun 1, 2017

Conversation

oguzkocer
Copy link
Contributor

Fixes #5456. This is a possible fix to our TransactionTooLargeException crash. Unfortunately we do not have enough details about the crashes to make sure we have the right fix for it, so we have to keep trying until we figure it out. Having said that I think this is a step in the right direction. I think, unless it's mandatory, we should always try to pass ids instead of whole objects between activities. It makes the code more robust as well as prevent issues like this one.

Originally, I was working on the release/7.3 branch for this, so we could fix it asap. However, I believe this fix looks deceptively simple yet can cause some unseen issues, so I think it's just safer to target develop. We don't want to introduce more crashes while trying to fix one.

The changes are straightforward, however I got a little worried about the config changes (re-creating fragments and activities) since we don't pass the cached version of the post anymore and a new version from the DB is retrieved. As far as I can tell from the code, we do snyc the changes before this happens and my tests didn't result in anything lost, but it'd be good if we can test it out further.

To test:

  • Go into the post list, open a post, edit it, rotate the screen, assign featured images etc. Anything you can think of when a cached post might be purged and the DB version is used. For such a small PR, it actually requires some rigorous testing.

@aforcier Since this is posts related, do you mind reviewing this one, I'd feel more comfortable if I got the :shipit: from you!

/cc @mzorz @maxme @theck13 (since you were all interested in this issue)

@@ -153,7 +153,7 @@
public class EditPostActivity extends AppCompatActivity implements EditorFragmentListener, EditorDragAndDropListener,
ActivityCompat.OnRequestPermissionsResultCallback, EditorWebViewCompatibility.ReflectionFailureListener,
PhotoPickerFragment.PhotoPickerListener {
public static final String EXTRA_POST = "postModel";
public static final String EXTRA_POST_LOCAL_ID = "postModelLocalId";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for the explicit naming EXTRA_POST_LOCAL_ID

@@ -32,7 +37,7 @@ public static EditPostPreviewFragment newInstance(SiteModel site, PostModel post
EditPostPreviewFragment fragment = new EditPostPreviewFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(WordPress.SITE, site);
bundle.putSerializable(EditPostActivity.EXTRA_POST, post);
bundle.putInt(EditPostActivity.EXTRA_POST_LOCAL_ID, post.getId());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a comment to explain why we switched from putSerializable to putInt (and why we're still doing it for the site).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, after this PR what I was going to suggest is we remove the putSerializables as much as possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and I disagree. We use putSerializable because we want to avoid passing ids, especially we want to avoid confusion with remote and local ids.

Copy link
Contributor Author

@oguzkocer oguzkocer May 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because we want to avoid passing ids

Can you elaborate on this? I am just curious about it. Because, we can avoid the confusion about the remote & local ids issue by just explicitly naming them like EXTRA_POST_LOCAL_ID or EXTRA_POST_REMOTE_ID. It's no more confusing than having the remote and local id versions of getters in our stores.

In general I thought it was better to pass the ids, especially to avoid crashes like this. I can't see what we get out of passing the serializable except for maybe convenience.

Please note that I am not against it, I just want to better understand it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's no more confusing than having the remote and local id versions of getters in our stores.

In the stores, we don't really have the choice because remote ids can't be unique. So we make that distinction (remoteId vs localId) to avoid any ambiguity.

But here in the app, we want to hide this and make it easier for developers. If we can avoid any id, that's even better. But in some cases (like here) we don't really have the choice.

Also note: when FluxC is complete, we will never see any remote id in the app - we currently have some because we still have REST calls not going through FluxC.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, once that's done we can actually start using the ids instead? That's good news!

Do you mind either committing that comment you mentioned or writing it here? I am still unsure what to write there. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since PostModel objects can be quite large, in order to avoid issues like TransactionTooLargeException it's better to pass the id of the post. However, we still want to keep passing the SiteModel to avoid confusion around local & remote ids.

@maxme Would a comment like the above one work for what you had in mind?

public class EditPostPreviewFragment extends Fragment {
@Inject PostStore mPostStore;
Copy link
Contributor

@aforcier aforcier May 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to need to inject this fragment into the AppComponent, otherwise mPostStore will always be null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was pretty sure I was missing something in that Fragment. Fixed in cd12939 thanks @aforcier!

@oguzkocer
Copy link
Contributor Author

I forgot the add a note about this in the original description, but the reason I am not reverting the changes in #5698 is because this crash might be occurring in multiple places in our app and until we know all crashes are gone, I'd like to keep the changes for it. Once it's resolved, I think we should attempt to revert that change and maybe others in the future to keep the code clean.

@maxme
Copy link
Contributor

maxme commented May 11, 2017

Note: if we want this in 7.4, we have to change the targeted branch.

@oguzkocer
Copy link
Contributor Author

Note: if we want this in 7.4, we have to change the targeted branch.

@maxme I'd feel better if we still merged it into develop and target 7.5 instead as explained below. I hate to do this for a crash but I just don't want to introduce more crashes. I leave the decision to you though.

Originally, I was working on the release/7.3 branch for this, so we could fix it asap. However, I believe this fix looks deceptively simple yet can cause some unseen issues, so I think it's just safer to target develop. We don't want to introduce more crashes while trying to fix one.

@maxme maxme removed this from the 7.4 milestone May 12, 2017
@maxme
Copy link
Contributor

maxme commented May 12, 2017

@maxme I'd feel better if we still merged it into develop and target 7.5 instead as explained below.

Ok, I removed the milestone.

@maxme maxme self-assigned this May 12, 2017
@oguzkocer
Copy link
Contributor Author

Just a reminder that this PR is still ready to be reviewed/merged! I just merged develop into the PR since there was a conflict. This comment is waiting feedback from @maxme and the last commit cd12939 is waiting to be reviewed by @aforcier.

I'd suggest us to merge this in as soon as possible, since it's hopefully fixing a crash.

updateSiteOrFinishActivity(savedInstanceState);
}

private void updateSiteOrFinishActivity(Bundle savedInstanceState) {
if (savedInstanceState == null) {
if (getArguments() != null) {
mSite = (SiteModel) getArguments().getSerializable(WordPress.SITE);
mPost = (PostModel) getArguments().getSerializable(EditPostActivity.EXTRA_POST);
mPost = mPostStore.getPostByLocalPostId(getArguments().getInt(EditPostActivity.EXTRA_POST_LOCAL_ID));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serializing and de-serializing the post as this used to do keeps the same reference to the post. Doing it this way creates a new object, which is not updated as mPost is updated in the EditPostActivity. As a result the preview will always show the post as it was when opened (for new posts, the preview is always blank). The loadPost() method will have to account for this.

@aforcier
Copy link
Contributor

@oguzkocer we should probably do the same thing for EditPostSettingsFragment - and I suspect this issue will have to be addressed there too.

@aforcier aforcier self-assigned this May 23, 2017
@oguzkocer
Copy link
Contributor Author

@aforcier The reason I didn't do the same thing in EditPostSettingsFragment was the issue you raised in EditPostPreviewFragment (I missed that one). Especially on the settings page, things could get really complicated if we don't keep a reference to it.

So, what I propose to do is, when post is passed to these fragments, we should use the id and get the post from the PostStore. For the config changes, we should just keep a reference to the object as I think this crash only occurs for when it's passed with intents, so we should be safe. What do you think?

@aforcier
Copy link
Contributor

For the config changes, we should just keep a reference to the object as I think this crash only occurs for when it's passed with intents, so we should be safe. What do you think?

I'm not sure I fully grasp the underlying issue, but it seems like the crash can happen whenever 'too much' data is passed in a Binder transaction, and my understanding is that that would also apply to the bundle usage in onSaveInstanceState(). So I'm not sure we can get away with fixing the crash without having to manage a separate PostModel reference in the fragments.

@@ -60,15 +58,11 @@ private void updateSiteOrFinishActivity(Bundle savedInstanceState) {
if (savedInstanceState == null) {
if (getArguments() != null) {
mSite = (SiteModel) getArguments().getSerializable(WordPress.SITE);
mPost = mPostStore.getPostByLocalPostId(getArguments().getInt(EditPostActivity.EXTRA_POST_LOCAL_ID));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change this fragment no longer needs PostStore - we can drop that injection and remove EditPostPreviewFragment from the AppComponent.

@oguzkocer oguzkocer force-pushed the crash/transaction-too-large-exception branch from b963513 to 5adf5dc Compare May 31, 2017 20:07
@aforcier
Copy link
Contributor

Looks good to me - but perhaps we should still add a comment like this one to explain why we're passing by ID in this case? Maybe in ActivityLauncher? What do you think @maxme?

@oguzkocer
Copy link
Contributor Author

I have added that comment with a slight change (confirmed by @maxme) to ActivityLauncher as you suggested @aforcier since the original change it was suggested for is removed. Should be ready to go now!

Thank you both!

@aforcier
Copy link
Contributor

aforcier commented Jun 1, 2017

:shipit:

@aforcier aforcier merged commit 9fa1680 into develop Jun 1, 2017
@aforcier aforcier deleted the crash/transaction-too-large-exception branch June 1, 2017 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash: TransactionTooLargeException
3 participants