2012-03-27 9 views
5

क्या AsyncTask.doInBackground सिंक्रनाइज़ करना संभव है - या एक ही परिणाम को एक और तरीके से प्राप्त करना संभव है?क्या एंड्रॉइड AsyncTask doInBackground कार्य निष्पादन को क्रमबद्ध करने के लिए सिंक्रनाइज़ किया जा सकता है?

class SynchronizedTask extends AsyncTask { 

    @Override 
    protected synchronized Integer doInBackground(Object... params) { 
     // do something that needs to be completed 
     // before another doInBackground can be called 
    } 
} 

मेरे मामले में, किसी भी AsyncTask.execute() पिछले एक पूरा कर लिया है से पहले शुरू किया जा सकता है, लेकिन मैं के बाद ही पिछले कार्य समाप्त हो गया है doInBackground में कोड निष्पादित करने के लिए की जरूरत है।

EDIT: जैसा कि सही ढंग से इंगित किया गया है, सिंक्रनाइज़ेशन केवल उसी ऑब्जेक्ट उदाहरण पर काम करता है। दुर्भाग्यवश, AsyncTask बनाने और execute() को उसी ऑब्जेक्ट उदाहरण पर एक से अधिक बार कॉल करना संभव नहीं है, जैसा कि AsyncTaskdocumentation के "थ्रेडिंग नियम" खंड में निर्दिष्ट है।

समाधान को संदर्भित करने के लिए कस्टम Executor का उपयोग करना है, या यदि आप एपीआई 11 या ऊपर, AsyncTask.executeOnExecutor() का उपयोग करते हैं, जैसा कि नीचे दी गई टिप्पणियों में सुझाया गया है।

मैंने an answer को SerialExecutor के कार्यान्वयन को दिखाया है जिसका उपयोग कार्यों को कतारबद्ध करने के लिए किया जा सकता है जो अनुक्रमिक रूप से निष्पादित किए जाएंगे।

+1

यही कारण है कि सिंक्रनाइज़ साधन नहीं है

यहाँ कोड है!इसका मतलब है कि फ़ंक्शन (या ब्लॉक) को इस ऑब्जेक्ट पर किसी अन्य थ्रेड के साथ इंटरलेविंग किए बिना निष्पादित किया जाता है। – Bondax

+0

@ बॉन्डैक्स हाँ, मुझे पता है। लेकिन दस्तावेज के अनुसार, 'doInBackground' को विभिन्न पृष्ठभूमि धागे द्वारा बुलाया जा सकता है। चूंकि यूआई थ्रेड पिछले एक से पहले किसी भी समय 'नया सिंक्रनाइज़ टास्क() 'कॉल कर सकता है, इसलिए आपके पास एक ही समय में' doInBackground' निष्पादित करने वाले दो या दो से अधिक भिन्न इंटरलिविंग थ्रेड हो सकते हैं। –

+1

हां, लेकिन विभिन्न AsyncTask उदाहरणों पर! – Bondax

उत्तर

15

आदर्श रूप में मदद मिलेगी, मैं एक SERIAL_EXECUTOR साथ AsyncTask.executeOnExecutor() उपयोग करने में सक्षम होना चाहते हैं, लेकिन इस एपीआई स्तर 11 या इसके बाद के संस्करण के लिए ही उपलब्ध है:

new AsyncTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params); 

एंड्रॉयड एपीआई लक्षित करने के लिए स्तर 11 के नीचे, मैंने एक कस्टम क्लास को कार्यान्वित करना समाप्त कर दिया जो ExecutorService को थ्रेड पूल आकार के साथ encapsulates 1. पूर्ण कोड खुला है here

Executors.newFixedThreadPool(int nThreads) एक थ्रेड पूल बनाता है जो एक साझा असंबद्ध कतार को संचालित करने वाले निश्चित थ्रेड का पुन: उपयोग करता है। किसी भी समय, nThreads धागे सक्रिय प्रसंस्करण कार्यों में होंगे। मेरे मामले में, nThreads 1 है, जिसका अर्थ है कि कार्यों को कतारबद्ध किया जा सकता है, लेकिन किसी भी समय केवल एक ही कार्य निष्पादित किया जाएगा।

public abstract class SerialExecutor { 
    private final ExecutorService mExecutorService; 

    public SerialExecutor() { 
     mExecutorService = Executors.newFixedThreadPool(1); 
    } 

    public void queue(Context context, TaskParams params) { 
     mExecutorService.submit(new SerialTask(context, params)); 
    } 

    public void stop() { 
     mExecutorService.shutdown(); 
    } 

    public abstract void execute(TaskParams params); 

    public static abstract class TaskParams { } 

    private class SerialTask implements Runnable { 
     private final Context mContext; 
     private final TaskParams mParams; 

     public SerialTask(Context context, TaskParams params) { 
      mContext = context; 
      mParams = params; 
     } 

