2013-10-27 9 views
17

से वापसी मान को संभालने के लिए मैं निम्नलिखित हस्ताक्षर के साथ AsyncTask वर्ग का उपयोग कर रहा:कैसे AsyncTask

public class ApiAccess extends AsyncTask<List<NameValuePair>, Integer, String> { 
    ... 
private String POST(List<NameValuePair>[] nameValuePairs){ 
    ... 
    return response; 
} 
} 

protected String doInBackground(List<NameValuePair>... nameValuePairs) { 
    return POST(params); 
} 

मैं इसे माध्यम से अन्य वर्ग से कॉल करने के लिए कोशिश कर रहा हूँ:

ApiAccess apiObj = new ApiAccess (0, "/User"); 
// String signupResponse = apiObj.execute(nameValuePairs); 
String serverResponse = apiObj.execute(nameValuePairs); //ERROR 

लेकिन यहाँ मैं इस मिल त्रुटि:

Type mismatch: cannot convert from AsyncTask<List<NameValuePair>,Integer,String> to String 

क्यों है कि जब मैं कक्षा में तीसरे पैरामीटर के रूप में निर्दिष्ट किया है String विस्तारित लाइन?

+0

विधि निष्पादन 'AsyncTask' परिणाम न लौटाता है। यदि आप asyncTask से कुछ परिणाम वापस करना चाहते हैं या कुछ डेटा प्रदान करना चाहते हैं, तो [प्रोटोकॉल] (http://stackoverflow.com/a/26820666/2835520) – IgniteCoders

उत्तर

29

आप असीनकटास्क की वापसी() विधि को वापस AsyncTask पर कॉल करके परिणाम प्राप्त कर सकते हैं, लेकिन यह परिणाम को प्राप्त करने के लिए प्रतीक्षा करता है क्योंकि यह एक सिंक्रोनस कार्य में एक सिंक्रोनस कार्य से बदल जाएगा।

String serverResponse = apiObj.execute(nameValuePairs).get(); 

जब से तुम एक अलग वर्ग में अपने AsyncTask है, तो आप एक इंटरफेस वर्ग बना सकते हैं और AsyncTask में यह घोषणा करते हैं और वर्ग आप से परिणाम का उपयोग करना चाहते हैं में प्रतिनिधि के रूप में अपने नए इंटरफ़ेस वर्ग को लागू कर सकते हैं। एक अच्छी गाइड यहां है: How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?

मैं आपके संदर्भ में उपरोक्त लिंक को लागू करने का प्रयास करूंगा।

(IApiAccessResponse)

public interface IApiAccessResponse { 
    void postResult(String asyncresult); 
} 

(ApiAccess)

public class ApiAccess extends AsyncTask<List<NameValuePair>, Integer, String> { 
... 
    public IApiAccessResponse delegate=null; 
    protected String doInBackground(List<NameValuePair>... nameValuePairs) { 
     //do all your background manipulation and return a String response 
     return response 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     if(delegate!=null) 
     { 
      delegate.postResult(result); 
     } 
     else 
     { 
      Log.e("ApiAccess", "You have not assigned IApiAccessResponse delegate"); 
     } 
    } 
} 

(आपका मुख्य वर्ग है, जो IApiAccessResponse लागू करता है)

ApiAccess apiObj = new ApiAccess (0, "/User"); 
//Assign the AsyncTask's delegate to your class's context (this links your asynctask and this class together) 
apiObj.delegate = this; 
apiObj.execute(nameValuePairs); //ERROR 

//this method has to be implement so that the results can be called to this class 
void postResult(String asyncresult){ 
    //This method will get call as soon as your AsyncTask is complete. asyncresult will be your result. 
} 
+1

यदि कोई सिंक्रोनस निष्पादन चाहता है, तो AsyncTask का उपयोग नहीं किया जाना चाहिए, यह एक बुरा विचार है। –

+3

मुझे पता है, लेकिन मैं उसे अंतर्दृष्टि देने की कोशिश कर रहा था कि उसे त्रुटि क्यों मिली, क्योंकि वह – frogmanx

0

कृपया AsyncTask पढ़ें। आप onPostExecute विधि पर परिणाम प्राप्त कर सकते हैं। आप कुछ ऐसा नहीं कर सकते:

String serverResponse = apiObj.execute(nameValuePairs); 

क्योंकि यह async है।

+0

का उपयोग करें, लेकिन मैं इसे बाहर से कॉल कर रहा हूं कि मैं वहां परिणाम कैसे प्राप्त कर सकता हूं? – Maven

+0

आप एक कॉलबैक लिख सकते हैं जिसे asyncTask (onPostExecute विधि) कहा जाता है और बाहर लागू किया जाता है। – Devrim

0

समस्या यह है कि जब आप निष्पादित, फोन AsyncTask ऑब्जेक्ट वापस कर दिया गया है, लेकिन परिणाम अभी तक नहीं है। परिणाम पृष्ठभूमि में गणना की जाती है। परिणाम का प्रकार अंततः एक स्ट्रिंग होगा (जैसा कि आपने निर्दिष्ट किया है), और onPostExecute() पर पारित किया जाएगा।

public class ApiAccess extends AsyncTask<List<NameValuePair>, Integer, String> { 
    ... 
    private String POST(List<NameValuePair>[] nameValuePairs){ 
    ... 
     return response; 
    } 

    protected void onPreExecute(){ 
     // this is run on the main (UI) thread, before doInBackground starts 
    } 

    protected void onPostExecute (String result){ 
     // this is run on the main (UI) thread, after doInBackground returns 
    } 

    protected String doInBackground(List<NameValuePair>... nameValuePairs) { 
     // run in another, background thread 
     return POST(params); 
    } 
} 

ध्यान रखें कि आपके उदाहरण में आप doInBackground() में परिणाम वापस नहीं कर रहे हैं, जो आप करना चाहिए:

आप इस प्रकार AsyncTask उपयोग करना चाहिए।

3

मैं एक हैंडलर कॉलबैक लागू करने का सुझाव दूंगा। आप टुकड़े (या गतिविधि के) हैंडलर को AsyncTask में पास करेंगे, जो AsyncTask समाप्त होने पर कॉल करेगा। AsyncTask भी एक मनमानी वस्तु वापस पास कर सकते हैं।

यहाँ एक उदाहरण AsyncTask, जो मैं अपने आप ही फाइल में है (नहीं subclassed):

public class MyTask extends AsyncTask<Void, String, String> { 

    private static final String TAG = "MyTask"; 
    private Handler mCallersHandler; 
    private Candy mObject1; 
    private Popsicle mObject2; 

    // Return codes 
    public static final int MSG_FINISHED = 1001; 

    public SaveVideoTask(Handler handler, Candy candyCane, Popsicle grapePop) { 
     this.mCallersHandler = handler; 
     this.mObject1  = candyCane; 
     this.mObject2  = grapePop; 
    } 

    @Override 
    protected String doInBackground(Void... params) { 

     // Do all of the processing that you want to do... 
     // You already have the private fields because of the constructor 
     // so you can use mObject1 and mObject2 
     Dessert objectToReturn = mObject1 + mObject2; 

     // Tell the handler (usually from the calling thread) that we are finished, 
     // returning an object with the message 
     mCallersHandler.sendMessage(Message.obtain(mCallersHandler, MSG_FINISHED, objectToReturn)); 

     return (null); 
    } 
} 

इस उदाहरण में कल्पना है कि आपके AsyncTask कैंडी और एक Popsicle का एक टुकड़ा की जरूरत है।फिर यह आपके टुकड़े में मिठाई वापस कर देगा।

आप का निर्माण और के साथ अपने टुकड़ा से एक पंक्ति में AsyncTask चला सकते हैं:

(new MyTask(mFragmentHandler, candyCane, grapePop)).execute(); 

लेकिन निश्चित रूप से, आप पहली बार टुकड़ा के हैंडलर (myFragmentHandler) स्थापित करने के लिए की आवश्यकता होगी। ऐसा करने के लिए, अपने टुकड़ा (या गतिविधि) की तरह दिखना चाहिए (नोट "Handler.Callback लागू करता है"):

public class MyFragment extends Fragment implements Handler.Callback { 

    private Handler mFragmentHandler; 
    private Candy candyCane; 
    private Popsicle grapePop; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     // Standard creation code 
     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 

     // Create a handler for this fragment 
     mFragmentHandler = new Handler(this); 

     // Other stuff... 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, 
      Bundle savedInstanceState) { 

     // Inflate the layout 
     View v = inflater.inflate(R.layout.my_fragment_layout, parent, false); 

     // The candyCane and grapePop don't need to be set up here, but 
     // they MUST be set up before the button is pressed. 
     // Here would be a good place to at least initialize them... 

     // Perhaps you have a button in "my_fragment_layout" that triggers the AsyncTask... 
     Button mButton = (Button) v.findViewById(R.id.mButton); 
     mButton.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       (new MyTask(mFragmentHandler, candyCane, grapePop)).execute(); 
      } 
     }); 
     return v; 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public boolean handleMessage(Message msg) { 

     switch (msg.what) { 

     case MyTask.MSG_FINISHED: 

      // Let's see what we are having for dessert 
      Dessert myDessert = (Dessert) msg.obj; 
      break; 

     } 
     return false; 
    } 

} 

