AsyncTask Android - Design Pattern and Return Values

后端 未结 2 403
忘了有多久
忘了有多久 2020-12-07 23:15

I\'m writing an application that validates login credentials on an external webserver - so I have the basic issue of creating a login screen that when submitted will send an

相关标签:
2条回答
  • 2020-12-07 23:52

    suppose the data format with web api is json, my design pattern :

    common classes
    1.MyAsyncTask : extends AsyncTask
    2.BackgroundBase : parameters to server
    3.API_Base : parameters from server
    4.MyTaskCompleted : callback interface

    public class MyAsyncTask<BackgroundClass extends BackgroundBase,APIClass extends API_Base> extends AsyncTask<BackgroundClass, Void, APIClass> {
        private ProgressDialog pd ; 
        private MyTaskCompleted listener;
        private Context cxt;
        private Class<APIClass> resultType;
        private String url;
        private int requestCode;    
    
        public MyAsyncTask(MyTaskCompleted listener, Class<APIClass> resultType, int requestCode, String url){
            this.listener = listener;
            this.cxt = (Context)listener;
            this.requestCode = requestCode;
            this.resultType = resultType;
            this.url = url;
        }
        public MyAsyncTask(MyTaskCompleted listener, Class<APIClass> resultType, int requestCode, String url, ProgressDialog pd){
                this(listener, resultType, requestCode, url);
                this.pd = pd;
                this.pd.show();
        }   
    
        @Override
        protected APIClass doInBackground(BackgroundClass... params) {
            APIClass result = null;
            try {           
                //do something with url and params, and get data from WebServer api
                BackgroundClass oParams = params[0];
                String sUrl = url + "?d=" + URLEncoder.encode(oParams.getJSON(), "UTF-8");
                String source = "{\"RtnCode\":1, \"ResultA\":\"result aaa\", \"ResultB\":\"result bbb\"}";
    
                //to see progressdialog
                Thread.sleep(2000);
    
                result = new com.google.gson.Gson().fromJson(source, resultType);           
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return result;
        }
    
         @Override
         protected void onPostExecute(APIClass result) {
            super.onPostExecute(result);
    
            try {
                if(pd != null && pd.isShowing())
                    pd.dismiss();
    
                API_Base oApi_Base = (API_Base)result;          
                listener.onMyTaskCompleted(result , this.requestCode);                      
            } catch (Exception e) {
                e.printStackTrace();
            }           
        }
    
    }
    public class API_Base {
        public int RtnCode;
    
        public String getJSON(Context context) throws Exception
        {
            return new com.google.gson.Gson().toJson(this);
        }
    
    
        public String toString(){
            StringBuilder sb = new StringBuilder();
    
            for (Field field : this.getClass().getFields()) {
                try {
                    field.setAccessible(true); 
                    Object value = field.get(this); 
                    if (value != null) {
                        sb.append(String.format("%s = %s\n", field.getName(), value));
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
    
            }
    
            return sb.toString();
        }
    
    }
    public class BackgroundBase {
    
        public String getJSON() throws Exception
        {       
            return new com.google.gson.Gson().toJson(this);
        }
    
    }
    public interface MyTaskCompleted {
        void onMyTaskCompleted(API_Base oApi_Base, int requestCode) ;
    }
    


    example, let's call two api in one activity
    assume :
    API 1.http://www.google.com/action/a
    input params : ActionA
    output params : RtnCode, ResultA

    API 2.http://www.google.com/action/b
    input params : ActionB
    output params : RtnCode, ResultB

    classes with example :
    1.MyActivity : extends Activity and implements MyTaskCompleted
    2.MyConfig : utility class, i set requestCode here
    3.BackgroundActionA, BackgroundActionB : model classes for api's input params
    4.API_ActionA, API_ActionB : model classes for api's output params

    public class MyActivity extends Activity implements MyTaskCompleted {
        ProgressDialog pd;
        Button btnActionA, btnActionB;
        TextView txtResult;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.my_layout);
            btnActionA = (Button)findViewById(R.id.btn_actionA);
            btnActionB = (Button)findViewById(R.id.btn_actionB);
            txtResult = (TextView)findViewById(R.id.txt_result);
    
            btnActionA.setOnClickListener(listener_ActionA);
            btnActionB.setOnClickListener(listener_ActionB);
    
            pd = new ProgressDialog(MyActivity.this);
            pd.setTitle("Title");
            pd.setMessage("Loading");
        }
    
        Button.OnClickListener listener_ActionA = new Button.OnClickListener(){
    
            @Override
            public void onClick(View v) {
                //without ProgressDialog
                BackgroundActionA oBackgroundActionA = new BackgroundActionA("AAA");
                new MyAsyncTask<BackgroundActionA, API_ActionA>(MyActivity.this, 
                                                                API_ActionA.class, 
                                                                MyConfig.RequestCode_actionA,
                                                                "http://www.google.com/action/a").execute(oBackgroundActionA);
            }
    
        };
        Button.OnClickListener listener_ActionB = new Button.OnClickListener(){
    
            @Override
            public void onClick(View v) {
                //has ProgressDialog
                BackgroundActionB oBackgroundActionB = new BackgroundActionB("BBB");
                new MyAsyncTask<BackgroundActionB, API_ActionB>(MyActivity.this, 
                                                                API_ActionB.class, 
                                                                MyConfig.RequestCode_actionB,
                                                                "http://www.google.com/action/b",
                                                                MyActivity.this.pd).execute(oBackgroundActionB);
            }
    
        };
    
        @Override
        public void onMyTaskCompleted(API_Base oApi_Base, int requestCode) {
            // TODO Auto-generated method stub
            if(requestCode == MyConfig.RequestCode_actionA){
                API_ActionA oAPI_ActionA = (API_ActionA)oApi_Base;
                txtResult.setText(oAPI_ActionA.toString());
    
            }else if(requestCode == MyConfig.RequestCode_actionB){
                API_ActionB oAPI_ActionB = (API_ActionB)oApi_Base;
                txtResult.setText(oAPI_ActionB.toString());
    
            }
    
        }
    
    }
    public class MyConfig {
        public static String LogTag = "henrytest";
    
        public static int RequestCode_actionA = 1001;
        public static int RequestCode_actionB = 1002;
    }
    public class BackgroundActionA extends BackgroundBase {
        public String ActionA ;
    
        public BackgroundActionA(String actionA){
            this.ActionA = actionA;
        }
    
    }
    public class BackgroundActionB extends BackgroundBase {
        public String ActionB;
    
        public BackgroundActionB(String actionB){
            this.ActionB = actionB;
        }
    }
    public class API_ActionA extends API_Base {
        public String ResultA;
    }
    public class API_ActionB extends API_Base {
        public String ResultB;
    }
    


    Advantage with this design pattern :
    1.one Advantage for multi api
    2.just add model classes for new api, ex: BackgroundActionA and API_ActionA
    3.determine which API by different requestCode in callback function : onMyTaskCompleted

    0 讨论(0)
  • 2020-12-08 00:05

    If you are designing a reusable task for something like this, you need to identify a reusable return type. Its a design decision on your part. Ask yourself, "Are my HTTP operations similar in both the mechanisms with which they are called and in which their data is processed?" If so, you can design a single class to do both. If not, you probably need different classes for your different remote operations.

    In my personal use, I have an object i attach key value pairs to and the common return type is the HttpEntity. This is the return type for both HTTP Get and Post, and this seems to work ok in my scenarios because i throw exceptions in exceptional HTTP result situations, like 404. Another nice aspect of this setup is that the code to attach parameters to a get or post are fairly similar, so this logic is pretty easy to construct.


    An example would be something like this (psuedo):

    public interface DownloadCallback {
       void onSuccess(String downloadedString);
       void onFailure(Exception exception);
    }
    

    Then in your code, where you go to do the download:

    DownloadCallback dc = new DownloadCallback(){
       public void onSuccess(String downloadedString){
         Log.d("TEST", "Downloaded the string: "+ downloadedString);
       }
       public void onFailure(Exception e){
         Log.d("TEST", "Download had a serious failure: "+ e.getMessage());
       }
     }
    
     DownloadAsyncTask dlTask = new DownloadAsyncTask(dc);
    

    Then inside the constructor of DownloadAsyncTask, store the DownloadCallback and, when the download is complete or fails, call the method on the download callback that corresponds to the event. So...

    public class DownloadAsyncTask extends AsyncTask <X, Y, Z>(){
      DownloadCallback dc = null;
    
      DownloadAsyncTask(DownloadCallback dc){
        this.dc = dc;
      }
    
      ... other stuff ...
    
      protected void onPostExecute(String string){
        dc.onSuccess(string);
      }
    }
    

    I'm going to reiterate that I think for the good of yourself, you should pass back HttpEntities. String may seem like a good idea now, but it really leads to trouble later when you want to do more sophisticated logic behind your http calls. Of course, thats up to you. Hopefully this helps.

    0 讨论(0)
提交回复
热议问题