什么是实施AsyncTask的正确方法? 静态或非静态嵌套类?

Android例子中的“Login”实现了AsyncTask作为非静态的内部类。 然而,根据Commonsguys,这个类应该是静态的,并且使用弱引用来看外部活动。

那么实现AsyncTask的正确方法是什么? 静态还是非静态?

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

从Googlelogin示例

 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[] { "foo@example.com:hello", "bar@example.com: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); } } } 

如果这取决于具体情况,那么使用HttpClient从Internet上加载ListView项目(文本+加位图),我应该如何实现我的AsyncTask?

Solutions Collecting From Web of "什么是实施AsyncTask的正确方法? 静态或非静态嵌套类?"

一般来说,我会build议静态实现(虽然都可以接受)。

Google的方法将需要更less的代码,但是你的asyncTask会和你的actitivy(这意味着不容易重用)密切相关。 但有时这种方法更具可读性。

使用CommonsGuy方法,将需要更多的努力(和更多的代码)来分离活动和异类,但是最终你会得到一个更模块化,更可重用的代码。

没有一个“正确”的方式来实现AsyncTask 。 但是这是我的两分钱:

本课程旨在在活动的上下文中执行“轻量级”工作。 这就是为什么它具有在UI线程中运行的onPreExecuteonProgressUpdateonPostExecute方法,以便他们可以快速访问字段和更新GUI。 任何可能需要更长时间才能完成的任务,并不意味着更新特定的活动,都应该转移到服务中。

这些方法主要用于更新GUI。 由于GUI是与Activity实例相关的东西(这些字段可能被声明为私有成员variables),所以将AsyncTask实现为非静态嵌套类会更方便。 这也是我认为最自然的方式。

如果这个任务要在其他活动中重用,我认为应该允许它有自己的类。 说实话,我不是静态嵌套类的粉丝,尤其是内部视图。 如果它是一个类,就意味着它在概念上与活动不同。 如果它是静态的,则意味着它与这个活动的具体实例无关。 但是,因为它们是嵌套的,所以这些类在父类中是可视化的,这使得难以阅读,并且可以在项目包资源pipe理器中不被注意,因为它只显示文件。 尽pipe耦合度比内部类更less,但这并不是很有用:如果类改变了,你必须将整个父文件合并/提交给版本控制。 如果你在哪里重用它,那么你将不得不作为Parent.Nested到处访问它。 所以为了不把其他活动连接到Parent类,你可能想要重构它并将嵌套类提取到它自己的文件中。

所以对于我来说,问题将是内部类与顶级类。

链接的文章已经说过了

但是,这确实强调,你希望你的AsyncTask的doInBackground()和Activity完全分离。 如果你只在主应用程序线程上触摸你的Activity,你的AsyncTask可以在方向改变中保持不变。

不要触摸AsyncTask的Activity(例如它的成员),它与静态嵌套类一致

静态嵌套类
与类方法和variables一样,静态嵌套类与其外部类相关联。 像静态类方法一样,静态嵌套类不能直接引用其封闭类中定义的实例variables或方法 – 只能通过对象引用来使用它们。

尽pipe从Android, AsyncTask引用和使用AsyncTask的例子仍然使用非静态嵌套类。

而根据这个Java的静态嵌套类,为什么? ,如果真的有必要的话,我会首先使用静态内部类,然后使用非静态的版本。