una otra objetos objeto net metodos instanciar externas dentro crear constructores como clases clase anidar anidados anidadas anidada java android asynchronous android-asynctask

otra - objetos anidados en java



¿Cuál es la forma correcta de implementar AsyncTask? ¿clase anidada estática o no estática? (3)

El artículo vinculado ya lo dice

Sin embargo, esto enfatiza que desea que doInBackground () de su AsyncTask esté completamente desacoplado de la Actividad. Si solo tocas tu actividad en el hilo principal de la aplicación, tu AsyncTask puede sobrevivir intacta al cambio de orientación.

No toque la Actividad (por ejemplo, sus miembros) desde AsyncTask , que está en línea con las Clases anidadas estáticas

Clases anidadas estáticas
Al igual que con los métodos y variables de clase, una clase anidada estática está asociada a su clase externa. Y al igual que los métodos de clases estáticas, una clase anidada estática no puede hacer referencia directamente a variables de instancia o métodos definidos en su clase adjunta; solo puede usarlos a través de una referencia de objeto.

Aunque, los ejemplos de Android, AsyncTask reference y Using AsyncTask siguen utilizando clases anidadas no estáticas.

Y de acuerdo con esta clase anidada estática en Java, ¿por qué? , Primero iría con la clase interna estática y recurriría solo a la versión no estática, si es realmente necesario.

El "Inicio de sesión" de los ejemplos de Android implementó AsyncTask como una clase interna no estática. Sin embargo, de acuerdo con Commonsguys, esta clase debe ser estática y usar referencia débil a la actividad externa. Ver esto .

Entonces, ¿cuál es la forma correcta de implementar AsyncTask ? Estático o no estático?

Implementación Commonsguy
https://github.com/commonsguy/cw-android/tree/master/Rotation/RotationAsync/

Ejemplo de inicio de sesión de Google

