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

Feature/particles view update #375

Merged
merged 7 commits into from Feb 25, 2017

Conversation

eneim
Copy link
Contributor

@eneim eneim commented Feb 21, 2017

IMPORTANT:

  • I commented out some lines in SplashActivity to make the sample, please read it and un-comment for normal behaviour.
  • I'm using AS RC-1 so please manually change gradle plugin back to 2.2.3, or I will do it after the review.

Issue

  • Current ParticlesAnimationView is beautifully implemented. But it comes with some trade off as follow:
    • Redundant Object allocation inside onDraw method: createLines(particles) uses Stream which will allocate new Iterators each calls. Furthermore it unnecessarily generates new Lines.
    • "Random" should be used once only to ensure the randomness of number. See its doc for more detail.
    • Current implementation of createLines(particles) will draw each line twice, which is not so good.
    • Calling drawLines to draw a single line is not so good too.
    • Private classes can be Private static class, to prevent leak (not now, just in case).

Overview: what I did

  • Make private class (Particle, Line) static.
  • Re-implement Line class, fix some step in Particle class that would allocate new objects in onDraw().
  • Cache necessary objects as ParticlesAnimationView's member, and just update them if need (see Random instance, List instance for example).
    • This fix reduce the number of Line instance from few thousands (数万 lines in some cases) to 780 (= C(40, 2)) (see my comment).
  • Improve onDraw and so on. Stream is no longer used here ...
  • isShouldLinked is actually shouldBeLinked I think :D.

Discussion: so it worth the change?

  • Current View is shown in few seconds, so there may be no need to do redundant work.
  • But ... some may want to use it as Cover background, or Title view etc, so improving it here can help.
  • See screenshot for more information (see number of GC calls, magenta (or blue?) in GPU log ...) (sorry don't know how to align 2 screenshot horizontally, please help).

Screenshot

Before After
screen shot 2017-02-21 at 23 55 34
screen shot 2017-02-21 at 23 59 15

Takt.stock(getApplication())
.seat(Seat.BOTTOM_RIGHT)
.interval(250)
.listener(fps -> Log.w("DroidKaigi", "heartbeat() called with: fps = [" + fps + "]"))
Copy link
Contributor

Choose a reason for hiding this comment

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

[Android Lint] reported by reviewdog 🐶
Error: Using 'Log' instead of 'Timber' [LogNotTimber]

…actually un-comment the normal way. some type and grammar fix
@konifar
Copy link
Contributor

konifar commented Feb 21, 2017

Thank you for contribution! Interesting!

@eneim
Copy link
Contributor Author

eneim commented Feb 22, 2017

Thanks. Let me fix the license and conflict in few minutes :D

@eneim
Copy link
Contributor Author

eneim commented Feb 22, 2017

FYI @konifar I would like to ask @roana0229 (author of this View) to review this if possible. My change may conflict with the expected behaviour in some unexpected ways.

@@ -226,6 +226,9 @@ dependencies {
debugCompile 'com.tomoima.debot:debot:2.0.2'
releaseCompile 'com.tomoima.debot:debot-no-op:2.0.2'

// fps, track the frame rate of animation view.
compile 'jp.wasabeef:takt:1.0.3'
Copy link
Contributor

Choose a reason for hiding this comment

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

🆒

@@ -52,12 +54,24 @@ protected void onCreate(Bundle savedInstanceState) {
protected void onStart() {
super.onStart();
loadSessionsForCache();

// Starting new Activity normally will not destroy this Activity, so set this up in start/stop cycle
// TODO remove it if you hate it ...
Copy link
Contributor

@konifar konifar Feb 23, 2017

Choose a reason for hiding this comment

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

I like it. So let's remove this TODO comment 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just push a commit to remove the TODO :D.


private class Line {
/**
* A Pair of 'Particles' whose centers can be 'linked to each other ... Called 'Line'.
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome! 👍

@konifar
Copy link
Contributor

konifar commented Feb 23, 2017

Looks good. Thanks 😃
@roana0229 Can you review this?

@eneim
Copy link
Contributor Author

eneim commented Feb 23, 2017

@konifar my latest commit cause a failed build on circleci, checking it, turns out :app:testDevelopDebugUnitTest failed with one case. But running it on my machine passes all tests. Can you manually trigger a rebuild? If it keeps failing again I will try to figure out what happened.

@konifar
Copy link
Contributor

konifar commented Feb 23, 2017

Sorry, currently CI is not stable. I'll work on it tonight.

@eneim
Copy link
Contributor Author

eneim commented Feb 23, 2017

Thanks, just take your time :D

Copy link
Contributor

@roana0229 roana0229 left a comment

Choose a reason for hiding this comment

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

Thank you for improving performance! Awesome 👍
I learned from this PR. 😄


private class Line {
/**
* A Pair of 'Particles' whose centers can be 'linked to each other ... Called 'Line'.
Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome! 👍

+ (point[3] - point[1]) * (point[3] - point[1])
));
void draw(Canvas canvas, Paint paint) {
if (!first.shouldBeLinked(LINK_HEXAGON_DISTANCE, second)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

In my opinion, shouldBeLinked is not necessary if first particle compare second particle in draw.

Copy link
Contributor Author

@eneim eneim Feb 24, 2017

Choose a reason for hiding this comment

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

@roana0229 not really get your full point, but do you mean to call shouldBeLinked from ParticlesAnimationView#onDraw instead of here? It will end up removing the need of using "Line" object (a Line is actually just a bridge between 2 particles :D).

Yesterday I thought about something like:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0, size = particles.size(); i < size; i++) {
            particles.get(i).draw(canvas, paint);
        }

        // for (int i = 0, size = lines.size(); i < size; i++) {
        //    lines.get(i).draw(canvas, paint);
        //}

        for (int i = 0; i < particles.size() - 1; i++) {
            for (int j = i + 1; j < particles.size(); j++) {
                if (particles.get(i).shouldBeLinked(LINK_HEXAGON_DISTANCE, particles.get(j))) {
                    // TODO draw, use the code from Line
                }
            }
        }
    }

I think what you mean is the following:

    // ParticlesAnimationView
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0, size = particles.size(); i < size; i++) {
            particles.get(i).draw(canvas, paint);
        }

         for (int i = 0, size = lines.size(); i < size; i++) {
             if (lines.get(i).shouldDraw()) {
                 lines.get(i).draw(canvas, paint);
             }
        }
    }

    // ParticlesAnimationView$Line
    ///// shouldDraw simply returns the comparison
    boolean shouldDraw() {
        return first.shouldBeLinked(LINK_HEXAGON_DISTANCE, second);
    }

Neither of above gain any huge impact (but the later looks clean and better, in fact :D). For now I would like to keep current version (this PR is pretty huge now) and maybe another PR from you if you really want to :p. So it is up to you ^^.

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought that the following code was good.

For now I would like to keep current version (this PR is pretty huge now) and maybe another PR from you

OK! 😄

@roana0229
Copy link
Contributor

LGTM 👍

@konifar
Copy link
Contributor

konifar commented Feb 25, 2017

Thanks for improvement!

@konifar konifar merged commit 2f107da into DroidKaigi:master Feb 25, 2017
@eneim eneim deleted the feature/particles-view-update branch February 26, 2017 04:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants