Android ئەپ ئېچىشتا MVP ئەندىزىسى ھەققىدە(1)

Views: 678 4 باھا /

Android ئەپ ئېچىشتا سۇپا ئالاھىدىلىكىگە ئاساسەن، ئىلگىرى كۆپ ھاللاردا MVC ئەندىزىسى(模式) قوللىنىپ كەلگەن. بىراق كۆچمە ئەپلەرنىڭ تىز ئومۇملىشىشى شۇنداقلا ئىقتىدار جەھەتتە بارغانسىرى مۇرەككەپلىشىشگە ئەگىشىپ، كىلاسسىك MVC ئەندىزىسى بۇ جەھەتتىكى ئىھتىياجنى قامدىيالماي قالدى. شۇنىڭ بىلەن كۆچمە ئەپلەرگە، جۈملىدىن Android قا خاس بولغان MVP ئەندىزىسى ئۇنىڭ ئورنىنى ئېلىشقا باشلىدى. بۇ يازمىمىزدا نەزەرىيە بىلەن ئاددىي مىسالنى بىرلەشتۈرۈپ، MVP ئەندىزىسى بىلەن دەسلەپكى قەدەمدە تونۇشۇپ چىقىمىز.
MVP ئەندىزىسى(Model-View-Presenter) - ئەمەلىيەتتە MVC ئەندىزىسى (Model-View-Controller) نىڭ Android سۇپىسىغا ماسلىشىپ ئۆزگەرتىلىشىنىڭ ھاسىلاتى. MVC نى پىروگرامما بىلەن تونۇشىدىغانلارنىڭ ھەممىسى ئاڭلاپ باقمىغاندىمۇ، ئىشلىتىپ باققان بولۇشى مۇمكىن. MVP بىلەن تونۇشۇشتىن بۇرۇن يەنىلا MVC نىڭ ئالاھىدىلىكىنى بىر ئەسلەپ ئۆتۈشىمىزگە توغرا كېلىدۇ.

MVC ئەندىزىسى

20150523132020239

سېخىما رەسىمىدە ئىپادىلەنگىنىدە:

  • View قىسمى: ئەمەلىيەتتە ئەپنىڭ UI قىسمىدىن ئىبارەت. ئابونىت كۆرۈنمە يۈزى، كونۇپكا، كىرگۈزۈش رامكىسى ۋە شۇنىڭدەك باشقا ئېلمىنىتلار موشۇ قىسمىدا بىر بىرتەرەپ قىلىنىدۇ
  • Model قىسمى: يەنى JavaBean ئەمەلىي تۈرلىرى(实体类) دىن ئىبارەت. مەلۇماتلارنى ئوبىكت ھالىتىدە ساقلاشقا ئىشلىتىلىدۇ
  • Controller قىسمى: ئەپ كۆرۈنمە يۈزى ۋە ئوبىكتلارنى يېڭىلاش، قىسقىسى View بىلەن Model نىڭ مۇناسىۋىتىنى باشقۇرۇش رولىنى ئۆتەيدۇ