package com.example.asynctaskdemo; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.TargetApi; import android.app.Activity; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.view.KeyEvent; import android.view.Menu; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.TextView; /** * Activity which displays a login screen to the user, offering registration as * well. */ public class LoginActivity extends Activity { /** * A dummy authentication store containing known user names and passwords. * TODO: remove after connecting to a real authentication system. */ private static final String[] DUMMY_CREDENTIALS = new String[] { "[email protected]:hello", "[email protected]:world" }; /** * The default email to populate the email field with. */ public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL"; /** * Keep track of the login task to ensure we can cancel it if requested. */ private UserLoginTask mAuthTask = null; // Values for email and password at the time of the login attempt. private String mEmail; private String mPassword; // UI references. private EditText mEmailView; private EditText mPasswordView; private View mLoginFormView; private View mLoginStatusView; private TextView mLoginStatusMessageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); // Set up the login form. mEmail = getIntent().getStringExtra(EXTRA_EMAIL); mEmailView = (EditText) findViewById(R.id.email); mEmailView.setText(mEmail); mPasswordView = (EditText) findViewById(R.id.password); mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { if (id == R.id.login || id == EditorInfo.IME_NULL) { attemptLogin(); return true; } return false; } }); mLoginFormView = findViewById(R.id.login_form); mLoginStatusView = findViewById(R.id.login_status); mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message); findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { attemptLogin(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.activity_login, menu); return true; } /** * Attempts to sign in or register the account specified by the login form. * If there are form errors (invalid email, missing fields, etc.), the * errors are presented and no actual login attempt is made. */ public void attemptLogin() { if (mAuthTask != null) { return; } // Reset errors. mEmailView.setError(null); mPasswordView.setError(null); // Store values at the time of the login attempt. mEmail = mEmailView.getText().toString(); mPassword = mPasswordView.getText().toString(); boolean cancel = false; View focusView = null; // Check for a valid password. if (TextUtils.isEmpty(mPassword)) { mPasswordView.setError(getString(R.string.error_field_required)); focusView = mPasswordView; cancel = true; } else if (mPassword.length() < 4) { mPasswordView.setError(getString(R.string.error_invalid_password)); focusView = mPasswordView; cancel = true; } // Check for a valid email address. if (TextUtils.isEmpty(mEmail)) { mEmailView.setError(getString(R.string.error_field_required)); focusView = mEmailView; cancel = true; } else if (!mEmail.contains("@")) { mEmailView.setError(getString(R.string.error_invalid_email)); focusView = mEmailView; cancel = true; } if (cancel) { // There was an error; don''t attempt login and focus the first // form field with an error. focusView.requestFocus(); } else { // Show a progress spinner, and kick off a background task to // perform the user login attempt. mLoginStatusMessageView.setText(R.string.login_progress_signing_in); showProgress(true); mAuthTask = new UserLoginTask(); mAuthTask.execute((Void) null); } } /** * Shows the progress UI and hides the login form. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) private void showProgress(final boolean show) { // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow // for very easy animations. If available, use these APIs to fade-in // the progress spinner. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime); mLoginStatusView.setVisibility(View.VISIBLE); mLoginStatusView.animate().setDuration(shortAnimTime).alpha(show ? 1 : 0).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE); } }); mLoginFormView.setVisibility(View.VISIBLE); mLoginFormView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); } }); } else { // The ViewPropertyAnimator APIs are not available, so simply show // and hide the relevant UI components. mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE); mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); } } /** * Represents an asynchronous login/registration task used to authenticate * the user. */ public class UserLoginTask extends AsyncTask<Void, Void, Boolean> { @Override protected Boolean doInBackground(Void... params) { // TODO: attempt authentication against a network service. try { // Simulate network access. Thread.sleep(2000); } catch (InterruptedException e) { return false; } for (String credential : DUMMY_CREDENTIALS) { String[] pieces = credential.split(":"); if (pieces[0].equals(mEmail)) { // Account exists, return true if the password matches. return pieces[1].equals(mPassword); } } // TODO: register the new account here. return true; } @Override protected void onPostExecute(final Boolean success) { mAuthTask = null; showProgress(false); if (success) { finish(); } else { mPasswordView.setError(getString(R.string.error_incorrect_password)); mPasswordView.requestFocus(); } } @Override protected void onCancelled() { mAuthTask = null; showProgress(false); } } }

Si depende de una situación específica, entonces con los elementos de ListView (texto + mapa de bits) cargados de internet usando HttpClient , ¿cómo debería implementar mi AsyncTask?


En general, recomendaría la implementación estática (aunque ambas son aceptables).

El enfoque de Google requerirá menos código, pero su asynctask estará estrechamente relacionada con su actividad (lo que significa que no se puede reutilizar fácilmente). Pero a veces este enfoque es más legible.

Con el enfoque de CommonsGuy, requerirá más esfuerzo (y más código) para desacoplar actividad y asynctask, pero al final tendrá un código más modular y más reutilizable.


No hay una sola forma "correcta" de implementar AsyncTask . Pero aquí están mis dos centavos:

Esta clase está destinada a realizar trabajos "ligeros" en el contexto de una Actividad. Es por eso que tiene los métodos onPreExecute , onProgressUpdate , onPostExecute ejecutándose en el hilo de UI, para que puedan acceder a los campos y actualizar la GUI rápidamente. Cualquier tarea que requiera más tiempo para completarse y no está destinada a actualizar una actividad específica se debe mover a un Servicio.

Esos métodos se utilizan principalmente para actualizar la GUI. Como la GUI está relacionada con la instancia Activity (los campos probablemente se declaren como variables de miembros privados), es más conveniente implementar AsyncTask como una clase anidada no estática. También es la forma más natural en mi opinión.

En caso de que la tarea se reutilice en otras actividades, creo que debería permitirse tener su propia clase. Para ser sincero, no soy partidario de las clases estáticas estáticas, especialmente las vistas internas. Si se trata de una clase, significa que es conceptualmente diferente de la actividad. Y si es estático significa que no está relacionado con esta instancia concreta de la actividad. Pero como están anidados, esas clases están visualmente dentro de la clase principal, lo que hace que sea más difícil de leer, y pueden pasar desapercibidas en el explorador de paquetes del proyecto, ya que solo muestra los archivos. Y a pesar de estar menos acoplado que las clases internas, esto no es realmente tan útil: si la clase cambia, debe fusionar / comprometer el archivo principal completo al control de la versión. Si lo vuelves a usar, tendrás que acceder a él como Parent.Nested todas partes. Entonces, para no asociar otras actividades a la clase Parent , probablemente le gustaría refactorizar y extraer la clase anidada a su propio archivo.

Entonces, para mí, la pregunta sería Inner Class vs Top-Level Class.