Skip to content
Easy and intuitive pattern for Android
Branch: master
Clone or download
Bansook Nam
Bansook Nam fix readme
Latest commit 4577334 Apr 5, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github/ISSUE_TEMPLATE Update issue templates Feb 28, 2019
doc
gradle/wrapper
sample rename some feilds, Mar 25, 2019
svc-annotation add javadoc for maven central. Mar 27, 2019
svc-compiler add javadoc for maven central. Mar 27, 2019
svc add javadoc for maven central. Mar 27, 2019
.gitignore first commit from svcConcept May 19, 2018
.travis.yml added travis ci configuration Mar 19, 2019
LICENSE
README.md
build.gradle 1.0.0 release Apr 5, 2019
dependencies.gradle change to kt maker. Mar 23, 2019
gradle.properties
gradlew first commit from svcConcept May 19, 2018
gradlew.bat first commit from svcConcept May 19, 2018
settings.gradle qualifier annotations divided as svc-annoation module Mar 14, 2019
spotless.gradle modified java indentation against 4 & removed useless codes Mar 18, 2019
spotless.license.kt added spotless gradle & license gradle Mar 15, 2019
versionsPlugin.gradle added gradle version plugin Mar 18, 2019

README.md

SVC

License Download API Build Status
🚀 Easy and intuitive pattern library for Android.

Why SVC?

MVP and MVVM use Fragment or Activity as "VIew"

So when we write code inside the Fragment or Activity, codes are getting mixed with "View" code and "Screen Code" such as onCreate,onCreateView, onViewCreated or onSaveInstanceState, onRestoreInstanceState .onActivityResult etc.

It makes hard to see each "View Logic" and "Screen Logic"

And the most important thing is that "Business Logic" can be included in the "View"(Fragment, Activity) easily.

It's because Activity, Fragments are actually "Control Tower" (control lifecycle and receives view events)

SVC gives the way how to divide Screen, View and Business Logic.

For more read check article below

  1. 4 reasons why MVP is not good enough https://medium.com/@bansooknam/intro-svc-the-better-pattern-against-mvp-138e6e790bbc

  2. Detail concept of SVC https://medium.com/@bansooknam/svc-the-better-pattern-against-mvp-66e6d342a23f

Ps. It can be used with ViewModel as Well. you can check Examples here below.
https://github.com/BansookNam/android-architecture
https://github.com/BansookNam/svc-lotto

How to implement

  1. For activity and fragment for the screen, should inherit the SVC_{name of screen class} class.
  2. Add screen annotations SvcActivity, SvcFragment, SvcDialogFragment.
  3. And declare RequireControlTower, RequireViews annotation above the class.
  4. Build you project, then SVC_{YourScreen} class will be generated automatically by svc processor.

1. Activity

@SvcActivity
@RequireViews(MainViews::class)
@RequireControlTower(MainControlTower::class) // magic things do happening
class MainActivity : SVC_MainActivity() { // SVC_MainActivity will be generated after build project.
  //extend SVC_{name of class}
}

2. Fragment

@SvcFragment
@RequireViews(StatisticViews::class)
@RequireControlTower(StatisticControlTower::class) // magic things do happening
class StatisticFragment : SVC_StatisticFragment() { // SVC_StatisticFragment will be generated after build project.
   //extend SVC_{name of class}
}

3. DialogFragment

@SvcDialogFragment
@RequireViews(SampleActionViews::class)
@RequireControlTower(SampleActionControlTower::class)
@RequireListener(SampleActionDialogListener::class) //listener from another screen.
class SampleActionDialog : SVC_SampleActionDialog() { // SVC_SampleActionDialog will be generated after build project.
    //extend SVC_{name of class}
}

Examples of ControlTower

  1. For controlTower, should inherit the SVC_{name of controlTower class} class.
  2. Declare annotations ControlTower.
  3. Declare RequireScreen, RequireViews annotation above the class.
  4. Build you project, then SVC_{YourControlTower} will be generated automatically by svc processor.

1. ControlTower

@ControlTower
@RequireViews(StatisticViews::class)
@RequireScreen(StatisticFragment::class) //screen which this controlTower will be used.
class StatisticControlTower : SVC_StatisticControlTower(), StatisticViewsAction { 
    //extend SVC_{name of class}
    //implement ViewsAction which 'Views' is needed.
}

2. ControlTower (Abstract screen use)

@ControlTower
@RequireViews(CommonViews::class)
@RequireScreen(CommonScreen::class) //abstract screen is available to declare. (CommonScreen is interface)
class CommonControlTower : SVC_CommonControlTower(), CommonViewsAction {
    //extend SVC_{name of class}
    //implement ViewsAction which 'Views' is needed.
}

You can really divide "Views" from Activity and Fragment.

so you can see logic about real Fragment and Activity very well like below. (source link)

@SvcActivity
@RequireViews(TaskDetailViews::class)
@RequireControlTower(TaskDetailCT::class)
class TaskDetailActivity : SVC_TaskDetailActivity() {

    var taskId: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        /**
         * we should set taskId before super onCreate
         * because createControlTower will be called on super.onCreate()
         * and taskId is non null String type in constructor of TaskDetailCT
         */
        taskId = intent.getStringExtra(EXTRA_TASK_ID)