مەسىلەن: View قىسمىدا، ئابونىت ئىشلەتكۈچى نامى ۋە پارولنى تولدۇرۇپ، "كىرىش" كونۇپكىسىنى باسقاندىن كېيىن كىرىش لوگىكىسى يۈرگۈزۈلۈپ، نەتىجىسى Controller ئارقىلىق مۇناسىپ Model غا ئۆتكۈزۈلىدۇ. شۇنىڭدەك ، Model نىڭ قىممىتى ئۆزگەرگەن ھامان يەنە Controller ئارقىلىق UI يېڭىلىنىپ، كىرىش كۆزنىكىدىن ئاتلاپ ئۆتىدۇ(ئادەتتە View قىسمىدا Model نىڭ قىممەتلىرىنى ھەر قېتىم Controller ئىشلەتمەي، بىۋاستە ئۆزگەرتىشكىمۇ بولىدۇ، بۇ بەزى ئاددى لوگىكىلىق قىممەت يېڭىلاش ئىشلىرىنى كۆپ قولايلىقلاشتۇرىدۇ. لېكىن مۇرەككەپ ئەھۋالدا Controller ۋە View قىسىملىرىدا Model ئۆزگەرتكەندە، تېخىمۇ مۇرەككەپلىك كەلتۈرۈپ چىقىرىدۇ).
يەنە مەسىلەن: ئەپ يۈزىدە قار ئۇچقۇنداۋاتقان، ئىكىراننىڭ خالىغان يىرىنى چەككەندە، قار ئۇچقۇنلىرى ئەتىراپقا كېڭىيىدىغان بىر ئۈنۈمنى چىقارماقچى بولدۇق دەيلى. ئاۋۋال Snow نامىدا X,Y كوردىنات قىممىتىنى ئۆز ئىچىگە ئالغان بىر Model قۇرىۋالىمىز. SurfaceView دىن بىرىنى View قىسىمىغا قويۇپ، قار ئۇچقۇنلىرىنى سىزىدىغان كۆزنەك قىلىمىز. ئاندىن بىر ئارقا سۇپا لىنىيەسى(后台线程) قوزغىتىپ، Snow نىڭ X,Y قىممەتلىرىنى رېتىملىق ئۆزگەرتىپ بېرىمىز.ئەلۋەتتە، بۇ ۋەزىپىلەرنى Controller ئۈستىگە ئالىدۇ. ئاندىن يەنە Controller ئارقىلىق SurfaceView نى يېڭىلاپ، قار ئۇچقۇنلىرىنى ھەرىكەتلەندۈرسەكلا بولىدۇ. يەنىمۇ ئىچكىرلىگەن ھالدا، SurfaceView دە چېكىلىش ھادىسىسىنى نازارەت قىلىپ، ئىكىراننىڭ خالىغان يىرى چېكىلگەندە، Controller ئارقىلىق Snow مودىلنىڭ كوردىناتلىرىنى مۇناسىپ ئۆزگەرتىش ئارقىلىقلا، ئىكىراننى چەككەندە قار ئۇچقۇنلىرى ئەتىراپقا كىڭىيىدىغان ئۈنۈمنى چىقارغىلى بولىدۇ.

MVP ئەندىزىسى

يۇقىرىدا بىر قەدەر كىلاسسىك بولغان MVC ئەندىزىسىنى ئەسلەپ ئۆتتۇق. ئەمەلىيەتتە، چوڭراق بىر ئەپ نۇرغۇنلىغان Activity ۋە Fragment لەردىن تەشكىل تاپىدۇ، ھەمدە كەسىپ لوگىكىسىمۇ(业务逻辑) كۆپ مۇرەككەپ بولىدۇ. MVC نىڭ تەلىپى بويىچە بارلىق Activity ۋە Fragment لەر View قىسمىغا تەۋە بولۇپ، كۆرۈنمە يۈز تەشكىللەش، ئىشلەتكۈچى كىرگۈزگەن مەلۇماتلارنى قوبۇللاش ۋە بىر قاتار ئاكتىپلىق دەۋرىيلىكى(生命周期) لارنى بىرتەرەپ قىلىش قاتارلىق مەشغۇلاتلار بىراقلا Activity ياكى Fragment لەر ئىچىدە بولىدۇ. يەنە كېلىپ، Activity بولسا Android ئەپ ئېچىشتا ئىنتايىن مۇھىم ئامىل. بولۇپمۇ ئۇنىڭ ئاكتىپلىق دەۋرىيلىكى بىۋاستە ئەپنىڭ مۇقىملىقىغا تەسىر كۆرسىتىدۇ. شۇڭا ئادەتتە بىر قىسىم كەسىپ لوگىكىلىرىنىمۇ بىۋاستە Activity ئىچىگە يېزىشقا مەجبۇر بولىمىز. ئاقىۋەتتە، Activity بارغانچە مۇرەككەپلىشىپ، كود قۇر سانى 1000 دىن ئېشىپ كېتىش نورمال ھادىسىگە ئايلىنىپ قالىدۇ. يەنە كېلىپ، بىر قىسىم تەكرار ئىشلىتىشكە بولىدىغان لوگىكا(مەسىلەن: كىرىش، تىزىملىتىش) لارمۇ Activity ئىچىگە يېزىلغانلىقتىن، باشقا جايلاردا تەكرار ئىشلىتىشكە ئامالسىز قالىمىز. بىر Activity ئىچىگە يېزىلغان كود 1000 قۇردىن ئىشىپ كەتكەندە ھەقىقەتەنمۇ نورمال بولماي قالىدۇ، ئازراق تۈر تەجىربىسى بار ئادەم بۇنداق كودنى كۆرگەندە چوقۇم قايتا رەتلەشنى ئويلاشماي قويمايدۇ.بۇنىڭلىق بىلەن : Activity ۋە Fragment لەر ئەسلىدىكى View لىق خاسلىقىدىن ھالقىپ، Controller نىڭ بىر قىسىمىنىمۇ ئۆز ئىچىگە ئېلىپ كېتىشى مۇمكىن. دېمەك، V بىلەن C ئىرماش - چىرماش بولۇپ كەتتى. بۇخىل ئەھۋالدا گەرچە ۋاقتىنچە ئىقتىدارنى ئەمەلگە ئاشۇرۇپ،كۆزلىگەن مەقسەتكە يەتكەن بولساقمۇ، كېيىن ئەپ ئىقتىدارىدىكى ئازراقلا تەڭشىلىش بىزگە زور ئاۋارىچىلىق ئەكىلىدۇ. ھەتتا بەزى قىسىملىرىنى قايتا يېزىشقا توغرا كېلىدۇ. بۇ مەسىلىلەرنى ھەل قىلىش ئۈچۈن View ۋە Contoller نىڭ مۇناسىۋەت پاسىللىرىنى ئېنىق ئايرىيدىغانغا MVP ئەندىزىسى بارلىققا كەلدى.