आप कोड के इन टुकड़ों का उपयोग करते हैं, एक बटन दबाने की AsyncTask ट्रिगर किया जाएगा। AsyncTask संसाधित होने पर कॉलिंग खंड निष्पादित करना जारी रहेगा। फिर, जब AsyncTask समाप्त हो जाता है, तो यह खंड को एक संदेश भेजेगा कि यह समाप्त हो गया है, और संदेश के साथ ऑब्जेक्ट पास करें। इस बिंदु पर, टुकड़ा संदेश देखेंगे, और जो भी आप चाहते हैं।

नोट: टाइपो हो सकता है। यह एक बहुत बड़े और जटिल कोड से काटा जाता है।

+0

के बारे में पूछ रहा था, मुझे लगता है कि हमें AsyncTask – Sayem

+0

के अंदर हैंडलर का एक सप्ताह का संदर्भ रखना चाहिए। मुझे स्पष्ट नहीं है आपका क्या मतलब है। मुझे लगता है कि कोड स्वरूपण खराब था, इसलिए मैंने इसे ठीक करने की कोशिश की। शायद यह शुरुआत में स्पष्ट नहीं था। इस समाधान के लिए –

+0

धन्यवाद Bremen_matt। मैं इस समाधान का उपयोग कर दो Async कार्यों के बीच समन्वयन समस्याओं को ठीक करने में सक्षम था। –