2011-04-24 70 views
45

我最近编写了我的第一个Android应用程序,大约有8,000-10,000行代码。有一件事不断阻碍我使用正常的设计模式,这是android大量使用异步调用(打开对话框,活动等)。由于这个原因,我的代码很快就开始寻找“意大利面条”,我最终开始不喜欢看某些类。异步编程最佳实践

对于任何人都会推荐的系统,是否有特定的设计模式或编程方法?对编写可管理的异步代码有任何建议吗?

+3

没有一个你认为是事件驱动程序设计强加于你的“意大利式面条”结构的例子,任何人都很难给你提供建议。 – CommonsWare 2011-04-24 23:45:30

+0

例如,当与对话框内的按钮侦听器组合使用诸如showDialog()/ onDialogCreate()之类的调用时,可以跟踪条件程序状态。它可能会变得棘手的管理流程。 – Ryan 2011-04-24 23:50:31

+0

也许你不应该使用对话框。 :-) Android上的对话框应该是例外,而不是规则。恰当的例子:相对较少的Web应用程序使用任何模式对话框(HTML对等),尽管使用正确的库肯定是可行的。 – CommonsWare 2011-04-25 00:04:22

回答

45
  • 使用全局变量

如果你不想弄糟与简单Intent.putExtra()调用代码,并管理这个东西每个独特Activity你必须在应用程序中使用全局变量。扩展Application并存储您的应用程序一直存在所需的数据。要实际执行它,use this excellent answer。这将使活动之间的依赖关系消失。例如,假设你在应用程序的生命周期中需要一个“用户名”用于你的应用程序 - 这是一个很好的工具。不需要肮脏的Intent.putExtra()电话。

  • 使用样式制作的第一款Android应用程序时

一个常见的错误是一个通常只是开始编写XML意见。 XML文件将(无问题且非常快)转到很多代码行。在这里你可以有一个解决方案,你只需使用style属性来实现一个特定的行为。例如,考虑这段代码:

值/ styles.xml

<style name="TitleText"> 
    <item name="android:layout_height">wrap_content</item> 
    <item name="android:layout_width">wrap_content</item> 
    <item name="android:textSize">18sp</item> 
    <item name="android:textColor">#000</item> 
    <item name="android:textStyle">bold</item> 
</style> 

布局/ main.xml中

现在,如果你有,比方说,二TextView s和他们两个应该有相同的行为,使他们使用TitleText风格。示例代码:

<!--- ... --> 
<TextView 
    android:id="@+id/textview_one" 
    style="@style/TitleText" 
/> 

<TextView 
    android:id="@+id/textview_two" 
    style="@style/TitleText" 
/> 
<!--- ... --> 

很简单,您不需要重复代码。如果你真的想进一步看看这个问题,请看Layout Tricks: Creating Reusable UI Components

  • 使用字符串

这一点很短,但我想提到它是非常重要的。开发人员可能犯的另一个错误是跳过strings.xml,并在代码内部(他将需要它)编写UI消息(和属性名称)。使您的应用程序更易于维护;只需在strings.xml文件中定义消息和属性即可。

  • 创建并使用全球工具类

当我写我的第一个应用程序,我只写了(和重复),我需要它的方法。结果?许多方法在各种活动之间具有相同的行为。我学到的是做一个工具课。例如,假设您必须在所有活动中提出网络请求。在这种情况下,请在实际的Activity内跳过定义它们并为其制定静态方法。示例代码:

public final class Tools { 

    private Tools() { 
    } 

    public static final void sendData(String url, 
       String user, String pass) { 
     // URLConnections, HttpClients, etc... 
    } 

} 

现在,你可以使用此代码下面你Activity需要向服务器发送数据:

Tools.sendData("www.www.www", "user", "pass"); 

但是,你明白了吧。使用这个“模式”,你需要它,它会阻止你搞乱你的代码。

  • 让自定义类定义了用户需要与应用程序

这可能是最有用的交互点的行为。为了定义“用户需要与应用程序进行交互”,假设您有一个Menu,这个行的行数很长,为什么我们要把Menu的计算保留在同一个类中?每个小项目都会让你的代码变得更加痛苦 - 你的代码看起来像“意大利面条”。例如,而不是有这样的事情:

@Override 
public boolean onPrepareOptionsMenu(Menu menu) { 
    MenuItem item; 
    item = menu.findItem(R.id.menu_id_one); 
    if (aBooleanVariable) { 
     item.setEnabled(true); 
    } else { 
     item.setEnabled(false); 
    } 
    // More code... 
    return super.onPrepareOptionsMenu(menu); 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem i) { 
    // Code, calculations... 
    // ... 
    // ... 
    return super.onOptionsItemSelected(i); 
} 

它重新设计的东西是这样的:

