开发一个负责所有网络任务的辅助网络类是不错的做法?

时间:2014-05-22 11:41:01

标签: android helper android-networking android-async-http

我创建了以下类:

public class AsyncHttpsClientHelper {

public static final int REMOVE_CREDIT_CARD = 1;
public static final int ENABLE_AUTORENEW = 2;
// +10 final ints...

private static AsyncHttpsClientHelper instance = null;
private static Activity activity;
// Some other variables

    private AsyncHttpsClientHelper(Context context) {
        // Initiate variables
    }

    public static AsyncHttpsClientHelper getInstance(Context context) {
        // Guarantees the same instance for this class (Singleton)
    }

    public void performNetworkTask(int networkTaskType, String value)
    {
        switch (networkTaskType)
        {
            case REMOVE_CREDIT_CARD:
            {
                CupsLog.d(TAG, "path: " + Consts.ACCOUNT_REMOVE_CREDIT_CARD_PATH);
                client.post(Consts.ACCOUNT_REMOVE_CREDIT_CARD_PATH , new JsonHttpResponseHandler() {

                 @Override
                 public void onSuccess(JSONObject result) {
                try {
                    CupsLog.d(TAG, Consts.ACCOUNT_REMOVE_CREDIT_CARD_PATH + " -> onSuccess, result: " + result.toString(3));
                    AccountService.getInstance(activity).pullAccountDetailsFromServer();
                    Toast.makeText(activity, "Your credit card was removed", Toast.LENGTH_SHORT).show();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

                 @Override
                 public void onFailure(Throwable arg0) {
                    CupsLog.d(TAG, "commitPaymentToServer -> onFailure");
                     BusProvider.getInstance().post(new DialogChangeEvent(DialogChangeEvent.REMOVE_CREDIT_CARD, "failed"));
                }
        });
        break;
            }
            case ENABLE_AUTORENEW:
            {
                // Do ENABLE_AUTORENEW logic
            }
            // +10 cases goes here...
        }
    }
}

这个类还没有完成,我还要在这里添加另外10个我在应用程序周围执行的其他网络调用。

要运行其中一个网络任务,我运行此行,例如:

AsyncHttpsClientHelper.getInstance(this).performNetworkTask(AsyncHttpsClientHelper.COMMIT_COUPON_TO_SERVER, event.getValue());

任务完成后,我使用Event事件Square工具触发Bus,以便为活动/片段布局提交所需的视觉更改。

问题:我的老板声称这是一种不好的做法,当我完成它时,这个课程会变得一团糟。更多的是他声称这个类应该是一个愚蠢的类,所有他知道如何做的是配置AsyncHttpClient对象并将其返回,以便我可以使用它并执行相关Activity内的https任务。基本上他说https调用本身应该位于Activity类中。我更喜欢这种方式,并认为它使我的活动更清洁,更好阅读。另一方面,他说这种方式更难以调试,而且这个类结合了Controller和View功能的一部分,它不应该这样做。

那么谁是对的?创建像这样的课真的是一种不好的做法吗?

8 个答案:

答案 0 :(得分:4)

请参阅Google IO 2010关于Android REST客户端应用的演示文稿 - 我认为它是您问题的完整答案。

https://www.youtube.com/watch?v=xHXn3Kg2IQE

干杯:)

答案 1 :(得分:3)

你保持对你的活动的静态引用 - 这是不好的做法!如果在长时间运行的网络运行期间手机旋转怎么办?

Google I / O演示文稿中描述的最强大,最干净的解决方案。

您的解决方案有一些缺点:

  • singleton不是线程安全的
  • 它使用Activity上下文 - 您可以轻松地获取内存泄漏或调用死活动UI
  • 用户界面和网络电话紧密相连
  • 它只支持一个活动

根据您的问题 - 是的,调用AsyncHttpClient将导致您建议使用更清晰的代码。

答案 2 :(得分:1)

考虑Dimitry关于轮换的内容,因为它是真的。切勿对与UI有任何连接的对象使用静态引用。它会导致内存泄漏,并且很难调试。

其他问题:

