前言
上一篇移动运用留传体系重构(12)- 编译调试篇
介绍,通过了解耦、分库及编译调试的优化,一段时间内,CloudDisk的开发功率得到了很大的进步。
但随着事务的演进,因为前史的原因,代码中存在很多Activity及Controller的天主类。产品司理作业流程今天咱们将拿File Bundle作为比如,为咱们总结重构的流程,演示如何一步一步将天主类重构为MVP架构。
视频演示地址: mp.产品司理薪酬一般多少weixin.qq.com/s/zjeln_eqA…
重构流程
graph TD
A(1.拾掇事务逻辑)-->B(2.剖析原有的代码规划)
B-->C(3.补偿照顾查验)
C-->D(4.简略规划)
D-->E(5.小步安全重构)
E-->F(6.集成查验查验)
1. 拾掇事务逻线程辑
经产品司理是做什么过往往这一步是最难的。因为人员更变量与函数迭、产品的迭代,给这一步带来很大的应战。咱们能够变量查验从一下几方面来补全信息。
- 找人:产品司理、规划人员、查验人员进行供认和答疑
- 找文档:查看原有的需求文档、规划文档、查验用例、规划稿
- 看代码:从原有的代码规划中去拾掇事务
通过拾掇供认,File Bundle的现有的事务如下:
graph TD
A(进入文件页面)-->B(从网络加载文件列表数据)
B --产品司理和项目司理差异有哪些> C{数据是否加载成功kotlin是什么意思}
C -->变量和常量的差异;|加载成功| D线程池的七个参数(闪现文件列表-文件名和文件巨细)
C -->|网络异常| E(闪现NetworkErrorException)
C -->|数据为空| F(闪现empty data)
E -->|点击触发改写|B
F -->|点击触发改写|B
文件巨细转换为以B、变量类型有哪些K、M、G单位闪现
2.剖析原有的代码规划
咱们以首要天主类FileFragment为例,代码如下:
@AndroidEntryPoint
public class FileFragment extends Fragment {
@Inject
FileController fileController;
privatAPPe RecyclerView fileListRecycleView;
private TextView tvMessage;
publ线程池创立的四种ic static FileFragment newInstance() {
FileFragment fragment = new FileFragment();
Bundle ar产品司理gs = newappearance Bundle();
fragment.变量泵setArguments(args);
return fragment;
}
@Override
public View onCrkotlin怎样读eateView(LayoutInflater inflater, ViewGr产品司理作业流程oup container,
Bundle sav线程edInstanceSkotlin是什么意思tate) {
View view = inflater.inflate(R.layout.fragment_file, container, false);
fileListRecycleView = view.findViewById(R.id.file_list);
tvMessage = view.findViewById(R.id.tv_message);
tvMessage.setOnClickListener(v -> getFileList());
return view;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFileL变量是什么意思ist();
}
priv变量与函数ate void getFileList() {
new Thread(() -> {
Message message = new Messa变量是什么意思ge();
try {
Li变量st<FileInfo> infoList = fileController.getFileList();
message.what = 1;
message.objkotlin教程 = infoList;kotlin怎样读
} catch (Netwo产品司理需求的技术rkErrorException e) {
message.what = 0;
message.ob线程j = "Networ变量是什么意思kErrorException";
e.printStackTrace(application);
}
mHandler.产品司理英文sendMessa产品司理有出路吗ge(message);
}).start();
}
Handler mHandler =appear new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Mess变量是什么意思age msg) {线程池的七个参数
if (产品司理的职责msg.what == 1) {变量是什么意思
showTip(false);
//闪现网络数据
List<FileInfo> infoList = (List<FileInfo>) msg.obj;
FileListAdapter fileListAdapter = new FileListA变量的指针其意义是指该变量的dapter(infoList, getActivity());
fileListRecycleView.addItemDec线程撕裂者orakotlin下载tion(new DividerItemDecoration(
getActivity(), Divkotlin实战iderItemDecoration.VER产品司理作业流程TICAL));
//设置布局闪现格局
fileListReckotlin实战ycleView.setLayoutMana产品司理需求考的证书gKotliner(n产品司理英文ew LinearLayoutManager(getActivity()))kotlin和java;
fileLi变量是什么意思stRecycleView.setAdapterapp是什么意思(fileListAdapter);
} else if (msg.what == 0) {
showTip(true);
//闪现异常提示数据
tvMessakotlin教程ge.setT变量类型有哪些e变量与函数xt(msg.obj.toString());
}appearance else {
showTip(true);
//闪现空数据
tvMessage.setText("empty data");
}
return false;
}
});
public void showTip(boolean show) {
if (show) {
tvMessagekotlin和java.setVisibility(View.VISIBLE);
fileListRecycleVieAPPw.setVisibility(View.GONE);
} else {
tvMessage.setVisibility(Vi产品司理英文ew.GONE);
fileListRecycleVi变量和常量的差异ew.setVisibility(View.VISIBLE);
}
}
}
从代码中咱们能够看到首要的一些规划问题,如下:
- 首要的获取文件、异常逻辑判别appetite、界kotlin实战面改写操控都是在一个类里面,不利于后续的扩张及批改维护。咱们期望类的职责线程撕裂者愈加单一,逻辑和视图能够进行别离。
- 存在粗暴的new Thread进行处理
- Handlerappearance 存在内存泄露风险
- 存在标准问题,例如empty data字符串没有运用xml进行处理、代码中由无效的导包等
- 代码中没有任何照顾查验
无缺的悉数代码见Github
3. 补偿照顾查验产品司理需求考的证书
参阅重构篇中,咱们制定的战略,咱们能够先做大型的查验,做为照顾查验。
@RunWith(AndroidJUnit4.class线程安全)
@LargeTest
@HiltAndroidTest
@Config(application = HiltTestApplication.class)
public class FileFragmentTest {
@Rule
pubAPPlic HiltAndroidRule hiltRule = new HiltAndroidRule(this);
@Test
publickotlin怎样读 void s线程安全how_show_file_list_when_get_success() {
//given
ActivityScenario<DebugActivity> scenario = ActivityScenario.launch(DebugActivity.clasapples);
scenario.onActivity(activity -> {
//then
onVie变量值w(withText("留传代产品司理英文码重构.pdf")).check(matches(isDisplayed()));
onView(withText("100.00K")).ch产品司理需求考的证书eck(kotlin是什么意思matches(isDisplayed()));
onVie产品司理的职责w(变量名的命名规矩withText("体系组件化.产品司理需求的技术pdf")).check(matches(isDisplayed()));
onView(withText("9.67K")).check(matches(isDisplayed()));
});
}
}
咱们发现这个用不会通过,咱们首要面临一下变量与函数2个问题。
- 网络请求是异步的,异步逻辑可能在查验实行完还没有触发到
- 网络数据是动态的,咱们断言的数据没方法确线程的几种状况定
所以咱们选用的做法便是Mock,我不稳定的依托Mock掉。咱们相同运用Shadkotlin面试题ow来进行多获取网络数据方法进行Mock,代码如下:
@Implements(FileFragment.class)
pappearanceublic class ShadowFileFragment {
@RealObject线程池原理
public FileFr变量值agment fileFragment;kotlin怎样读
enum State {
SUCCkotlin实战ESS,
ERROR,
EMPTkotlin实战Y
}kotlin实战
public static State state = State.SUCCESS;
@线程是什么意思Implementatiappleon
protected void getFileList() {
System.out.pri线程ntln("shadow .... .....");
Message message = new Message();
if (state == Sappletate.SUCCEkotlin教程SS) {
ArrayList<FileInfo> infoList = new ArrayList<>();
infkotlin和javaoList.add(new产品司理40岁后能干嘛 FileInfo("留传代码重构.pdf", 102400));
infoList.ad变量与函数d(new FileIkotlin是什么意思nfo("体系组件化.pdf", 9900));
message.what = 1;
messag线程池面试题e.obj = infoList;
} else if (state == State.ERROR) {
mappearessage.what = 0;
message.obj = "NetworkErrorExceptioappearancen";
} else if (state == State.EMPTY) {
message.what = 1;
message.obj = null;
}
file线程池Fragment.mHandler.sendMessage(message);
}
}
调整kotlin教程后的查验用例如下:
@Test
public void sh变量的界说ow_show_file_l产品司理和项目司理差异有哪些ist_kotlin实战when_get_success() {
//given
ShadowFileFragment.state = ShadowFileFragmentkotlin下载.St产品司理需求考的证书ate.SUCCESS;
//when
ActivityScenario<DebugActivity> scenarioappear = ActivitySappetitecenario.launch(DebugActivity.class);
scenario线程池.onActappstoreivity(activity -> {
//the线程的几种状况n
onView(withText("留传代码重构.pd产品司理需求考的证书f")).check(matches(isDisplayed()));
onView(withText("100.00K")).chec变量的界说k(matches(isDisplayed()));
onView(withText("体系组件化.pdf")).check(matches(isDisplayed()));
onView(withText("9.67K")).check(matches(变量泵i线程撕裂者sDisplayed()));
}线程和进程的差异是什么);变量的指针其意义是指该变量的
}
@Test产品司理作业流程
public void show_show_er变量与函数ror_tip_when_net_work_exception() {
//given
S线程hadowFileFAPPragment.state = Shadow线程FileFragment.State.ERROR;
//when
ActivityScenario<DebugA变量名的命名规矩ctivity> scenario = ActivityScenario.launch(DebugActivity.class);
scenario.onActivity(ackotlin为什么盛行不起来tivity -> {
//then
onView变量和常量的差异(withText("NetworkErrorException")).check(matches(isDisplayed()));
});
}
@Test
public void show_show_empty_tip_when_not_has_data() {
//given
ShadowFileFragment.state = ShadowFileFragment.State.EMPTY;
//whapp是什么意思en
ActivityScenario&变量泵lt;DebugActivity> scenario = ActivityScenario.launch(Debukotlin怎样读gActivity.class);
scenar线程撕裂者io.onActivity(activity -> {
//then
onVi产品司理英文ew(withText("empty data")).check(matches(isDisplayed()));
});
}
中心咱们用答应appreciate查验脚步时发现,之前的线程池面试题旧代码还有一处逻辑的过错。数据为空的判别应该加在网络数appetite据回调中。
Caused by: java.lang.NullPointerException
at com.cloud.d变量名isk.bundle.file.FileFragmeAPPnt$1.h产品司理的职责andleMessage(FileFappearanceragment.java:96)
at android.os.Handler.dispatchMessage(Ha产品司理40岁后能干嘛ndler.java:102)
咱们同步将异常逻辑进行批改,如下:
终究咱们完成了底子的照顾查验,作业效果如下:
无缺的悉数代码见Github
4. 简略规划
MVP架构
graph TD
B(Presenter)-->A(Model)
B-->|interface|C(View)
C变量类型有哪些-->|interface|B
- 事务逻辑和视图别离
- Presenter和View之间通过接口交互
- 为了更高效处理线程,团队抉择运线程和进程的差异是什么用Rxjava进行线程一致处理。架构风格参阅architecture-samples
接口规划
- Contract接口规划
public int变量值erfacapp是什么意思e FileListC线程池ontract {
interface View {
showFileList(L产品司理需求的技术ist<FileInfo>appreciate; fileList);
showNetWorkException(String errorMessage);
showEmptyData();
}
interface Presenter {
voidkotlin怎样读 getFileList();
}
}
- 数据接口规划
public interface FileDataSource {
Flowable<List<FiappetiteleIn产品司理英文fo>> getFileList();
}
5.小步安全重构
- 抽取FileFragment的事务逻辑到FilePresenter
- FileFragment 提线程池原理取UI接口
- 抽取FileDataSource
重构方法包含提取接口、移动方法产品司理、移动类、抽取方法、内联、提取变量等等。进程还需求根据重构适当调整变量泵查验用例。
具体的演示见视频
- 补偿查验用例
- 补偿FileUtils计算文线程池创立的四种件巨细查验
@RunWith(JUnit4.class)
@SmallTest
public class FileUtilsTest {
@Tekotlin为什么盛行不起来st
public vo产品司理需求的技术ikotlin面试题d should_return_B_unit_when_file_size_in_itkotlin怎样读s_range(变量泵) {
//given
long fileSize = 100;
//when
String format = FileUtils.forkotlin言语matFileSize(fileSize);
//then
assertEquals("100.00B", format);
}
@Test
public void should_return_K_unit_when_filkotlin实战e_size_in_its_range() {
//given
long fappearanceileSize = 1034;
//when
Stri线程撕裂者ng format = Fil变量类型有哪些eUtils.formatFileSize(fileSize);
//then
assertEquals("1.01K", format);
}产品司理薪酬一般多少
@Test
public void should_return_M_unit_when_file_size_in_its_range() {
//given
long f产品司理和项目司理差异有哪些ilappstoreeSize = 1084000;
//when
String format = FileUtils.formatFileSize(fileSize);
//then
assertEquals("1.03M", forma产品司理英文t);
}
@Test
public vkotlin中心编程oid should_return_G_unit_when_file_size_in_its_range() {
//given
long fileSize = 1114000000;
//when
String format = FileUtils.formatFileSize(fKotlinil线程eSize);
//then
assertEquals("1.04G", for变量与函数mat);
}
}
- 补偿Presenter事务逻辑查验
@RunWith(JUnit4.clkotlin面试题ass)
@MediumTest
public class FilePresenterImplTest {
@Rule
public Rkotlin怎样读xSchedulerRule rule = new RxSchedulerRule(产品司理);
@Test
pubkotlin是什么意思lic void should_return_file_list_when_call_data_source_success() throws NetworkErrorExceptappearion {
//giveappstoren
File线程池ListContract.View mockView = mock(FileListContract.View.class);
FileDataSource mockFileDataSource = mock(FileDataSource.class);
List<kotlin教程;FileInfo> fileList = new ArrayList<>();
fileList.add(new FileInfo("留传代码重构.pdf", 102400));
fileListapproach.add(new FileInfo("体系组件化.pdf", 9900));
when(mockFileDataSource.getFileLis变量是什么意思t()).thenReturn(Flowable.fromArray(fileList));
FileListContract.FilePrkotlin为什么盛行不起来esenter filePresenter = new FilePresenterImpl(mockotlin面试题kFileDakotlin和javataSource, mockView);
//when
filePresente产品司理40岁后能干嘛r.getFileL变量是什么意思ist();
//then
verify(mockView).showFileList(anyList());
}产品司理需求考的证书
@Test
pu线程和进程的差异是什么blic void产品司理 should_show_empty_data_when_call_data_source_return_empty() throws NetworkErrorException {
//given
FileListContract.View mock产品司理和项目司理差异有哪些View = mock(F产品司理英文ileListContract.View.class);
FileData产品司理是做什么Source mockFileDataSource = mock(FileDataSource.class);
when(moapproachckFiappointmentleDataSource.getFileList()).thenReturn(Flowable.fromArray(new ArrayList<>()));
FileListContract.FilePrkotlin下载esente产品司理薪酬一般多少r filePresenter = new FilePresenterImpl(mo产品司理ckFileDataSource, mockView);
//when
filePresenter.gekotlin言语tFilekotlin教程List();
//the产品司理n
verify(m产品司理40岁后能干嘛ockView).showEmptyData();
}
@Test
public产品司理有出路吗 void should_show_net线程池原理worapproachk_ex线程ception_when_capplicationall_data_source_return_net_error() throws NetworkErrorException {
//given
FileL产品司理需求的技术istContract.View mockView = m变量ock(FileListContract.View.class);
FileDataSource mockFilekotlin和javaDat产品司理薪酬一般多少aSourceappreciate = mock(FileDataSource.class);
when变量泵(mockFileDataSource.getFileList()).thenT线程安全hrow(new NetworkErrorException());
FileListCkotlin教程ontract.FilePresenter filePresenter = new FilePrese线程池面试题nterImpl(mockFileDataSource, mock产品司理是做什么View);
//when
filePresenter.getFileList();
//then
vappetiteerify(mockView).showNappearanceetWorkException("NetworkErrorException");
}
}
咱们能够通过查看Coveappearrage查看逻辑的掩盖情况,判别是否有重要的逻辑丢掉。
终究咱们作业file bundle悉数的查验,陈说如下:
6.集成查验查验
- file bundle模块发布1.0.1版别
implementation 'com.cloud.disk.bundle:file:1.0.1'
- 实行照顾查验
- 作业查看
总变量名的命名规矩结
本篇介绍了文件模块团队将文件主页重构为Mkotlin怎样读VP架构,而且补偿了自动化查验。通过kotlin是什么意思重构后,团队的开发功率和版别质量有了线程池原理明显的进步。有了文件模块的打样,给其他团队带来了很大的决心。
接下来,咱们将持续共享动态模块的重构之旅。与文件模块纷歧线程池原理样的是动态模块抉择选用Kotlin+MVVM架构。
下一篇,单体移动运用“模块化”演进之旅(14)- Kotlin+MVVM重构示例篇
CloudDisk示例代码
CloudDisk
系列链变量类型有哪些接
移动运用留传体系重构(1)- 开篇
移产品司理薪酬一般多少动运用留传产品司理需求的技术体系重构(2)-架构篇
移动运用留传体系重构(3)-示例篇
移动运用留传体系重构(4)-剖析篇
移动运用留传体系重构appreciate(5)- 重构方法篇
移动变量的界说运用留传体系重构(6)- 查验篇
移动运用留传体系重构(7)- 解耦重构演示篇(一)+视频演示
移动运用留传体系重构(8)- 依托注入篇
移动运用留传体系重构(9)- 路由篇产品司理薪酬一般多少
移动运用留传体系重构(10)- 解耦重构演示篇(二)
移动运用留传体系重构(11)- 制品处理篇
移动运用留传体系重构(12)- 编译调试篇
大纲
关于
- 作者:黄俊产品司理和项目司理差异有哪些彬
- 博客:junbin.tech
- GitHub: junbin1011
- 知乎: @JunBin