我正在开发一个Android项目。我搜索过高低,但我无法找到一个好的策略来分割和打包我的代码。
我的问题是我有使用主类变量的内部类,而我无法弄明白如何将它们分离。
我试图创建帮助类,但是我要么通过构造函数传递很多变量,要么暴露我的主类,而我不想做。< / p>
我希望每个类的最大代码行保持为150.目前,它是278.我正在寻找想法来解耦这些,特别是如何重构类以保留抽象(private
变量)。 Java
最佳做法是什么?
例如,here是我的主要课程之一,MainActivity
,约300行。
答案 0 :(得分:4)
修改强>
在添加MainActivivty
的实际代码后,我建议如下:
MainActivity
之外获取所有与UI相关的代码后,方法addButtons()
将会消失,而CategoriesListener
类也会消失。AllPostsFetchAsyncTask
确实不需要成为内部阶级。将其实现为活动之外的常规类。为了将此类中的数据传递回MainActivity
,只需定义MainActivity
将实现的侦听器接口,并将MainActivity.this
传递给构造函数 - 当此任务完成时,它将在MainActivity
上调用回调方法,后者将处理与Adapter
的数据绑定。事实上,你在这里采用了一种非常糟糕的做法 - 让AllPostsFetchAsyncTask
知道MainActivity
的实现细节,你在两者之间创建了不必要的耦合,从而违反了OOP的封装,单一责任和开放封闭原则。 / LI>
醇>
只需执行上述两个步骤,您就可以使这个特定的MainActivity
方式短于150行代码。
说,你将活动保持150行的意图太严格了。这归结为这样一个事实:如果您的Activity
或Fragment
不是微不足道的,那么一旦您实施onCreate()
,onPause()
,onResume()
,{{1} },onPrepareOptionsMenu()
和其他标准生命周期方法,即使在添加自定义控制器的逻辑之前,您也可能拥有超过150行代码。
现在,我完全讨厌内部课程,并试图不惜一切代价避免它们。以下清单可以作为指导,但无论如何都不完整:
onBackStackChanged()
,Activities
和Fragments
)中的UI元素 - 将这些操作封装在不同的类中。这些类是MVC / MVP视图(而不是Android View),我将它们放在Adapters
或views
个包中。我的mvcviews
和Activities
的源代码往往只有Fragments
次调用。findViewById()
放在一个单独的包中(即使它们长30行)。我称之为Adapters
或controllers.adapters
controllers.listadapters
的包,即使它只包含一个类。定义抽象类pojos
和AbstractActivity
并放置控制器使用的任何便利逻辑。例如:我的AbstractFragment
和AbstractActivity
中总是有以下方法(或类似方法):
AbstractFragment
检查是否有任何第三方库可能在您的应用上下文中有用并使用它们。
我的包装通常遵循以下模式:
我知道你写过你已经看过一些关于MVC的讨论,但我仍然鼓励你尝试我在这个模板/教程项目中提出的实现:https://github.com/techyourchance/android_mvc_template
希望这有帮助
答案 1 :(得分:3)
首先,根据您的活动的实施,您错过了一些有关活动的重要事项。
<强> 1。只有使用静态内部类或AsyncTasks的独立类:请参阅Background task, progress dialog, orientation change - is there any 100% working solution?
重要的是:
第2步:让AsyncTask通过数据成员保存在Activity上,通过构造函数和setter设置。
步骤#5 :在onCreate()中,如果getLastNonConfigurationInstance()不为null,则将其强制转换为AsyncTask类,并调用setter将新活动与任务相关联。
您会注意到,您必须根据Android的生命周期方法注册和取消注册您的组件。重要的是要知道,始终遵循Android生命周期!
记住这将始终引导您找到解决Android方式的正确答案。
<强> 2。在需要时使用数据保留类。
这里并不真正属于一个活动:
// Stores the fetched dataMap
ArrayList<HashMap<String, String>> arrayList;
当您的活动被销毁时,例如在配置更改期间,您的所有数据都已消失,您需要再次加载所有数据。
访问和存储数据可以通过多种不同方式完成:http://developer.android.com/guide/faq/framework.html#3
在您的情况下,这可能适用:
公共静态字段/方法
跨活动/服务访问数据的另一种方法是使用公共静态字段和/或方法。 您可以从您的任何其他类访问这些静态字段 应用。要共享一个对象,创建您的对象的活动 object设置一个静态字段以指向此对象和任何其他对象 想要使用此对象的活动只是访问此静态 字段。
另外考虑将数据存储在数据库中或通过其他方式存储,因此即使您的应用程序被销毁,您的数据也不会消失。
第3。与您的活动的沟通可以这样完成:http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
以相同的方式将它用于您的视图和查看侦听器。有一个管理你的视图的组件(像片段一样),将它注册到你的Activity,使用它,在不需要时或在生命周期需要它时注销它。
就像 1 中所述,Android生命周期是一切的关键。
<强> 4。依赖注入是一个非常重要的主题,您可以使用它的框架(如Dagger 2或RoboGuice)或以您自己的方式执行。确保您的Injector知道依赖项(比如哪些Buttons需要哪些ClickListeners和Information或您的适配器需要哪些数据)并将它们绑定在一起。在总是考虑生命周期时,您将看到需要哪些接口和方法以及何时调用它们。
<强> 5。不要担心关于代码行数。如果您的设计一致且有意义,即使有500行,您也不会遇到可读性问题。顺便说一句。在正确记录代码时,它可轻松获得超过150行代码。所以,再次担心这一点。
如果您对实施细节有任何具体问题,请询问具体问题,否则您会得到一个臃肿的答案。
答案 2 :(得分:1)
这是部分问题的答案。正如问题中所述
我试图创建辅助类,但是我要么通过构造函数传递很多变量
这与Telescoping constructor非常相似。所以,为了解决这个问题,我个人会使用类似于Builder Pattern的东西。
class A {
public class B {
public B(int x, int y, int z, int m, int n, int o){
}
}
}
以上案例可以修改如下。
class A {
public class B{
int a, int b, int c, int m, int n, int p = 0;
public B(){
}
public B setA(int x){
a = x;
return this;
}
public B setB(int x){
b = x;
return this;
}
... and similar methods for other properties.
}
}
当您拥有许多属性并且您的类 - 客户端需要记住更多方法时,上述解决方案可能会使您的类看起来很长。因此,我想在上面的模式中做一些修改。为每个属性分配密钥也会使类客户端更简单。
class A {
public class B{
int a, int b, int c, int m, int n, int p = 0; // key for int a == "a" and for b is "b" and so on... this is our assumption.
public B(){
}
public B setProperty(String key, int value){
if(key.equals("a")){
a = value;
}else if(key.equals("b")){
b = value;
} ... and so on for other properties.
return this;
}
}
}
答案 3 :(得分:0)
如果内部类只访问字段,那么为/** new container class */
class FooBar {
public Foo foo;
public Bar bar;
}
/** nice, easy and SHORT! */
class MainActivity {
private FooBar fooBar;
public MainActivity() {
new Ping(fooBar);
new Pong(fooBar).someMethod();
}
}
/** successfully converted from inner class to class */
class Ping {
public Ping(FooBar fooBar) {
fooBar.foo = new Foo(); // Ping modifies Foo
}
}
/** successfully converted from inner class to class */
class Pong {
private Bob bob;
private FooBar fooBar;
public Pong (FooBar fooBar) {
this.fooBar = fooBar;
fooBar.bar = new Bar(); // Pong modifies bar
bob = new Bob();
}
public void someMethod () {
fooBar.bar.setSomethingTo(Bob.getSomething()); // Pong modifies bar of Main class
fooBar.foo = new Foo(fooBar.bar); // Pong assignes something to bar
}
}
类的所有相关字段引入一个新的Container类(当然,您也可以创建两个或三个小容器而不是一个大容器)。
然后可以将您的示例修改为:
class Foo {
public Foo() {}
public Foo(Bar bar) {}
}
class Bar {
public void setSomethingTo(String something) {}
}
class Bob {
static String getSomething() {return "Something";}
}
我使用这些类存根来获取代码编译:
MainActivity
如果内部类也在访问方法,那么您可以在接口中指定那些由MainActivity
实现的方法。仅使用接口将MainActivity
的实例移交给其他类。这样您就不必暴露完整的UIView
,并且可以避免循环依赖。
答案 4 :(得分:-2)
拿出你的内部类,在他们的构造函数中将MainActivity的实例传递给它们。
MainActivity mainActivity;
DownloadJSON(MainActivity mainActivity) {
super();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setCancelable(false);
this.mainActivity=mainActivity;
}
将mainActivity中的变量设为公共,您可以像这样访问它们:
// Extract the metadata
mainActivity.pageCount =Integer.parseInt(metaData.get("PAGE_COUNT"));