     public void run() { 
      execute(mParams); 
      Activity a = (Activity) mContext; 
      a.runOnUiThread(new OnPostExecute()); 
     } 
    } 

    /** 
    * Used to notify the UI thread 
    */ 
    private class OnPostExecute implements Runnable { 

     public void run() { 

     } 
    } 
} 

यह बढ़ाया और एक सीरियल कार्य प्रबंधक के रूप में इस्तेमाल किया जा सकता एक Activity में:

public class MyActivity extends Activity { 
    private MySerialExecutor mSerialExecutor; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     // ... 
     mSerialExecutor = new MySerialExecutor(); 
    } 

    @Override 
    protected void onDestroy() { 
     if (mSerialExecutor != null) { 
      mSerialExecutor.stop(); 
     } 
     super.onDestroy(); 
    } 

    public void onTrigger(int param) { 
     mSerialExecutor.queue(this, new MySerialExecutor.MyParams(param)); 
    } 

    private static class MySerialExecutor extends SerialExecutor { 

     public MySerialExecutor() { 
      super(); 
     } 

     @Override 
     public void execute(TaskParams params) { 
      MyParams myParams = (MyParams) params; 
      // do something... 
     } 

     public static class MyParams extends TaskParams { 
      // ... params definition 

      public MyParams(int param) { 
       // ... params init 
      } 
     } 
    } 
} 
+0

नए सिंक टास्क() में SERIAL_EXECUTOR क्या है। ExecuteOnExecutor (SERIAL_EXECUTOR, पैराम्स); param मेरा पैरामीटर है .... –

+0

एक इरादा सेवा एक वैध विकल्प हो सकता है?यह नौकरियों को असंकालिक रूप से चलाता है और एक फीफो नौकरी कतार लागू करता है। –

3

आप इसके बजाय IntentService का उपयोग करने के बारे में सोचना चाह सकते हैं। ऐसा लगता है कि यह आपकी प्रक्रिया के लिए बेहतर फिट हो सकता है क्योंकि यह कतार के लिए सुविधाओं में बनाया गया है।

+0

धन्यवाद, अच्छे विकल्प के लिए +1, लेकिन मुझे एक सीरियल कार्य निष्पादन की आवश्यकता है जो प्रत्येक पुन: सक्रिय गतिविधि द्वारा स्वतंत्र रूप से किया जाता है। यही कारण है कि मुझे सभी गतिविधियों के बीच साझा करने के लिए केंद्रीय सेवा के बजाय 'AsyncTask' के समान प्रति-गतिविधि पृष्ठभूमि कार्य धारावाहिक की आवश्यकता है। –

+0

मुझे लगता है कि आपको executeOnExecuter के समान परिणाम क्या मिलेगा जैसा कि आपने अभी इस प्रश्न में नोट किया है, AsyncTask से कक्षा में एक स्टेटिक सिंक्रोनिज्ड विधि को कॉल कर रहा है (यह क्लास को अन्य थ्रेड से लॉक कर देगा) जिसमें प्रक्रिया के लिए आपका काम शामिल है। हालांकि executeOnExecutor के साथ यह आपके धागे संसाधित होने के आदेश को बीमा नहीं करेगा। यदि आपको लगता है कि आप जिस तरीके से एपीआई 11 के निष्पादन के साथ थ्रेड कर रहे हैं, तो आप इस प्रक्रिया का उपयोग करते हैं, तो अगर आप अपने धागे को कतार नहीं लेना चाहते हैं तो इस प्रक्रिया का उपयोग करें। – shibbybird

+0

यह सुनिश्चित करने के लिए कि कार्यों का क्रम संरक्षित किया गया है, मैंने 'SerialExecutor' क्लास को कार्यान्वित किया है जो 'निष्पादक सेवा' का उपयोग करता है 'निष्पादक # newFixedTreadPool (1)' (इस प्रश्न का मेरा उत्तर देखें)। 'निष्पादक # newFixedThreadPool (int nThreads) 'के प्रलेखन से, यह विधि एक थ्रेड पूल बनाता है जो एक साझा असंबद्ध कतार को संचालित करने वाले निश्चित थ्रेड का पुन: उपयोग करता है। किसी भी समय, अधिकांश 'nThreads' धागे सक्रिय प्रसंस्करण कार्यों में होंगे। यदि सभी थ्रेड सक्रिय होने पर अतिरिक्त कार्य सबमिट किए जाते हैं, तो वे कतार में तब तक प्रतीक्षा करेंगे जब तक कि थ्रेड उपलब्ध न हो जाए। –

-2

AsyncTask का उपयोग पृष्ठभूमि थ्रेड चलाने के लिए किया जाता है ताकि आप वर्तमान प्रक्रिया में हस्तक्षेप न करें।

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { 
protected Long doInBackground(URL... urls) { 
    int count = urls.length; 
    long totalSize = 0; 
    for (int i = 0; i < count; i++) { 
     totalSize += Downloader.downloadFile(urls[i]); 
     publishProgress((int) ((i/(float) count) * 100)); 
    } 
    return totalSize; 
} 

protected void onProgressUpdate(Integer... progress) { 
    setProgressPercent(progress[0]); 
} 

protected void onPostExecute(Long result) { 
    showDialog("Downloaded " + result + " bytes"); 
} 

}