2114527

MVP نىڭ يادرولۇق ئىددىيەسى:

MVP ئەندىزىسى Activity لەر ئىچىدىكى UI لوگىكىسى(Activity ئاكتىپلىق دەۋرىيلىكى، ھادىسە قاتارلىقلار...) نى View ئىغىزى (接口) غا، كەسىپ لوگىكىسى(业务逻辑) نى Presenter ئىغىزىغا ئابىستراكىتلاشتۇرۇپ (抽象化) بېرىدۇ. Model يەنىلا ئەسلىدىكىگە ئوخشاش بولىدۇ.

مانا بۇ بىز چۈشەنمەكچى بولغان MVP دىن ئىبارەت. بۇ بويىچە بولغاندا Activity نىڭ ۋەزىپىسى كۆپ ئاددىيلىشىدۇ. پەقەت ئاكتىپلىق دەۋرىيلىكىگە مۇناسىپ ئىنكاس بىلدۈرۈپ، قالدى ئىشلارنى Presenter نىڭ بىر تەرەپ قىلىشىغا تاپشۇرۇپ بەرسىلا بولدى. يۇقىرىقا رەسىمدە كۆرسىتىلگەندەك، Presenter بولسا View بىلەن Model ئوتتۇرىسىدىكى كۆۋرۈكتىن ئىبارەت. قۇرۇلمىنىڭ تەرتىپلىك ۋە ئاددى بولۇشى ئۈچۈن، View قىسمىدا بىۋاستە Model بىلەن ئالاقە قىلالمايدۇ. بۇ ھەم MVP نىڭ MVC دىن ئەڭ چوڭ پەرقلىرىنىڭ بىرىدۇر.

MVP ئەندىزىسىنىڭ رولى

MVC نى شاللىۋىتىپ، ئورنىغا دەسسىيەلىگەن ئىكەن MVP نىڭ چوقۇم ئۆز ئالاھىدىلىكلىرى بولىدۇ:

  • UI لوگىكىسى بىلەن كەسىپ لوگىكىسىنى ئايرىپ چىقىپ، ئۆزئارا باغلىنىش(耦合) دەرىجىسىنى تۆۋەنلىتىدۇ(يەنى: M+V+P ئۈچ قىسىمنىڭ ئۆز ئارا باغلىنىشچانلىقى تۆۋەنلەپ، خالىغان بىرسىگە ئۆزگەرتىش كىرگۈزگەندە قالغان ئىككىسىگە بىۋاستە كۆرسىتىدىغان تەسىرى تۆۋەنلەيدۇ).
  • Activity پەقەت ئاكتىپلىق دەۋرىيلىكىنى بىر تەرەپ قىلسىلا بولىدىغان، مۇرەككەپلىكتىن خالىي بولىدۇ
  • كۆرۈنمە يۈز ۋە كەسىپ لوگىكىسى ئايرىم ھالدا View ۋە Presenter ئىغىزىغا مەۋھۇملاشتۇرۇلۇپ، كودلار ئېنىق ۋە چۈشىنىشلىك بولىدۇ
  • Presenter ئىغىزغا مەۋھۇملاشتۇرۇلغانلىقتىن، كۆپ خىل ھالەتتە ئەمەلگە ئاشۇرۇشقا(实现) بولىدۇ، دېمەك بۆلەك سېنىقى(单元测试) قىلىشقا كۆپ قولايلىق بولىدۇ.
  • باشقىلار .......

