【问题标题】:Android AsyncTask and object passingAndroid AsyncTask 和对象传递
【发布时间】:2012-06-04 21:28:54
【问题描述】:

我需要一些关于登录过程代码基本架构的帮助。我正在实现异步 Http 处理以使 ICS 工作正常。

此代码的目标是登录我的应用程序。

  • 从 UI (Login.java) 提交登录表单
  • 连接到我们的服务器并通过http传递用户名/密码获取XML结果
  • 将 XML 结果解析为数组。 (ParseXML.java)
  • 在 UI 中显示结果反馈。

现在这一切都在我的程序中运行了,但是在尝试使用强制 Asyc HTTP 连接的 ICS 进行测试后,我很快意识到了我的问题并让我怀疑我的整个设计......

目前工作的基本方式:

Login.java:

  class Login {
    ...
    ParseXML myXMLParser = new ParseXML();  
    myXMLParser.doLogin(username, password, Login.this);    

    public doFinished(result) {
      // update UI
    }
    ...
  }

ParseXML.java:

  class ParseXML {
    // class variable to hold login object for async to access
    public Login loginObj;
    ...
    public void doLogin(String _username, String _password, Login _l) {
      loginObj = (Login) _l;
      ...

      // create loginUrl string to run through async
      ...
      new DownloadFilesTask().execute(loginUrl);
    }

    class DownloadFilesTask extends AsyncTask<a, b, c> {
      doInBackground() {
        // do stuff
        // download result of http call
        // parse XML
      }

      onPostExecute(result) {        
        // call the public class variable of login object i have and tell it to update the UI
        // pass back the result array.
        loginObj.doFinished(result);
      }
    }
  }

我主要担心以这种方式做事的设计不好,我应该简单地将 XML 和 http 连接代码移动到我的 Login.java 文件中,以便将其全部包含在内(UI、HTTP、XML Parsing、Asyc)。

我特别关心从 onPostExecute() 回调 Login.doFinished()。这对记忆有害吗?我担心这会导致 ParseXML 对象避免垃圾收集,因为它现在返回登录活动,一旦用户登录,它将继续运行,而 ParseXML 又保持打开状态。

我来自 PHP 背景,所以我一直在尝试将我的所有 XML 解析和 HTTP 处理保留在 ParseXML“模块”中,以便我知道在哪里寻找对此的更改。

目前ParseXML 处理所有http 工作,即getUsersgetChannelsaddUserdelUserdoLogin 等。但是我是否应该尝试移动所有代码来处理 XML 和 HTTP相关屏幕/活动中的连接(异步),因此它们是独立的?

非常感谢您对此的任何帮助

【问题讨论】:

    标签: java android android-asynctask


    【解决方案1】:

    在这种情况下我会使用接口

    下载Helper.java

    public interface DownloadHelper 
    {
       public void OnDownloadFinish(String Response);
       public void OnDownloadFailed(String Response); 
    }
    

    Login.java

    class Login {
    
        DownloadHelper helper=new DownloadHelper()
        {
          public void OnDownloadFinish(String Response)
           {
               // update UI
    
           } 
    
          public void OnDownloadFailed(String Response)
           {
               //Take Action
           }     
        };  
    
    
        new ParseXMLTask(this,helper).execute(username, password);
    }
    

    ParseXMLTask.java

    class ParseXMLTask extends AsyncTask<Object,Object,Object>
    {
        DownloadHelper helper;
        public ParseXMLTask (Context context,DownloadHelper helper)
        {
           this.helper=helper;
        }   
        public void onPreExecute(){}
    
        public Object DoInBackground(Object object)
        {
           // do stuff
          // download result of http call
         // parse XML
         return parsed response
        }  
    
       public void onPostExceute(Object object)
        {
    
           helper.OnDownloadFinish((String)object);
           or
            helper.OnDownloadFailed((String)object);
    
        }
    }
    

    【讨论】:

    • 这似乎是一个不错的方法,但它不是仍然容易出现内存泄漏吗?
    【解决方案2】:

    我应该简单地在我的 Login.java 文件中移动 XML 和 http 连接代码,以便将其全部包含在内(UI、HTTP、XML Parsing、Asyc)。

    这正是我们在 OO 设计中试图避免的,一个该死的大类包含所有内容(UI 内容、业务逻辑等)。

    根据您的要求,一个好的 OO 设计 IMO 是:

    1. 创建接口 IBusniessDAO 定义所有方法签名(getUsers、getChannels 等)。
    2. 创建一个POJO(AKA.Plain Old Java Object)类XmlParser实现了IBusinessDAO,在这个类中,你可以正常编写方法实现,这里不处理任何异步执行(这不是Business POJO的工作)。这些方法的使用位置和方式(同步或异步)在调用者类(即 Activity)中确定。如果说以后想用JsonParser替换XmlParser,简单创建JsonParser实现IBusinessDAO,替换XmlParser。
    3. AsyncTask 总是留在Activity(作为一个内部类),如果一个Activity 需要网络功能,只需在这个Activity 中初始化你的IbusinessDAO 对象,并在AsyncTask.doInBackground() 方法中正确调用网络相关的方法,然后更新UI此活动直接在 AsyncTask.onPostExecute() 方法中管理的内容。

    查看我之前在answer 中编写的示例代码,希望对您有所帮助。

    【讨论】:

    • 正如我在另一个线程中所说,这是一个很大的帮助 yorkw 我将研究 POJO 对象设计。我喜欢您在另一个线程中关于尝试将所有异步代码留在活动中的观点,因为它基本上有 2 个任务执行后台任务,然后更新您的 UI。对我来说,尝试将我的异步代码隐藏在离我的 UI 远离的伪 BO 中是愚蠢的。感谢大佬的帮助
    • 也许POJO在这种情况下不是一个合适的术语,不要太在意实际的词。它只是一个用于隔离/集中网络相关代码的常规 java 类,就像您已经在 ParseXML.java 中所做的那样,这里的要点是最好不要在这个原始 DAO(AKA.数据访问对象)类,并将它们(即 AsyncTask)留在 Activity 中,作为从 OO 角度更好的代码重构。
    • 非常感谢您的回答,更多的设计理念正是我所需要的。将异步代码移动到我的活动中并将我的总线 dao 和 dbo 对象分开会更有意义
    • ... 我还阅读了更多关于使用接口进行设计的内容。因此将重新设计以使用 IDAO 接口,以便有潜在的 codr 重用。干杯
    【解决方案3】:

    从您的帖子中,我假设您有一个 LoginActivity,它创建一个 ParseXML,然后有一个 LoginObject(您可以称之为“LoginCallback”吗?)将结果返回给显示结果的 LoginActivity。这应该可行,这是一种经常使用的回调模式。回调通常定义为接口,而不是类。

    另一种方法是在 LoginActivity 中启动一个 AsyncTask,在其 doInBackground 中调用 ParseXML,并将结果直接返回给 onPostExecute 中的 LoginActivity。

    【讨论】:

    • 谢谢克里斯汀,是的,你提出的第二点是我在帖子中想要表达的意思.
    • PS:关于你的第一点,我也试图让回调继续,因为我确信这是这样做的好方法,我什至试图从我的登录中实现一个“接口”屏幕来做到这一点。你的建议给了我新的希望,这可能会奏效,所以我会再次调查。目前虽然我的代码只是将Login.thisLogin.java 传递给ParseXMLParseXML&gt;Async 然后调用Login 中的公共方法说“嘿,我完成了..”。但正如我所提到的,我担心这是一个内存问题,因为它不能被 GC 收集。但我可能完全错了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多