2013-01-17 39 views
24

"Đăng nhập" từ các ví dụ Android được triển khai AsyncTask dưới dạng lớp bên trong không tĩnh. Tuy nhiên, theo Commonsguys, lớp này nên tĩnh và sử dụng tham chiếu yếu đến hoạt động bên ngoài see this.Cách chính xác để triển khai AsyncTask là gì? lớp lồng nhau tĩnh hoặc không tĩnh?

Vì vậy, cách chính xác để triển khai AsyncTask là gì? Tĩnh hay không tĩnh?

Commonsguy Thực hiện
https://github.com/commonsguy/cw-android/tree/master/Rotation/RotationAsync/

Đăng nhập ví dụ từ 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); 
     } 
    } 
} 

Nếu nó phụ thuộc vào một tình huống cụ thể, sau đó với ListView mục (text + plus Bitmap) tải từ internet sử dụng HttpClient, tôi nên triển khai AsyncTask như thế nào?

Trả lời

13

Nói chung, tôi khuyên bạn nên triển khai tĩnh (mặc dù cả hai đều có thể chấp nhận được).

Cách tiếp cận của Google sẽ yêu cầu ít mã hơn nhưng asynctask của bạn sẽ được kết hợp chặt chẽ với hoạt động của bạn (có nghĩa là không dễ dàng tái sử dụng). Nhưng đôi khi cách tiếp cận này dễ đọc hơn.

Với phương pháp CommonsGuy, nó sẽ đòi hỏi nhiều nỗ lực hơn (và nhiều mã hơn) để tách hoạt động và asynctask, nhưng cuối cùng bạn sẽ có một mã mô-đun hơn, có thể tái sử dụng hơn.

+1

Từ sự hiểu biết của tôi, một lớp lồng nhau không tĩnh giữ một tham chiếu đến nó bên ngoài lớp học. Nếu người dùng đột nhiên hủy hoạt động hiện tại (nhấn nút quay lại) trong khi có một số tác vụ vẫn được xếp hàng đợi trong các nhóm luồng. Sau đó, cách tiếp cận này (không tĩnh) có khả năng tạo rò rỉ bộ nhớ vì GC sẽ không thể lấy lại bộ nhớ cho hoạt động đó. Tôi có hiểu chính xác điều này không? Btw, cảm ơn rất nhiều. – Chan

+1

@Chan AsyncTask dễ bị rò rỉ, cả hai bên trong và tĩnh lồng nhau. Nếu thiết bị thay đổi cấu hình và hoạt động được tạo lại, thật dễ dàng để quên việc hủy tác vụ cũ và sau đó nó còn lại chạy trong bg. –

+0

@MisterSmith: Cảm ơn. Vậy có phương pháp thay thế nào khác không? – Chan

2

Các bài viết liên quan đã nói nó

này nhấn mạnh, mặc dù, rằng bạn muốn doInBackground() của AsyncTask của bạn được hoàn toàn tách rời khỏi hoạt động. Nếu bạn chỉ chạm vào Hoạt động của mình trên chuỗi ứng dụng chính, AsyncTask của bạn có thể tồn tại thay đổi định hướng nguyên vẹn.

Đừng chạm vào hoạt động (ví dụ như các thành viên của nó) từ AsyncTask, đó là phù hợp với Static Nested Classes

lớp Nested tĩnh
Như với các phương pháp lớp học và các biến, một tĩnh lồng nhau lớp được kết hợp với lớp ngoài của nó. Và giống như các phương thức lớp tĩnh, một lớp lồng nhau tĩnh không thể tham chiếu trực tiếp đến các biến mẫu hoặc các phương thức được định nghĩa trong lớp kèm theo của nó - nó có thể sử dụng chúng chỉ thông qua một tham chiếu đối tượng.

Mặc dù, các ví dụ từ Android, AsyncTask referenceUsing AsyncTask vẫn đang sử dụng các lớp lồng nhau không tĩnh.

Và theo điều này Static nested class in Java, why?, trước tiên tôi sẽ đi với lớp học và khu nghỉ dưỡng tĩnh tĩnh chỉ nếu không thực sự cần thiết.

14

Không có cách thực hiện "chính xác" duy nhất AsyncTask. Nhưng đây là hai xu của tôi:

Lớp này nhằm mục đích thực hiện công việc "nhẹ" trong ngữ cảnh của Hoạt động.Đó là lý do tại sao nó có các phương thức onPreExecute, onProgressUpdate, onPostExecute chạy trong chuỗi giao diện người dùng, để chúng có thể truy cập các trường và cập nhật GUI nhanh chóng. Bất kỳ tác vụ nào có thể mất nhiều thời gian hơn để hoàn thành và không có nghĩa là cập nhật một hoạt động cụ thể sẽ được chuyển sang Dịch vụ.

Những phương pháp này chủ yếu được sử dụng để cập nhật GUI. Vì GUI là một cái gì đó liên quan đến cá thể Hoạt động (các trường có thể được khai báo là các biến thành viên riêng), nên thuận tiện hơn khi triển khai thực hiện lớp AsyncTask là một lớp lồng nhau không tĩnh. Đó cũng là cách tự nhiên nhất trong quan điểm của tôi.

Trong trường hợp nhiệm vụ sẽ được sử dụng lại trong các hoạt động khác, tôi nghĩ rằng nó nên được phép có lớp riêng của mình. Thành thật mà nói, tôi không có fan hâm mộ của các lớp lồng nhau tĩnh, đặc biệt là các khung nhìn bên trong. Nếu nó là một lớp, điều đó có nghĩa là nó khác biệt về mặt khái niệm so với hoạt động. Và nếu nó là tĩnh nó có nghĩa là nó không liên quan đến trường hợp cụ thể của hoạt động này. Nhưng khi chúng được lồng vào nhau, các lớp đó trực quan bên trong lớp cha làm cho nó khó đọc hơn, và có thể không được chú ý trong trình thám hiểm gói dự án vì nó chỉ hiển thị các tệp. Và mặc dù ít được kết hợp hơn so với các lớp bên trong, điều này không thực sự hữu ích: nếu lớp thay đổi, bạn phải hợp nhất/cam kết toàn bộ tệp gốc vào điều khiển phiên bản. Nếu bạn sử dụng lại nó ở đâu, thì bạn sẽ phải truy cập nó như Parent.Nested ở mọi nơi. Vì vậy, để không kết hợp các hoạt động khác với lớp Parent, bạn có thể muốn cấu trúc lại nó và giải nén lớp lồng vào tệp riêng của nó.

Vì vậy, đối với tôi câu hỏi sẽ là Lớp bên trong so với Lớp cấp cao nhất.

Các vấn đề liên quan