Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the correct way to implement AsyncTask? static or non static nested class?

The "Login" from Android examples implemented AsyncTask as a non-static inner class. However, according to Commonsguys, this class should be static and use weak-reference to the outside activity see this.

So what is the correct way to implement AsyncTask? Static or non-static?

Commonsguy Implementation
https://github.com/commonsguy/cw-android/tree/master/Rotation/RotationAsync/

Log in example from 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);         }     } } 

If it depends on a specific situation, then with ListView items (text + plus Bitmap) loaded from the internet using HttpClient, how should I implement my AsyncTask?

like image 740
Chan Avatar asked Jan 17 '13 08:01

Chan


People also ask

How is async task implemented?

An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params , Progress and Result , and 4 steps, called onPreExecute , doInBackground , onProgressUpdate and onPostExecute .

Why do we need static nested class?

Use a non-static nested class (or inner class) if you require access to an enclosing instance's non-public fields and methods. Use a static nested class if you don't require this access.

Can a nested class be non-static?

Terminology: Nested classes are divided into two categories: non-static and static. Non-static nested classes are called inner classes. Nested classes that are declared static are called static nested classes. A nested class is a member of its enclosing class.

What is the use of AsyncTask class?

Android AsyncTask is an abstract class provided by Android which gives us the liberty to perform heavy tasks in the background and keep the UI thread light thus making the application more responsive. Android application runs on a single thread when launched.


1 Answers

There's no single "correct" way of implementing AsyncTask. But here are my two cents:

This class is intended to perform "light" work in the context of an Activity. That's why it has the methods onPreExecute, onProgressUpdate, onPostExecute running in the UI thread, so that they can access fields and update GUI quickly. Any task that might take a longer time to complete and it is not meant to update a specific activity should be moved to a Service.

Those methods are mostly used to update the GUI. As the GUI is something related to the Activity instance (the fields are likely declared as private member variables), it is more convenient to implement the AsyncTask as a non-static nested class. It is also the most natural way in my opinion.

In case the task is going to be reused in other activities, I think it should be allowed to have its own class. To be honest, I'm no fan of static nested classes, especially inside views. If it is a class it means it is conceptually different than the activity. And if it is static it means it is not related to this concrete instance of the activity. But as they are nested, those classes are visually inside the parent class making it harder to read, and can go unnoticed in the project package explorer as it only shows files. And despite being less coupled than inner classes, this is not really that useful: if the class changes, you have to merge/commit the whole parent file to the version control. If you where to reuse it, then you'll have to access it as Parent.Nested everywhere. So in order to not to couple other activities to the Parent class, you probably would like to refactor it and extract the nested class to its own file.

So for me the question would be Inner Class vs Top-Level Class.

like image 128
Mister Smith Avatar answered Oct 03 '22 10:10

Mister Smith