studio - AsyncTask Android-Patrón de diseño y valores de retorno
oncancelled asynctask android (2)
Si está diseñando una tarea reutilizable para algo como esto, necesita identificar un tipo de retorno reutilizable. Es una decisión de diseño de tu parte. Pregúntese: "¿Son mis operaciones HTTP similares tanto en los mecanismos con los que se llaman como en los que se procesan sus datos?" Si es así, puedes diseñar una sola clase para hacer ambas cosas. Si no es así, probablemente necesite clases diferentes para sus diferentes operaciones remotas.
En mi uso personal, tengo un objeto al que adjunto pares de valores clave y el tipo de retorno común es HttpEntity . Este es el tipo de retorno tanto para HTTP Get como para Post, y parece que funciona bien en mis escenarios, ya que arrojo excepciones en situaciones de resultados HTTP excepcionales, como 404. Otro aspecto interesante de esta configuración es que el código para adjuntar parámetros a un o las publicaciones son bastante similares, por lo que esta lógica es bastante fácil de construir.
Un ejemplo sería algo como esto (psuedo):
public interface DownloadCallback {
void onSuccess(String downloadedString);
void onFailure(Exception exception);
}
Luego en tu código, donde vas a hacer la descarga:
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);
Luego, dentro del constructor de DownloadAsyncTask, almacene DownloadCallback y, cuando la descarga se complete o falle, llame al método en la devolución de llamada de la descarga que corresponda al evento. Asi que...
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);
}
}
Voy a reiterar que creo que, por el bien de ustedes mismos, debería devolver a HttpEntities. La cadena puede parecer una buena idea ahora, pero realmente puede ocasionar problemas más adelante cuando desee hacer una lógica más sofisticada detrás de sus llamadas http. Por supuesto, eso depende de ti. Esperemos que esto ayude.
Estoy escribiendo una aplicación que valida las credenciales de inicio de sesión en un servidor web externo, por lo que tengo el problema básico de crear una pantalla de inicio de sesión que, cuando se envíe, enviará una solicitud HTTP a un servidor en segundo plano y no causará que la interfaz de usuario se bloquee. un ProgressDialog para el usuario.
Mi problema radica en que quiero escribir una clase de Solicitud HTTP genérica que extienda AsyncTask, así que cuando llame a .execute()
luego .execute()
parámetros de Cadena que pueden contener algo como ''post'', y cuando se doInBackground
se verá el ''publicar'' la cadena y luego reenviar esos parámetros a la llamada respectiva en mi clase. El pseudo código sería algo así como
public class HTTPOperations extends AsyncTask<String, Void, String>
{
doInBackground(String... string1,additionalParams)
{
if string1.equals "post"
response = httpPost(additionalParams)
return response;
}
httpPost(params)
{
// do http post request
}
}
Esto es todo en lo que podría pensar, además de crear una clase para cada solicitud HTTP Post / GET, etc., que deseo realizar y extender ASyncTask ...
Lo que me lleva a mi siguiente problema, si el HTTP POST es exitoso y devuelve un token de autenticación, ¿cómo accedo a este token?
Debido a que el nuevo httpOperations.execute (), no devuelve la cadena de doInBackground, sino un valor de tipo
Lo siento si esto no tiene sentido, no puedo resolver esto en absoluto. Por favor, pida una explicación si la necesita. Las ideas y los patrones de diseño de AsyncTask son enormemente bienvenidos.
Supongamos que el formato de datos con api web es json, mi patrón de diseño:
clases comunes
1.MyAsyncTask: extiende AsyncTask
2.BackgroundBase: parámetros al servidor
3.API_Base: parámetros del servidor
4.MyTaskCompleted: interfaz de devolución de llamada
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) ;
}
ejemplo, llamemos dos api en una actividad
asumir
API 1. http://www.google.com/action/a
parámetros de entrada: ActionA
params de salida: RtnCode, ResultA
API 2. http://www.google.com/action/b
parámetros de entrada: ActionB
parámetros de salida: RtnCode, ResultB
Clases con ejemplo:
1.MyActivity: extiende la actividad e implementa MyTaskCompleted
2.MyConfig: clase de utilidad, establezco requestCode aquí
3.BackgroundActionA, BackgroundActionB: clases modelo para los parámetros de entrada de api
4.API_ActionA, API_ActionB: clases modelo para los parámetros de salida de la API
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;
}
Ventaja con este patrón de diseño :
1. una ventaja para multi api
2. simplemente agrega clases modelo para la nueva api, ej: BackgroundActionA y API_ActionA
3.determinar qué API por diferente requestCode en función de devolución de llamada: onMyTaskCompleted