2013-01-17 32 views
24

एंड्रॉइड उदाहरणों से "लॉगिन" एक गैर स्थैतिक आंतरिक वर्ग के रूप में AsyncTask लागू किया गया। हालांकि, Commonsguys के अनुसार, यह वर्ग स्थिर होना चाहिए और बाहर की गतिविधि see this के कमजोर संदर्भ का उपयोग करना चाहिए।AsyncTask को लागू करने का सही तरीका क्या है? स्थैतिक या गैर स्थैतिक घोंसला वर्ग?

तो AsyncTask को लागू करने का सही तरीका क्या है? स्थिर या गैर स्थैतिक?

गूगल

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); 
     } 
    } 
} 

यदि यह ListView आइटम (पाठ + प्लस बिटमैप) से लोड के साथ एक विशिष्ट स्थिति पर निर्भर करता है, तब से Commonsguy उदाहरण में कार्यान्वयन
https://github.com/commonsguy/cw-android/tree/master/Rotation/RotationAsync/

प्रवेश करें HttpClient का उपयोग कर इंटरनेट, मुझे अपने AsyncTask को कैसे कार्यान्वित करना चाहिए?

उत्तर

13

सामान्य रूप से मैं स्थिर कार्यान्वयन की सिफारिश करता हूं (हालांकि दोनों स्वीकार्य हैं)।

Google दृष्टिकोण को कम कोड की आवश्यकता होगी, लेकिन आपके एसिंक्टास्क को आपके एक्टिविटी के साथ कसकर जोड़ा जाएगा (जिसका अर्थ है कि आसानी से पुन: प्रयोज्य नहीं है)। लेकिन कभी-कभी यह दृष्टिकोण अधिक पठनीय है।

CommonsGuy दृष्टिकोण के साथ, गतिविधि और एसिन्टास्क को कम करने के लिए इसे अधिक प्रयास (और अधिक कोड) की आवश्यकता होगी, लेकिन अंत में आपके पास एक अधिक मॉड्यूलर, अधिक पुन: प्रयोज्य कोड होगा।

+1

मेरी समझ से, एक गैर स्थैतिक घोंसला वर्ग कक्षा के बाहर इसका संदर्भ रखता है। यदि उपयोगकर्ता अचानक वर्तमान गतिविधि को रद्द कर देता है (बैक बटन दबाएं) जबकि थ्रेड पूल में कई कार्य अभी भी कतारबद्ध हैं। तो क्या यह दृष्टिकोण (गैर स्थैतिक) संभावित रूप से स्मृति रिसाव बनाएगा क्योंकि जीसी उस गतिविधि के लिए स्मृति को पुनः प्राप्त करने में सक्षम नहीं होगा। क्या मुझे ये ठीक तरह से समझ आ रहा है? बीटीडब्ल्यू, बहुत बहुत धन्यवाद। – Chan

+1

@ चेन AsyncTasks आंतरिक और स्थैतिक घोंसले दोनों, रिसाव के लिए प्रवण हैं। यदि डिवाइस कॉन्फ़िगरेशन बदलता है और गतिविधि को फिर से बनाया जाता है, तो पुराने कार्य को रद्द करना भूलना आसान होता है और फिर यह बीजी में चल रहा है। –

+0

@ मिस्टरस्मिथ: धन्यवाद। तो क्या कोई और वैकल्पिक तरीका है? – Chan

2

जुड़ा हुआ लेख पहले से ही यह

इस पर जोर देना है, हालांकि, आप अपने AsyncTask की doInBackground() चाहते हैं कि पूरी तरह से गतिविधि से decoupled जा करने के लिए कहते हैं। यदि आप केवल मुख्य गतिविधि थ्रेड पर अपनी गतिविधि को स्पर्श करते हैं, तो आपका AsyncTask अभिविन्यास परिवर्तन बरकरार रह सकता है।

गतिविधि (जैसे अपने सदस्यों) AsyncTask से है, जो Static Nested Classes

