异步编程最佳实践

时间:2011-04-24 23:12:58

标签: java android asynchronous

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

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

4 个答案:

答案 0 :(得分:46)

  • 使用全局变量

如果您不希望通过简单的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并且它们都应该具有相同的行为,那么让它们使用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 文件中定义消息和属性。

  • 创建和使用全局工具类

当我编写第一个应用程序时,我只是编写(并重复)了我需要它的方法。结果?许多方法在各种活动之间具有相同的行为。我学到的是制作工具类。例如,假设您必须在所有活动中发出Web请求。在这种情况下,跳过在实际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,行数在行数方面很长,为什么我们保留{{1在同一个班级的计算?每个小项目都会让你的Menu课程变得更长 - 你的代码看起来像“意大利面条”。例如,而不是像这样的东西:

Activity

将其重新设计为:

@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. } } onClickonClickListener,列表很长。要了解更多“最佳做法”,您可以查看Google here的一些示例应用程序。看看他们是如何以一种美好而正确的方式实现的。

最后一句话;保持代码清洁,以合理的方式命名变量和方法,尤其是以正确的方式。始终,始终了解您在代码中的位置 - 这非常重要。

答案 1 :(得分:6)

从业余角度来看,我不认为我的第一次尝试是一个干净的,生产就绪的应用程序。我有时候会吃意大利面条,fettucini甚至是馄饨代码。那时,我试图重新思考代码中最不喜欢的内容,并寻找更好的选择:

  • 重新思考您的课程以更好地描述您的对象,
  • 将每种方法中的代码保持在最低限度,
  • 尽可能避免依赖于静态变量,
  • 使用线程执行昂贵的任务,不要将它们用于快速程序,
  • 将UI与应用程序逻辑分开(将其保留在您的类中),
  • 将私人字段保留在任何地方:当您想要更改课程时,它会很有用,
  • 迭代这些直到您喜欢代码

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

正如OceanBlue指出的那样,可能不清楚final static变量不会产生任何危险,但可以的公共静态变量可能会发生变化。静态本身不是问题,但是他们会有一个值,然后发现价值发生了变化。可能很难发现问题所在。典型的例子是点击计数器或计时器值,当可以点击多个视图或多个计时器时。

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

答案 2 :(得分:3)

如果处理UI是您最关心的问题,那么您将需要掌握事件驱动的编码。事件驱动编码背后的思想背后是所有现代UI系统,并且在各种事物(不仅仅是UI)中都很有用。

在学习过程中,我最简单的方法就是将每个组件和事件看作是独立的。您需要担心的是传递给您的事件方法的事件对象。如果你习惯于编写基本上从头到尾运行的应用程序,那么这是一种思维转变,但是练习会很快让你到达那里。

答案 3 :(得分:0)

使用模型视图控制器模式怎么样?

至少你必须在“模型”中隔离(对象或对象集) 所有的国家及其逻辑管理,并在 一个单独的类(可能是Activity类) 所有与视图,听众,回调,...相关的东西......)