3

I need some help on the basic architecture of my code around the login process. I'm implementing Async Http processing to get things working for ICS.

the goal of this code is for logging into my app.

  • Login form submit from UI (Login.java)
  • connect to our server and pass username / password via http get XML result
  • parse XML results to array. (ParseXML.java)
  • display result feedback in UI.

Now this all worked in my program however after trying to test with ICS which enforces Asyc HTTP connections i quickly realised my problem and led me to doubt my entire design...

the basic way it currently works:

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);
      }
    }
  }

I'm mostly concerned that its bad design to be doing things this way and I should simply move the XML and http connection code within my Login.java file so its all included (UI, HTTP, XML Parsing, Asyc).

Particularly i'm concerned with calling back to Login.doFinished() from onPostExecute(). is this bad for memory? I'm worried that would cause the ParseXML object to avoid garbage collection because it is now going back to Login Activity which will continue running once the user is logged in in turn holding ParseXML open.

I come from a PHP background so I have been trying to keep all my XML parsing and HTTP processing within the ParseXML "module" so that i know where to look for changes to this.

At the moment ParseXML handles all http work, ie, getUsers, getChannels, addUser, delUser, doLogin etc. But Should I try moving all the code to handle XML and HTTP connections (async) within the relevant screen/ activity so they are self contained?

I really appreciate any help on this

Kev
  • 118,037
  • 53
  • 300
  • 385
wired00
  • 13,930
  • 7
  • 70
  • 73

3 Answers3

2

I would Use interface in this case

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);

    }
}
Vipul
  • 27,808
  • 7
  • 60
  • 75
1

From your post I assume that you have a LoginActivity that creates a ParseXML which then has a LoginObject (can you call that "LoginCallback"?) to return the result to the LoginActivity that displays the result. This should work, it's a callback pattern that is used a lot. A callback is generally defined as an interface, not a class.

Another approach would be to start an AsyncTask in LoginActivity, that calls ParseXML in its doInBackground, and returns the result directly to LoginActivity in onPostExecute.

Christine
  • 5,617
  • 4
  • 38
  • 61
  • Thanks Christine yep that 2nd point you make is what I was trying to get at in my post I'm considering putting the code just as you say to keep it more encapsulated within the "Login Screen" class. – wired00 Jun 01 '12 at 04:38
  • PS: Regarding your first point I was trying also to get a callback going because i was sure that was a good way of doing this, and I even was trying to implement a "interface" from my login screen to do it. Your suggestion gives me renewed hope this might work so i'll look into that again. Currently though my code is simply passing `Login.this` from `Login.java` to `ParseXML`. `ParseXML>Async` then calls a public method within `Login` to say "hey i'm done..". But as i mentioned, i worry this is a memory issue because it cannot be collected by the GC. but i could be completely wrong on that! – wired00 Jun 01 '12 at 04:41
1

I should simply move the XML and http connection code within my Login.java file so its all included (UI, HTTP, XML Parsing, Asyc).

This is exactly what we trying to avoid in an OO design, a big damn class contains everything (UI stuff, business logic and etc).

Based on your requirement, a good OO deisgn IMO is:

  1. Create interface IBusniessDAO define all method signatures (getUsers, getChannels and etc).
  2. Create a POJO (AKA. Plain Old Java Object) class XmlParser implements IBusinessDAO, in this class, write you method implementation normally and do not handle any asynchronous execution here (that is not the job of Business POJO). where and how these methods are intended to be used (synchronously or asynchronously) is determined in the caller class (i.e. Activity). If says in the future, you want to replace XmlParser with JsonParser, simple create JsonParser implements IBusinessDAO and replace XmlParser.
  3. AsyncTask always stay with Activity (as an inner class), if an Activity requires network functions, simply initialize you IbusinessDAO object in this Activity and call the network-related method properly in AsyncTask.doInBackground() method, and update the UI stuff managed by this activity directly in AsyncTask.onPostExecute() method.

Check out the sample code I written in this answer before, hope this helps.

Community
  • 1
  • 1
yorkw
  • 40,926
  • 10
  • 117
  • 130
  • as i said in the other thread this is a big help yorkw i will be researching about POJO object design. I liked your point in the other thread about trying to leave all Async code within the activity because it basically has 2 tasks performing a background task, THEN updating your UI. and its stupid for me to try burying my async code down in psuedo BO's which is further _away_ from my UI. Thanks for the big help mate – wired00 Jun 01 '12 at 06:26
  • Perhaps POJO is not a proper terms in this scenario, don't concern yourself too much on the actual word. It is just a regular java class for isolating/centralizing network related code, much like what you have already did in ParseXML.java, The point here is better not to perform any asynchronous code or android-related code in this raw DAO (AKA. Data Access Object) class, and leave them (i.e. AsyncTask) stay with Activity, as a better code-refactoring from OO perspective. – yorkw Jun 01 '12 at 10:23
  • right thanks very much for your answer a more design philosophy was more what i needed. Moving async code into my activity and leaving my bus dao and dbo objects seperate makes much more sense – wired00 Jun 02 '12 at 04:07
  • ... ive also been reading more on design using interfaces. So will redesign to use IDAO interface just so there is potential codr reuse. Cheers – wired00 Jun 02 '12 at 04:10