Activity نى ئاددىيلاشتۇرىدۇ

ئادەتتە تۈر ئەسلى كودىنى كۆرۈشكە(ئوقۇشقا) توغرا كەلگەندە نۇرغۇن كىشىلەر ئىشنى Activity دىن باشلايدۇ. كىلاسسىك ئۇسۇل بويىچە كود قۇر سانى 1000 دىن ئىشىپ كەتكەن Activity نى بىردەم كۆرۈپلا باش ئاغرىيدۇ،
MVP ئەندىزىسىنى ئىشلەتكەندىن كېيىن، Activity نىڭ قۇرۇلمىسى كۆپ ئاددىيلىشىپ، پەقەت بىر قىسىم FindView、SetListener ۋە Init قاتارلىق كودلار بىلەنلا چەكلىنىدۇ. قالغانلىرى Presenter نى چاقىرىپ ئىشلىتىش، ۋە View لارنىڭ مۇناسىۋەتلىك ئىغىزلىرىنى ئەمەلگە ئاشۇرۇشتىن ئىبارەت. دېمەك، Presenter قىسمىغا قارىساقلا، نۆۋەتتىكى Activity گە يۈكلەنگەن كەسىپ لوگىكىسى (业务逻辑) نى ئاسانلا چۈشۈنۈپ كېتەلەيمىز. Activity نى باشقۇرۇش، ئاسىراش، ھەتتا چوڭ كۆلەمدە ئۆزگەرتىش ئەھۋاللىرىدىمۇ كۆپ ئاۋارىچىلىق بولمايدۇ.

بۆلەك سىنىقى (单元测试) قىلىشقا قولايلىق

بۆلەك سىنىقىدا ئادەتتە، يېڭىدىن قوشۇلغان مەلۇم ئىقتىدار بۆلەكلىرىدە مەسىلە بار يوقلىقى ئايرىم - ئايرىم ھالدا سىناق قىلىنىدۇ. كىلاسسىك ئۇسۇل بويىچە: سىنايدىغان بۆلەكنىڭ Activity قىسمىغا تەقلىدىي سىناق كود بۆلىكى يېزىپ سىنىشىمىز، مەسىلە بار - يوقلۇقىنى ئايرىپ بولغاندىن كېيىن سىناق كود بۆلىكىنى رەسمىي كودقا ئالماشتۇرىشىمىز مۇمكىن. بىراق كېيىن ئويلىمىغان يەردىن، بۇ بۆلەكتە مەسىلە بارلىقى بايقالسا، يەنە قايتىدىن سىناق كودنى ئەسلىگە كەلتۈرۈپ، سىناق ئېلىپ بېرىشقا مەجبۇر بولىمىز( ۋاي دادام...).
MVP ئەندىزىسى بويىچە، ئەپنىڭ كەسىپ لوگىكىلىرى Presenter ئىچىدە تاماملىنىدىغانلىقى ئۈچۈن، بىز پەقەت Presenter نىڭ ئىغىزلىرى(接口) غا ۋارىسلىق قىلغان PresenterTest سىنىپى (类) دىن بىرنى قۇرۇپلا، مۇناسىپ Activity ئىچىدىكى Presenter نى PresenterTest كە ئالماشتۇرۇپ سىناق قىلساق بولىدۇ. سىناق تاماملانغاندا يەنە Presenter غا ئالماشتۇرۇپ قويىمىز. كېيىن يەنە مەسىلە بايقالسا، قايتا سىناق قىلىشتا يەنە شۇ PresenterTest كەل ئالماشتۇرۇپ سىنىساقلا بولىدۇ.

Activity ئىچىدە ئىچكى ساقلىغۇچ قېچىپ كېتىش (内存泄露) تىن ساقلانغىلى بولىدۇ

