Android AsyncTask 和对象传递

3
我需要关于登录过程代码基本架构的帮助。我正在实施Async Http处理以使ICS工作。
这段代码的目的是用于登录到我的应用程序。
  • 从UI提交登录表单(Login.java)
  • 通过http get XML结果连接到我们的服务器并传递用户名/密码
  • 将XML结果解析为数组。(ParseXML.java)
  • 在UI中显示结果反馈。
现在,在我的程序中所有这些都可以工作,但是在尝试使用强制执行异步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 解析、异步)。

特别是我担心从 onPostExecute() 回调到 Login.doFinished() 是否会导致内存问题?我担心这会导致 ParseXML 对象避免垃圾回收,因为它现在返回到 Login Activity,并在用户登录后继续运行,从而保持 ParseXML 开启。

我来自 PHP 背景,所以一直试图将所有的 XML 解析和 HTTP 处理保存在 ParseXML “模块”中,这样我就知道在哪里寻找更改。

目前,ParseXML 处理所有的 HTTP 工作,例如 getUsersgetChannelsaddUserdelUserdoLogin 等。但我是否应该尝试将处理 XML 和 HTTP 连接(异步)的所有代码移动到相关屏幕/活动中,使其自包含?

我非常感谢您的帮助。

3个回答

2
我会在这种情况下使用接口。 DownloadHelper.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);

    }
}

这似乎是一个不错的方法,但它仍然容易出现内存泄漏问题吗? - Apostrofix

1
从您的帖子中我推断出您有一个LoginActivity,它创建了一个ParseXML,然后有一个LoginObject(您可以称之为“LoginCallback”吗?)来将结果返回给显示结果的LoginActivity。这应该可以工作,这是经常使用的回调模式。回调通常被定义为接口而不是类。
另一种方法是在LoginActivity中启动一个AsyncTask,在其doInBackground中调用ParseXML,并直接在onPostExecute中将结果返回给LoginActivity。

谢谢Christine,是的,你提到的第二点正是我在帖子中试图表达的。我正在考虑按照你所说的方式将代码放置,以使其更加封装在“登录屏幕”类中。 - wired00
关于您的第一个问题,我也试图实现回调,因为我确定这是一个好的方法。 我甚至在我的登录屏幕上尝试实现“接口”来执行此操作。 您的建议给了我新的希望,所以我会再次尝试一下。 不过目前,我的代码只是从Login.java传递 Login.thisParseXMLParseXML>异步然后调用Login中的公共方法以表明“嘿,我完成了……”。 但是正如我所提到的,我担心这是一个内存问题,因为它无法被GC收集,但我完全可能是错的! - wired00

1

我应该将XML和HTTP连接代码移动到我的Login.java文件中,以便所有内容都包含在内(UI、HTTP、XML解析、异步)。

这正是我们在OO设计中试图避免的,一个大家伙类包含所有东西(UI元素、业务逻辑等)。

根据您的要求,我认为一个好的OO设计如下:

  1. 创建接口IBusniessDAO,定义所有方法签名(getUsers、getChannels等)。
  2. 创建POJO(即普通的Java对象)类XmlParser实现IBusinessDAO,在此类中,通常编写您的方法实现,并且不要在此处处理任何异步执行(这不是业务POJO的工作)。这些方法的使用方式(同步或异步)及其如何使用取决于调用者类(例如Activity)。如果将来想要用JsonParser替换XmlParser,只需创建JsonParser实现IBusinessDAO并替换XmlParser即可。
  3. AsyncTask始终与Activity一起(作为内部类),如果Activity需要网络功能,只需在此Activity中初始化您的IbusinessDAO对象,并在AsyncTask.doInBackground()方法中正确调用与网络相关的方法,并在AsyncTask.onPostExecute()方法中直接更新此Activity管理的UI元素。

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


正如我在另一个帖子中所说,这对我来说是一个很大的帮助,Yorkw。我将研究POJO对象设计。我喜欢你在另一个帖子中提到的观点,即尝试将所有异步代码留在活动中,因为它基本上有两个任务:执行后台任务,然后更新您的UI。而且,对我来说,把我的异步代码埋藏在伪BO中是愚蠢的,因为它离我的UI更远了。感谢你的大力帮助,伙计。 - wired00
也许在这种情况下,POJO不是一个合适的术语,不要过于关注实际单词。它只是一个常规的Java类,用于隔离/集中与网络相关的代码,就像您已经在ParseXML.java中所做的那样。这里的重点是最好不要在这个原始DAO(即数据访问对象)类中执行任何异步代码或Android相关代码,并将它们(即AsyncTask)留给Activity,从面向对象的角度进行更好的代码重构。 - yorkw
非常感谢您的回答,更多的设计哲学正是我所需要的。将异步代码移入我的活动中,并将我的总线DAO和DBO对象保持分离,这样做更有意义。 - wired00
我最近也在阅读更多关于使用接口设计的内容。所以,我将重新设计代码,使用IDAO接口,以便有潜在的代码重用。谢谢。 - wired00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接