  • 忘记getInstance(上下文c)。 (实际上,你必须写这个因为 静态上下文引用)
  • 您的performNetworkTask方法具有"值"仅在其中一个任务中使用的属性。令人困惑的是,没有人会知道"价值"是,只有编写此代码的人。如果您需要其他请求的其他参数怎么办?将它们作为"值"等参数附加这将是一个烂摊子。您应该创建一个抽象的Request类,并为每个请求类型派生一个新类。这样就可以很容易地理解会发生什么,并且很容易扩展功能。
  • 我猜你的老板试图说你不应该把回调连接到你的助手类。网络可以由一个单独的类(最好是由服务或async http客户端)处理,但回调应该肯定在Activity中,因为那是反应发生的地方。您将如何以不同的方式对来自不同活动的请求做出反应?您的实现不能,因为所有回调都是有线的。看一下图书馆的网站,它有一个比较好的例子来说明如何实现这个: http://loopj.com/android-async-http/#recommended-usage-make-a-static-http-client

并回答您的问题:

  

我的老板声称这是一种不好的做法,而且这个班级会   当我完成它时会变得一团糟。

是的,它会变得一团糟(当你开始添加/修改功能时会变得更糟)。

  

更多的是他声称这个班级应该是一个愚蠢的班级   所有他知道如何做的是配置AsyncHttpClient对象和   返回它,以便我可以使用它并在内部执行https任务   相关活动。

应该是愚蠢的。在我看来,你可以保留performNetworkTask方法,但是你需要有回调参数来让调用者做出不同的反应。

public void performNetworkTask(Request request, JsonHttpResponseHandler handler);

您还应该放弃int networkTaskType。我的建议是使用抽象的Request类。但是,如果你喜欢这种方式,那么切换到Enum是最低限度的。

  

基本上他说https调用本身应该位于   活动类。

" Https来电"可以意味着什么。我认为他的意思是回调应该由调用者传递。

  

我更喜欢这种方式,并认为它使我的活动更清洁   并且更好阅读。

这样你在Activity中的代码肯定会少,但是你只能支持一个Activity!基本上,您只是将缺少的代码从Activity移动到此帮助程序类。更不用说以任何方式修改助手都会很痛苦。

  另一方面,他说这种方式更难   调试,这个类结合了Controller和View的一部分   它不应该做的功能。那么谁是对的?它真的是一个   创建像这样的类的不良做法?

  • 我同意您尝试将View部分连接到帮助程序类。
  • 我不知道他的意思是什么"难以调试",所以最好的 要问他。
  • 是的,这是一个不好的做法。你应该重构。

答案 3 :(得分:0)

使代码更易读,更易于维护是一种很好的做法。封装责任是两者兼顾的最佳方式之一。

对你的老板来说,一个很好的论据是:View中的View和服务器 STARTS 之间的连接以及服务器中的 END ,但获得它的人之间的联系完成(并且 RESPONSABLE )就是这个类。与Activity或服务器如何完成无关,只有结果。


根据您所分享的代码进行一些修改,我建议:

  • 删除构造函数和getInstance()
  • 创建initiator()方法并启动AsyncHttpClientGson和其他参数
  • 创建扩展助手的其他类并实现他们自己的特定performNetworkTask()(他们可以并且也应该具有他们特定的方法名称)
  • 静态使用performNetworkTask()
  • 开始处理回调(View对此负责)

会是这样的:

public class HttpsClientAsyncHelper {
   Acitivity activity;
   AsyncHttpClient client;
   Gson gson;

   // Other params

   public static void initiator(Context context)
   {
       activity = (Activity) context;
       client = new AsyncHttpClient().setCookieStore(CookieUtil.getInstance(activity)
                                .getPersistentCookieStore());
       gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
                               .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                               .create();
   }