Android ئەپلىرىدە ئىچكى ساقلىغۇچ ئارتىپ كېتىش (OOM-内存溢出) ھادىسىسى كۆرۈلۈشنىڭ ئاساسلىق سەۋەبى، ئىچكى ساقلىغۇچ قىچىپ كېتىش، يەنى ياخشى باشقۇرالمىغانلىقتىن، ئىچكى ساقلىغۇچ يىتىشمەسلىكتىن ئىبارەت. ئادەتتە ئىچكى ساقلىغۇچ قىچىپ كېتىش Activity ۋە Bitmap ئىشلەتكەندە كۆپ كۆرۈلىدۇ.
كىلاسسىك ئۇسۇل بويىچە بىر توقاي بىماسقەدەملىك ۋەزىپىلەر (异步任务) بىراقلا Activity ئىچىگە قويۇلىدۇ. مەسىلەن: توردىن رەسىم يۈكلەشنى ئالساق، گەرچە بۇ مەشغۇلات بىماسقەدەمدە، ئارقا لىنىيە (后台线程) دە ئېلىپ بېرىلسىمۇ، بىراق، رەسىم يۈكلىنىپ بولغاندىن كېيىن قايتارما فۇنكىسىيە (回调函数) چاقىرىپ، رەسىمنى Activity دىكى ImageView گە قويىشىمىز لازىم. دېمەك، بۇ ۋاقىتتا ئىشلەتكۈچى نۆۋەتتىكى Activity دىن باشقىسىغا ئالمىشىپ كەتكەن تەقدىردىمۇ، رەسىم يۈكلەش ۋەزىپىسى ئارقا سەھنىدە داۋاملىشىدۇ، شۇنداقلا سېستىما رەسىمنى يۈكلىمەكچى بولغان Activity نىڭ نەقىل (引用) نى ساقلاپ قالىدۇ. دېمەك، بۇ ۋاقىتتا سېستىما ئاپتوماتىك ھالدا Activity نىڭ ئەمەلىي مىسالى (实例) نى يىغىۋالالمايدۇ (回收)

MVP ئەندىزىسىنىڭ قوللىنىلىشى

94032090

يۇقىرىقىسى ئاددىيغىنە بىر MVP ئەندىزىسىنىڭ ULM سېغىمىسى. سېخىمىدىن كۆرۈۋالغىلى بولىدۇكى: MVP ئەندىزىسىنى قوللانغاندا ئاز دېگەندىمۇ تۆۋەندىكىدەك بىر قانچە قەدەم باسقۇچلارنى بېسىشىمىزغا توغرا كېلىدۇ:
1. IPresenter ئېغىزى (接口) قۇرۇش ۋە كەسىپ لوگىكىسىغا مۇناسىۋەتلىك بارلىق ئىغىزلارنى بۇنىڭ ئىچىگە قويۇش، شۇنداقلا PresenterCompl شەكلىدە ئىغىزنى ئەمەلگە ئاشۇرۇش(بۇنىڭ ئىچىدە ئەپ ئىقتىدارلىرىنى كۆرۈشكە ۋە بۆلەك سىنىقى قىلىشقا قولايلىق).
2. IView ئېغىزى قۇرۇپ، كۆرۈنمە يۈزگە مۇناسىۋەتلىك بولغان بارلىق لوگىكىلىلارنىڭ بۇنىڭ ئىچىگە قويۇش. بۇ ئىغىز ئادەتتە مۇناسىپ بولغان Activity/Fragment لەر ئىچىدە ئەمەلگە ئاشۇرۇلىدۇ.
3. UML رەسىمدە كۆرسىتىلگىنىدەك، Activity نىڭ ئىچىدە IPresenter بولىدۇ، ئاندىن PresenterCompl نىڭ ئىچىدە يەنە IView ئېغىزى ئىشلىتىلىپ، Model غا تايانغان بولىدۇ. دىمەك، Activity ئىچىدە پەقەت IPresenter لا ئىشلىتىلىدۇ. باشقا مۇناسىۋەتلىك ئىقتىدارلارنىڭ ھەممىسى PresenterCompl ئىچىدە ئەمەلگە ئاشۇرۇلغان بولىدۇ.
4. Model قىسمى چوقۇم بولۇشى زۆرۈر ئەمەس، ئەمما View ۋە Presenter قىسىملىرى جەزمەن بولۇشى كېرەك.
يۇقىرىقى چۈشەندۈرۈشلەردىن كېيىن شۇنداق يەكۈنلەشكە بولىدۇكى: ئەسلى Activity ئىچىدە بىر تەرەپ قىلىنىدىغان بىر توقاي ئىقتىدارلار MVP ئەندىزىسى بويىچە View ۋە Presenter ئېغىزلىرىغا ئابىستراكىتلاشتۇرىلدۇ(抽象化) ۋە باشقا سىنىپلار ئىچىدە ئايرىم ئەمەلگە ئاشۇرۇلىدۇ. بۇ خىل ئەھۋالدا ئەمەلگە ئاشۇرۇدىغان ئىقتىدارنىڭ مۇرەككەپلىكىگە قاراپ IView ۋە IPresenter ئىغىزلىرى كۆپىيىپ ماڭىدۇ، دېمەك بۇ دەسلىپىدە كىشىگە بىر ئاز ئاۋارىچىلىق تۇيۇلىدۇ. لېكىن MVP ئەندىزىسىگە كۆنۈكۈپ كەتكەندىن كېيىن بۇلارمۇ ھىچگەپ ئەمەس.
يۇقىرىدا بىرتالاي نەزەرىيە سۆزلەپ ئۆتتۇق، ئەمدى ئاددىيغىنە بىر ئەمەلىي مىسال بىلەن كىلەيلى!