        super.onCreate(savedInstanceState)
    }

    override fun onSupportNavigateUp(): Boolean {
        onBackPressed()
        return true
    }


    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        val deletePressed = item.itemId == R.id.menu_delete
        if (deletePressed) ct.deleteTask()
        return deletePressed
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.taskdetail_fragment_menu, menu)
        return true
    }

    fun startEditTastActivity(taskId: String) {
        val intent = Intent(this, AddEditTaskActivity::class.java)
        intent.putExtra(AddEditTaskActivity.ARGUMENT_EDIT_TASK_ID, taskId)
        startActivityForResult(intent, REQUEST_EDIT_TASK)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == REQUEST_EDIT_TASK) {
            // If the task was edited successfully, go back to the list.
            if (resultCode == Activity.RESULT_OK) {
                setResult(Activity.RESULT_OK)
                finish()
            }
        }
    }

    fun finishAfterDelete() {
        setResult(Activity.RESULT_OK)
        finish()
    }

    companion object {
        const val EXTRA_TASK_ID = "TASK_ID"
        const val REQUEST_EDIT_TASK = 1
    }

}

Definition of “SVC”

Each alphabet stands for.

S — Screen

V — Views

C — Control Tower

+In addition

ViewsAction — Contains user interaction method which "Views" can produce. and Control Tower should know (such as click, swipe, drag..)

Diagram

1. SVC

diagram

  1. Each "Screen" has "Views" and "ControlTower".
  2. "Views" don't know "ControlTower" directly. It knows "ControlTower" as "ViewsAction"
  3. "ControlTower" knows "Views"'s public methods and fields.
  4. Each "Views" and "ControlTower" has "Screen"

2. MVP, MVVM

diagram

diagram

When we use MVP or MVVM, "View"(which is implemented on Activity, Fragment) can easily get Bigger with lots of responsibility. It has 3 main responsibility.

  1. Screen logics
  2. View logics
  3. Control tower logics (access directly to Mediator "Presenter" or "ViewModel")

And both MVP, MVVM can call Business logics of Mediator directly.

3. SVC with Model

3-1. SVC-M (similar with MVP)

diagram

As same as MVP, Mediator("ControlTower") comunicated with Model.

It's exactly same.

3-2. SVC-VM-M type 1

diagram

We can use ViewModel in ControlTower to take advantage of "Auto Lifecycle Management". We use ControlTower as Mediator and ViewModel as data holder. In this type, ControlTower has Repositories and manage the datas

3-3. SVC-VM-M type 2

diagram

Similar with type1, however in this architecture ViewModel has Repositories and manage the data. You can design in type2 in case of Repository can independently divided with ControlTower. ViewModel will contain data change methods.

4. Difference between MVP,MVVM vs SVC

There are 2 big differences.

  1. SVC divides "View"'s 3 responsibilities into 3 parts, which is Screen, ControlTower, Views
  2. "Views" cannot call "Control Tower" directly. (Because "Views" knows "ControlTower" as "ViewsAction")

With this 2 big differences. We can

  1. Prevent "View" from being "God View"
  2. We can see well divided logics.
  3. When we write "View" logic we don't need to think about business logics.
  4. We don't need to make duplicated methods by interfaces (compare to MVP)
  5. We don't need to observe commands with parameter (compare to MVVM)
  6. We can use same "Views" in "A Activity" and "B Fragment". (reusable. ex-CommonViews from sample)
  7. We can understand intuitively with clear naming.

Include on your project

Download

1. Project Top Build.gradle

Packages are available in jcenter

Include below in your top build.gradle file

allprojects {
    repositories {
        jcenter() //add this line
    }
}

2. Application Build.gradle

Include below in your "application" build.gradle file

apply plugin: 'kotlin-kapt'


implementation "com.naver.android.svc:svc:1.0.0"
kapt "com.naver.android.svc:svc-compiler:1.0.0"

3. Done! You can use it!

4. Svc-template can makes "works" easier

Github Link: https://github.com/naver/svc-template

If you want to create Activity, Fragment, DialogFragment quickly. Try SvcTemplate.

  1. clone https://github.com/naver/svc-template.git

  2. run shell script through command line. (Terminal in mac)./install.sh

  3. restart Android Studio

  4. right click, and use "SVC" - "SVC ***" svcTemplate

  5. write screen name, author then click "Finish". svcTemplate2 svcTemplate3
    You will see "Unresolved Reference" error.

  6. click "Build" - "Rebuild Project" This will create "SVC_{component}" based on annotations. svcTemplate4

  7. **Done! Happy coding!

Reuse of Views and ControlTower

"Views" and "ControlTower" can be reused in different Screens. (It means it has same look or same viewsAction and proccess)

  1. Views you can easily reuse "Views" in this pattern

  2. ControlTower If you want to reuse you should implement your screen as "Screen"or make "Abstract Screen (implements Screen)" with common methods then refer the "Abstract Screen" on your reused "Views" or "ControlTower".

License

SVC is licensed under the Apache License, Version 2.0. See LICENSE for full license text.

Copyright 2018 NAVER Corp.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
You can’t perform that action at this time.