स्टेटिक नेस्टेड वर्ग
वर्ग के तरीकों और चर के साथ के रूप में, एक स्थिर नेस्टेड साथ कतार में है मत छुओ वर्ग अपनी बाहरी कक्षा से जुड़ा हुआ है। और स्थैतिक वर्ग विधियों की तरह, एक स्थिर नेस्टेड क्लास सीधे संलग्न वर्ग या परिभाषित कक्षाओं में परिभाषित विधियों को संदर्भित नहीं कर सकता है - यह केवल ऑब्जेक्ट संदर्भ के माध्यम से उनका उपयोग कर सकता है।

हालांकि

, एंड्रॉयड, AsyncTask reference और Using AsyncTask अभी भी गैर स्थिर नेस्टेड वर्गों का उपयोग कर रहे हैं से उदाहरण हैं।

और यह Static nested class in Java, why? के अनुसार, मैं पहले स्थिर भीतरी वर्ग के साथ जाने के लिए और केवल गैर स्थिर संस्करण का सहारा है, अगर यह वास्तव में आवश्यक है जाएगा।

14

AsyncTask को लागू करने का कोई भी "सही" तरीका नहीं है। लेकिन यहां मेरे दो सेंट हैं:

यह कक्षा किसी गतिविधि के संदर्भ में "प्रकाश" कार्य करने का इरादा है।यही कारण है कि इसमें यूआई थ्रेड में onPreExecute, onProgressUpdate, onPostExecute विधियां हैं, ताकि वे फ़ील्ड तक पहुंच सकें और जल्दी से GUI अपडेट कर सकें। कोई भी कार्य जो पूरा करने में लंबा समय ले सकता है और यह किसी विशिष्ट गतिविधि को अपडेट करने के लिए नहीं है, उसे किसी सेवा में ले जाना चाहिए।

उन विधियों का उपयोग ज्यादातर जीयूआई को अद्यतन करने के लिए किया जाता है। चूंकि जीयूआई गतिविधि उदाहरण से संबंधित कुछ है (फ़ील्ड को संभावित रूप से निजी सदस्य चर के रूप में घोषित किया जाता है), AsyncTask को एक गैर स्थैतिक घोंसला वर्ग के रूप में लागू करना अधिक सुविधाजनक है। यह मेरी राय में सबसे स्वाभाविक तरीका भी है।

यदि कार्य अन्य गतिविधियों में पुन: उपयोग किया जा रहा है, तो मुझे लगता है कि इसे अपनी कक्षा रखने की अनुमति दी जानी चाहिए। ईमानदार होने के लिए, मैं स्थिर घोंसला वाले वर्गों का कोई प्रशंसक नहीं हूं, खासकर विचारों के अंदर। यदि यह एक वर्ग है तो इसका मतलब है कि यह गतिविधि से अवधारणात्मक रूप से अलग है। और यदि यह स्थैतिक है तो इसका मतलब है कि यह गतिविधि के इस ठोस उदाहरण से संबंधित नहीं है। लेकिन जैसा कि वे घोंसले में हैं, वे वर्ग अभिभावक वर्ग के अंदर दृश्यमान हैं जो इसे पढ़ने में कठिन बनाते हैं, और प्रोजेक्ट पैकेज एक्सप्लोरर में अनजान हो सकते हैं क्योंकि यह केवल फाइलें दिखाता है। और आंतरिक कक्षाओं से कम युग्मित होने के बावजूद, यह वास्तव में उपयोगी नहीं है: यदि वर्ग बदलता है, तो आपको संपूर्ण मूल फ़ाइल को संस्करण नियंत्रण में विलय/प्रतिबद्ध करना होगा। यदि आप इसे पुन: उपयोग करना चाहते हैं, तो आपको इसे हर जगह Parent.Nested तक पहुंचाना होगा। तो Parent कक्षा में अन्य गतिविधियों को जोड़ने के लिए, शायद आप इसे पुन: सक्रिय करना चाहते हैं और नेस्टेड क्लास को अपनी फ़ाइल में निकालना चाहते हैं।

तो मेरे लिए सवाल इनर क्लास बनाम टॉप-लेवल क्लास होगा।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^