Talk is cheap, let me show you the code!

MVP ئەندىزىسى قوللىنىلغان ئاددىي مىسال

87960424

يۇقىرىقى رەسىمدەك ئاددى بىر كىرىش كۆزنىكى. Login كونۇپكىسىنى باسقاندىن كېيىن قوللانچى نامى ۋە پارولغا قارىتا تەكشۈرۈش ئېلىپ بېرىلىدۇ. Clear نى باسقاندا كىرگۈزۈش رامكىلىرى قۇرۇقدىلىدۇ.
مىسال ئەپ قۇرۇلمىسى تۆۋەندىكى رەسىمدەك:

63555794

كۆرگىنىمىزدەك MVP ئەندىزىسىنىڭ قۇرۇلمىسى تېخىمۇ ئېنىق. ئادەتتە ئىقتىدار بۆلەكلىرى بىر قەدەر مۇستەقىل ۋە چوڭ بولغان ئەپلەرگە نىسبەتەن، ئىقتىدار بويىچە بوغچا (Package) قۇرۇپ ئاندىن ھەربىرىنىڭ ئىچىگە model、view、presenter لىرىنى ئايرىم ئورۇنلاشتۇرىسىمۇ بولىدۇ. ياكى ئومۇمى تۈر بوغچىسى ئىچىگە بىرلا model、view、presenter قۇرۇلمىسىنى ئورۇنلاشتۇرسىمۇ بولىدۇ.
ئاۋۋال LoginActivity قىسمىغا قاراپ باقايلى:

public class LoginActivity extends ActionBarActivity implements ILoginView, View.OnClickListener {

	private EditText editUser;
	private EditText editPass;
	private Button   btnLogin;
	private Button   btnClear;
	ILoginPresenter loginPresenter;
	private ProgressBar progressBar;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		//find view
		editUser = (EditText) this.findViewById(R.id.et_login_username);
		editPass = (EditText) this.findViewById(R.id.et_login_password);
		btnLogin = (Button) this.findViewById(R.id.btn_login_login);
		btnClear = (Button) this.findViewById(R.id.btn_login_clear);
		progressBar = (ProgressBar) this.findViewById(R.id.progress_login);

		//set listener
		btnLogin.setOnClickListener(this);
		btnClear.setOnClickListener(this);

		//init
		loginPresenter = new LoginPresenterCompl(this);
		loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()){
			case R.id.btn_login_clear:
				loginPresenter.clear();
				break;
			case R.id.btn_login_login:
				loginPresenter.setProgressBarVisiblity(View.VISIBLE);
				btnLogin.setEnabled(false);
				btnClear.setEnabled(false);
				loginPresenter.doLogin(editUser.getText().toString(), editPass.getText().toString());
				break;
		}
	}

	@Override
	public void onClearText() {
		editUser.setText("");
		editPass.setText("");
	}

	@Override
	public void onLoginResult(Boolean result, int code) {
		loginPresenter.setProgressBarVisiblity(View.INVISIBLE);
		btnLogin.setEnabled(true);
		btnClear.setEnabled(true);
		if (result){
			Toast.makeText(this,"Login Success",Toast.LENGTH_SHORT).show();
			startActivity(new Intent(this, HomeActivity.class));
		}
		else
			Toast.makeText(this,"Login Fail, code = " + code,Toast.LENGTH_SHORT).show();
	}


	@Override
	public void onSetProgressBarVisibility(int visibility) {
		progressBar.setVisibility(visibility);
	}
}