private MyCustomMenuInstance mMenuInstance; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);   
    setContentView(R.layout.main); 

    mMenuInstance = new MyCustomMenuInstance(); 
} 

@Override 
public boolean onPrepareOptionsMenu(Menu menu) { 
    mMenuInstance.onPrepareOptionsMenu(menu); 
    return super.onPrepareOptionsMenu(menu); 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem i) { 
    mMenuInstance.onOptionsItemSelected(i); 
    return super.onOptionsItemSelected(i); 
} 

例如,MyCustomMenuInstance

public class MyCustomMenuInstance { 

    // Member fields.. 

    public MyCustomMenuInstance() { 
     // Init stuff. 
    } 

    public void onPrepareOptionsMenu(Menu menu) { 
     // Do things.. 
     // Maybe you want to modify a variable in the Activity 
     // class? Well, pass an instance as an argument and create 
     // a method for it in your Activity class. 
    } 

    public void onOptionsItemSelected(MenuItem i) { 
     // Do things.. 
     // Maybe you want to modify a variable in the Activity 
     // class? Well, pass an instance as an argument and create 
     // a method for it in your Activity class. 
    } 

} 

你看这是怎么回事。您可以将其应用于很多事情,例如onClick,onClickListener, onCreateOptionsMenu,该列表很长。要了解更多“最佳实践”,您可以看到来自Google here的一些示例应用程序。看看他们是如何以一种很好和正确的方式实现的。

最后的单词;保持你的代码干净,以合理的方式命名你的变量和方法,特别是以正确的方式。总是要明白自己在代码中的位置 - 这非常重要。

+0

对于你的抽象工具类不这样做。继承人的构成。这样做:http://en.wikipedia.org/wiki/Composition_over_inheritance – 2011-06-07 03:13:47

+0

@Robert Massaioli:这不是继承 - 只是一个静态方法的工具类;当你需要它时可用。 – Wroclai 2011-06-14 10:18:13

+0

啊对了,你让我感到困惑,因为你说这个类从来没有被实例化或者被分类的惯常方式是给它一个私有构造函数。如果你所有的方法都是公共静态的,那么你可以直接从任何地方直接调用它。我对你使用'抽象'感到困惑。 – 2011-06-14 10:52:17

3

如果处理用户界面是您最关心的问题,那么您需要掌握事件驱动编码。事件驱动编码背后的思想背后的所有现代UI系统,并在各种事情(不只是用户界面)有用。

学习时最简单的方法就是把每个组件和事件看作是独立的。所有你需要担心的是事件对象传入你的事件方法。如果您习惯于编写基本上从头到尾运行的应用程序,那么这是一种思维转变,但实践会让您很快就到达目的地。

6

从业余​​的角度来看,我不希望我的第一次尝试成为一个干净的,生产就绪的应用程序。我有时会吃意大利面,fettucini甚至馄饨代码。在这一点上,我试图重新思考什么是我不喜欢从代码中的最高,并搜索一个更好的选择:

  • 重新考虑你的类来更好地描述你的对象,
  • 保持代码中的每个方法到最低限度,
  • 避免依赖于静态变量的任何地方,你可以
  • 昂贵的任务使用线程,不使用它们的快速程序,
  • 的UI从应用程序逻辑(把它放在你的类分开代替),
  • 保持私有字段的任何地方,您可以:当你想改变你的类将是有帮助的,
  • 迭代通过这些,直到你喜欢的代码

一个我在看到的最常见的错误异步方法是在创建一个或多个线程的循环内部使用静态变量,而不考虑该值可能在另一个线程中更改。 避免静态!

由于OceanBlue指出,它可能无法从该清楚,final static变量不会造成任何危险,但公共静态变量可以变化。这对静力学本身并不是问题,但是有了这样一个概念,即它们将具有价值,然后发现其值发生了变化。可能很难找出问题所在。典型的例子是点击计数器或定时器值,当可能有多个视图点击或多个定时器时。

希望你会收到比我有更多经验的人的建议。祝你好运!

+0

@Aleamdam:你强调不使用静态。我想知道你对“公共最终静态”值有何看法?基本上,业务价值不是硬编码,而是可以放在一个单独的类中,如:MyBusinessDefs.java? – OceanBlue 2011-04-25 02:19:00

+1

@OceanBlue我强调不要依赖于**在执行线程**期间可能会改变的静态公共变量**。当然,最终的静态变量不会造成这个问题。事实上,我更喜欢它的使用,因为它不仅易于在需要时进行更改,而且还有助于提高阅读清晰度。我会在我的回答中进一步澄清这一点。 – Aleadam 2011-04-25 02:24:04

0

如何使用模型视图控制器模式?

你至少要在“模式”来隔离(对象或对象集) 所有国家和它的逻辑管理,并在 一个单独的类(也许Activity类) 所有的东西有关意见,听众,回调......)