जहां अपने सभी doInBackground समारोह iscalled और लौट आए वस्तु के लिए पोस्ट पर अमल चले जाएँगे के पहले। कुछ प्रक्रिया के बाद आप जिस कोड को चलाने के लिए चाहते हैं उसे आप PostExecute फ़ंक्शन में डाल सकते हैं। इस निश्चित रूप से आप

0
public class RestAsyncTask1 extends AsyncTask<String, Void, String> { 

    private AsyncTaskCompleteListener callback; 
    private Context context; 
    private String method; 
    private static final AtomicInteger PROGRESS_NUM = new AtomicInteger(0); 
    private static ProgressDialog PROGRESS_DIALOG; 

    public RestAsyncTask1(Context context, AsyncTaskCompleteListener callback, String method) { 
     this.callback = callback; 
     this.context = context; 
     this.method = method; 
    } 

    public static String format(String url, String... params) { 
     String[] encoded = new String[params.length]; 

     for (int i = 0; i < params.length; i++) { 
      encoded[i] = Uri.encode(params[i]); 
     } 

     return String.format(url, (String[]) encoded); 
    } 

    @Override 
    protected void onPreExecute() { 
     int x = PROGRESS_NUM.getAndIncrement(); 

     if (x == 0) { 
      String title = "M_yug"; 
      PROGRESS_DIALOG = new ProgressDialog(context); 
      // PROGRESS_DIALOG.setTitle(title); 
      PROGRESS_DIALOG.setIndeterminate(true); 
      PROGRESS_DIALOG.setCancelable(false); 
      PROGRESS_DIALOG.setOnCancelListener(null); 
      PROGRESS_DIALOG.setMessage("Loading. Please wait..."); 
      PROGRESS_DIALOG.show(); 
     } 
    } 

    @Override 
    protected String doInBackground(String... params) { 
     String url = params[0]; 
     String response = null; 
     HttpURLConnection connection = null; 

     if (params.length > 1) { 
      if (method.equals(Method.GET)) { 
       url = format(url, (String[]) Arrays.copyOfRange(params, 1, params.length)); 
      } else if (params.length > 2) { 
       url = format(url, (String[]) Arrays.copyOfRange(params, 1, params.length - 1)); 
      } 

      try { 
       URL call = new URL(url); 
       connection = (HttpURLConnection) call.openConnection(); 
       connection.setRequestProperty("Content-Type", "application/json"); 
       //connection.setRequestProperty("M-Yug", Utilities.VERSION); 
       connection.setRequestMethod(method); 
       connection.setDoOutput(true); 

       if (method.equals("POST")) { 
        BufferedOutputStream outputStream = new BufferedOutputStream(connection.getOutputStream()); 
        outputStream.write(params[params.length - 1].getBytes()); 
        outputStream.flush(); 
       } 

       int status = connection.getResponseCode(); 

       if (status == HttpURLConnection.HTTP_OK) { 
        InputStream is = connection.getInputStream(); 
        response = readValue(is); 
       } else if (status == 400) { 
        InputStream is = connection.getErrorStream(); 
        BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
        StringBuilder builder = new StringBuilder(); 
        String line; 

        while ((line = reader.readLine()) != null) { 
         builder.append(line); 
        } 

        reader.close(); 
        Toast.makeText(context, "" + builder.toString(), Toast.LENGTH_SHORT).show(); 
       } 

       connection.disconnect(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       if (connection != null) { 
        connection.disconnect(); 
       } 
      } 
     } 

     return response; 
    } 

    @Override 
    protected void onPostExecute(String s) { 
     int x = PROGRESS_NUM.decrementAndGet(); 

     if (x == 0 && PROGRESS_DIALOG != null && PROGRESS_DIALOG.isShowing()) { 
      PROGRESS_DIALOG.dismiss(); 
     } 

     if (s!=null) { 
      String resopnse=s.toString(); 
      callback.onSuccess(resopnse); 
     } else { 
      Toast.makeText(context,"Server Not Responding",Toast.LENGTH_SHORT).show(); 
     } 
    } 

    private String readValue(InputStream is) { 
     BufferedReader br = null; 
     StringBuilder sb = new StringBuilder(); 
     String line; 

     try { 
      br = new BufferedReader(new InputStreamReader(is)); 

      while ((line = br.readLine()) != null) { 
       sb.append(line); 
      } 
     } catch (Exception e) { 
     } 

     return sb.toString(); 
    } 

    enum Method { 
     GET, POST 
    } 
} 
+1

AsyncTask कार्य निष्पादित करने के लिए यह कक्षा सभी गतिविधियों के लिए उपयोगी हो सकती है। –

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