كودلاردىن كۆرۈۋىلىشقا بولىدۇ، LoginActivity دە پەقەت findView ۋە setListener مەشغۇلاتلىرىلا بىر تەرەپ قىلىنغان. ئۇنىڭدىن باشقا ILoginPresenter ئىغىزىنى ئۆز ئىچىگە ئالغان بولۇپ، بارلىق ئىقتىدارلار شۇنىڭ ماسلاشتۇرىشى بىلەن مۇناسىپ ئىغىزلاردا ئەمەلگە ئاشۇرۇلغان. شۇڭا LoginActivity نىڭ قۇرۇلمىسى قارىماققا تولىمۇ ئاددىي كۆرۈنىدۇ. سىنچىلاپ قارىساق LoginActivity نىڭ يەنە ILoginView ئىغىزىغا ۋارىسلىق قىلغانلىقىنى بايقايمىز. بۇنىڭ نېمە ئۈچۈنلىكىنى چۈشەنمىگەن بولساق تۇرۇپ تۇرسۇن.
ئاۋۋال ILoginPresenter نىڭ قۇرۇلمىسىغا قاراپ باقايلى

public interface ILoginPresenter {
	void clear();
	void doLogin(String name, String passwd);
	void setProgressBarVisiblity(int visiblity);
}
public class LoginPresenterCompl implements ILoginPresenter {
	ILoginView iLoginView;
	IUser user;
	Handler    handler;

	public LoginPresenterCompl(ILoginView iLoginView) {
		this.iLoginView = iLoginView;
		initUser();
		handler = new Handler(Looper.getMainLooper());
	}

	@Override
	public void clear() {
		iLoginView.onClearText();
	}

	@Override
	public void doLogin(String name, String passwd) {
		Boolean isLoginSuccess = true;
		final int code = user.checkUserValidity(name,passwd);
		if (code!=0) isLoginSuccess = false;
		final Boolean result = isLoginSuccess;
		handler.postDelayed(new Runnable() {
			@Override
			public void run() {
				iLoginView.onLoginResult(result, code);
			}
		}, 3000);

	}

	@Override
	public void setProgressBarVisiblity(int visiblity){
		iLoginView.onSetProgressBarVisibility(visiblity);
	}

	private void initUser(){
		user = new UserModel("mvp","mvp");
	}
}

يۇقىرىقى كودتا كۆرسىتىلگىنىدەك، LoginPresenterCompl گە ILoginView نىڭ نەقىلى ئۆتكۈزۈلگەن. دېمەك، LoginPresenterCompl ئىچىدىلا بىۋاستە UI مەشغۇلاتى قىلىشقا بولىدۇ. بۇيەردە بىۋاستە ھالدا Activity نى چىللاپ ئىشلەتمەستىن، ILoginView نىڭ نەقىلىنى ئىشلەتكەچكە، ئىقتىدار لوگىكىسى بىلەن ئەمەلىي Activity نىڭ مۇناسىۋىتى يوق. دېمەك، بىر ئىقتىدارنى خالىغان Activity ئىچىدە خالىغانچە ئىشلىتىشكە بولىدۇ. ئاددىي قىلىپ ئىيىتقاندا، بارلىق ئىقتىدار لوگىكىلىرىنى موشۇ ھالەتتە ئىغىزلارغا جەملىۋىلىپ، Activiy ئىچىدە لازىم بولغاندا new قىلىپ ئىشلەتسەكلا بولىدۇ.

IVIew ۋە IPresenter ئىغىزلىرى ئارقىلىق مەلۇم Activity نىڭ كۆرۈنمە يۈز لوگىكىسى (UI Logic) ۋە كەسىپ لوگكىسى(Business Logic) نى پۈتۈنلەي ئايرىۋىتىمىز

