svc
Deprecated
It will be sustained on git below.
https://github.com/BansookNam/svc
:rocket: 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
4 reasons why MVP is not good enough https://medium.com/@bansooknam/intro-svc-the-better-pattern-against-mvp-138e6e790bbc
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
- For activity and fragment for the screen, should inherit the
SVC_{name of screen class}
class. - Add screen annotations
SvcActivity
,SvcFragment
,SvcDialogFragment
. - And declare
RequireControlTower
,RequireViews
annotation above the class. - 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
- For controlTower, should inherit the
SVC_{name of controlTower class}
class. - Declare annotations
ControlTower
. - Declare
RequireScreen
,RequireViews
annotation above the class. - 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
- Each "Screen" has "Views" and "ControlTower".
- "Views" don't know "ControlTower" directly. It knows "ControlTower" as "ViewsAction"
- "ControlTower" knows "Views"'s public methods and fields.
- Each "Views" and "ControlTower" has "Screen"
2. MVP, MVVM
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.
- Screen logics
- View logics
- 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)
As same as MVP, Mediator("ControlTower") comunicated with Model.
It's exactly same.
3-2. SVC-VM-M type 1
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
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.
- SVC divides "View"'s 3 responsibilities into 3 parts, which is Screen, ControlTower, Views
- "Views" cannot call "Control Tower" directly. (Because "Views" knows "ControlTower" as "ViewsAction")
With this 2 big differences. We can
- Prevent "View" from being "God View"
- We can see well divided logics.
- When we write "View" logic we don't need to think about business logics.
- We don't need to make duplicated methods by interfaces (compare to MVP)
- We don't need to observe commands with parameter (compare to MVVM)
- We can use same "Views" in "A Activity" and "B Fragment". (reusable. ex-
CommonViews
from sample) - We can understand intuitively with clear naming.
Include on your project
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 *"
5) write screen name, author then click "Finish".
You will see "Unresolved Reference" error.
6) click "Build" - "Rebuild Project" This will create "SVC_{component}" based on annotations.
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.