   // Other methods
}

再创建10个类:

public class RemoveCreditCardAsyncTask extends HttpsClientAsyncHelper {

   public static void performNetworkTask(Context context)
   {
       initiator();
       // Do what you did in this specific case
   }
}

<强>用法:

 RemoveCreditCardAsyncTask.performNetworkTask(this);
 // specific method names
 AutoRenewAsyncTask.enableAutoRenew(this);
 AutoRenewAsyncTask.disableAutoRenew(this);
 // even more specific
 AutoRenewAsyncTask.enable(this);
 AutoRenewAsyncTask.disable(this);

我自己在一个名为Network的更通用的类中练习,它处理与WebService的所有通信:

serverPostRequest(String controller, String action, JSONObject jsonParameters) throws Exception {}

fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {} 

奖金:对您来说可能很有用的方法:

public static boolean isAvailable(Context context)
{
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();

    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

答案 4 :(得分:0)

也许来自Misko Hevery的链接:

http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/

及其后续行动:

http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/

会有所帮助。他专门处理信用卡应用程序中的单身人士,并且它具有隐含的MVC。 MVC无处不在。你通常需要一个很好的理由离开它。

你的逻辑中也有一个大的开关()。通常由OO中的多态性处理。方法擅长以单元测试友好的方式封装功能。

答案 5 :(得分:0)

我完全同意你的老板关于他说,这应该是一个愚蠢的阶级。而不是Helper类,您很可能需要一个类的 Executor Worker 类。单身人士大部分时间都是邪恶的,毕竟你最终也会泄露你的背景并最终导致内存泄漏。

有一种更好的方法,使用自我保留Fragments

现在考虑一下,将你的助手类变成一个自我保留的Fragment,它应该是系统的连接持有者,并且应该能够通过该连接执行某些任务。同样丢失switch...case并将您的任务变成某类RunnableCallable类。

现在你有一个基于片段的执行器,类和一堆可以执行的任务。这种方法将为您带来这些优势:

  • 由于我们的片段是自我保留的,它将像单身一样,
  • 您可以在活动之间使用此片段,这是使用单身时无法做到的事情,
  • 由于片段本身是一个Android组件,因此android会在您需要时为您提供上下文,因此您不必担心泄漏上下文或内存。
  • 即使您在某些任务正在运行时丢失了当前上下文(假设用户使用的主页按钮),您也可以等到另一个上下文可用(片段重新附加到某个活动)

顺便说一句,您也可以使用Service来代替Fragments,原则相同,但可能会更难实现,因为Service-Activity通信会增加另一层复杂性。

答案 6 :(得分:0)

尝试使用此方法进行与网络相关的任务:

1。创建HttpHelper类,其中初始化http对象并编写帮助程序方法以执行http请求。

2。为您的所有http请求创建单独的AsyncTask,并从此类初始化HttpHelper并执行网络操作,这有两个好处:

a)您的代码仍然可读且模块化,易于维护和调试。

b)由于网络请求是独立的,因此可以自由地在应用程序内的任何位置使用此类。

3。AsyncTask Interface回传,可以使用Handler,也可以直接传递活动对象,但这样可以泄露上下文这可能导致内存泄漏。

答案 7 :(得分:0)

回答以下问题:

  1. 你需要在每个方法中重复一些逻辑吗? 类?如果是 - 那么很可能你需要把它分成更多 类,以防止代码重复。
  2. 您的班级是否具有面向客户的输出(View),内部业务逻辑(Controller)和数据访问/持久性逻辑 (型号) - 如果它需要同时具有这两者,那么你会 可能喜欢拆分它以便将表示分开 业务逻辑和数据访问(MVC)。
  3. 您的类是否包含在其他用例/集成/等中可能有用的逻辑?如果是,您可能希望将此逻辑转换为单独的类(在实际类中继承或包含为属性。