ئەمدى ILoginView ئىغىزىغا قاراپ باقايلى:

public interface ILoginView {
	public void onClearText();
	public void onLoginResult(Boolean result, int code);
	public void onSetProgressBarVisibility(int visibility);
}

يەنى، كىرىش كۆزنىكىدىكى مۇناسىۋەتلىك لوگىكىلارغا بۇ ئىغىز ئىچىدە ئابستراكىت ئىنىقلىما بېرىلگەن.

خولاسە

يۇقىرىقىلىرى بىرقانچە ئەمەلىي تۈرلەرنى ئىشلەش ۋە ئۆگېنىش جەريانىدا MVP ئەندىزىسى ھەققىدە چۈشىنىپ يەتكەنلىرىم. گەرچە MVP نىڭ بىر قىسىم كەمچىلىكلىرى بولسىمۇ، MVVP ئەندىزىسى تېخى پىشىپ يىتىلمىگەن، MVC ئىھتىياجنى قامدىيالمىغان ئەھۋالدا بۇنىڭدىن ياخشىسى يوق دەپ ئويلايمەن. ئۇيغۇرچە Android ئەپلەردە قايسى خىل ئەندىزە رامكىسىنى كۆپ قوللىنىدۇ ماڭا نامەلۇم، ئەمما چوڭ تىپتىكى ئەپلەرگە نىسبەتەن مۇۋاپىق بىر ئەندىزە تاللاپ، ئەپ قۇرۇلمىسىنىڭ مۇكەممەللىكىگە كاپالەتلىك قىلىش ھەقىقەتەنمۇ مۇھىمدۇر.

4 باھا »

  1. FinalFantasy
    FinalFantasy May 4th, 2016 at 01:41 pm
    جاۋاب

    بىر قۇر كۆز يۈگرىتىپ چىقتىم، ياخشى يېزىپسىز. MVC/P غا يەنە Dependency Injection (ئۇيغۇرچە «تايانچ قۇيۇش» دەمدۇق؟) نى بىرلەشتۈرۈپ ئىشلەتسىڭىز، ماقالىڭىزنىڭ بېشىدا تىلغا ئالغاندەك، پروگراممىلىرىڭىزدىكى ھەرقايسى زاپچاس (component) لار ئارىسىدىكى باغلىنىش (coupling) يەنىمۇ ئىلگىرىلىگەن ھالدا تۆۋەنلەپ، كودىڭىزنىڭ سىناق قىلىنىشچانلىقى (testability) بىلەن ئاسراشچانلىقى (maintainability) تېخىمۇ يۇقىرى كۆتۈرۈلىدۇ.

    1. تەشنا
      تەشنا May 4th, 2016 at 07:13 pm
      جاۋاب

      رەھمەت سىزگە. راست دېگىنڭىزدەك تايانچ قويۇشمۇ ھەقىقەتەن ئۈنۈملۈك بىر ئۇسۇسلكەن، Android قا نىسبەتەن مەخسۇس بۇ مەسىلىنى ھەل قىلىدىغانغا، Square شىركېتى يېزىپ چىققان DAGGER ئامبېرى بار ئىكەن. ئىلگىرى ئاز تولا ئۇچرىشىپ باققان بولساممۇ، چوڭقۇرلاپ چۈشىنىشكە پۇرسەت بولمىغانىدى، ۋاقىت چىقىرىپ ئوبدان كۆرۈپ باقسام بولغۇدەك...

      1. FinalFantasy
        FinalFantasy May 6th, 2016 at 01:29 pm
        جاۋاب

        Dagger نى كۆرۈپ باقتىم، annotation لارنى ئىشلىتىپ، ئىشلارنى سەل مۇرەككەپلەشتۈرۈۋالغاندەك ھېس قىلدىم. dependency injection نى ئەڭ ياخشىسى ئەڭ ئاددىي بولغان constructor injection دىن باشلاپ كۆرۈپ بېقىڭ:

        https://en.wikipedia.org/wiki/Dependency_injection#Constructor_injection

  2. ھەۋەسكار
    ھەۋەسكار May 6th, 2016 at 10:19 pm
    جاۋاب

    تىخنىكىلىق مەسىلىلەرگە كەلگەندە مەندەك ئۇماچسىزلار گەپ قىلالماي قالىدىكەنمىز