2011-04-21 13 views
12

मैं पैकेज एक में एक गतिविधि (SignerClient), और पैकेज बी (MyService)एंड्रॉयड ResultReceiver भर में संकुल

गतिविधि के resultreceiver में एक सेवा है:

private ResultReceiver resultreceiver = new ResultReceiver(null) { 
      @Override 
      protected void onReceiveResult(int resultCode, Bundle resultData) { 
      ... 
      } 
     }; 

सेवा शुरू:

Intent intent = new Intent("com.example.STARTSERVICE"); 
intent.putExtra("resultreceiver", resultreceiver);    
startService(intent); 

प्राप्त करने वाला अंत:

ResultReceiver rr = (ResultReceiver) intent.getParcelableExtra("resultreceiver"); 

ऐसा करने पर क्लाइंट और सर्वर एक ही पैकेज में हैं ठीक काम करता है। लेकिन इस मामले में मुझे मिलता है:

FATAL EXCEPTION: IntentService[MyService] 
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.example.cryptoclient.SignerClient$1 
at android.os.Parcel.readParcelable(Parcel.java:1883) 
at android.os.Parcel.readValue(Parcel.java:1771) 
at android.os.Parcel.readMapInternal(Parcel.java:2008) 
at android.os.Bundle.unparcel(Bundle.java:208) 
at android.os.Bundle.getParcelable(Bundle.java:1100) 
at android.content.Intent.getParcelableExtra(Intent.java:3396) 
at org.axades.service.MyService.onHandleIntent(MyService.java:28) 
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:59) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:123) 
at android.os.HandlerThread.run(HandlerThread.java:60) 

मुझे क्या याद आ रही है? क्या मेरा विचार भी संभव है?

+0

चूंकि यह विषय काफी पुराना है: समर्थन लाइब्रेरी से यह वर्ग एंड्रॉइड लॉलीपॉप से ​​पैकेज 'android.os' में जोड़ा गया था, और इस प्रक्रिया में समस्या हल हो गई है। सही आयात करने के लिए सुनिश्चित करें ... (नीचे उत्तर देखें) –

उत्तर

14

हां, आपका विचार संभव है। ClassNotFoundException अपवाद फेंक दिया गया है क्योंकि आप अलग-अलग ClassLoader द्वारा एक अलग प्रक्रिया में बनाए गए वर्ग को अद्वितीय करने की कोशिश कर रहे हैं।

ResultReceiver वर्ग Parcelable इंटरफ़ेस जो अंतर-प्रक्रिया कॉल (आईपीसी) के लिए उपयुक्त है, फिर भी सेवा में अपनी वस्तु को पढ़ने के लिए आप एक ही classloader उपयोग करने की आवश्यकता है कि क्लाइंट अनुप्रयोग में ऑब्जेक्ट निर्माण के लिए इस्तेमाल किया गया था यानी (में लागू करता है वह काम)। सेवा पक्ष पर उस क्लासलोडर को प्राप्त करने के लिए, क्लाइंट पैकेज नाम और CONTEXT_INCLUDE_CODE पास करने वाली विधि createPackageContext पर कॉल करें। CONTEXT_IGNORE_SECURITY झंडे का संयोजन। यह ग्राहक संदर्भ ऑब्जेक्ट वापस करेगा जिससे सही क्लासलोडर ऑब्जेक्ट प्राप्त किया जा सकता है।

उदाहरण:

public int onStartCommand(Intent intent, int flags, int startId) { 
    try { 

// assuming SignerClient activity is located in the package "com.example.client.A" 
    Context context = createPackageContext("com.example.client.A", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); 
    ClassLoader cl = context.getClassLoader(); 

    Bundle bundle = intent.getExtras(); 
    bundle.setClassLoader(cl); 
    ResultReceiver rr = bundle.getParcelable("resultreceiver"); 

//... your interaction with ResultReceiver ... 
    rr.send(1, null); // will result in a onReceiveResult call in the client activity 

    } catch (NameNotFoundException e) { 
    Log.e("MyService", "SignerClient package context was not found", e); 
    throw new RuntimeException(e); 
    } 
    return START_STICKY; 
} 

मैं बस अपना कोड में इसका इस्तेमाल किया गया है - एक आकर्षण की तरह काम करता है।

अद्यतन
हालांकि मैं MessengerResultReceiver के बजाय प्रयोग करने पर विचार करने के लिए सुझाव देते हैं। यह Parcelable इंटरफ़ेस लागू करता है और इसे विस्तारित करने की आवश्यकता नहीं है इस प्रकार क्लासलोडर समस्या संभव नहीं है। और यह recommended in the official documentation भी है।

अद्यतन 2
मामले में आप अभी भी ResultReceiverRobert's answer in this thread पर एक नज़र डालें उपयोग करने के लिए पसंद करते हैं। यह हैकी संदर्भ मैनिप्लेशंस से क्लीनर और सरल दिखता है।

+0

मुझे लगता है कि आप यहां गलत हैं, http://developer.android.com/reference/android/os/Message.html#getData() के अनुसार ऐसा लगता है कि आपको अभी भी क्लास लोडर का उपयोग करने की आवश्यकता है। –

+0

@MiroKropacek वास्तव में नहीं। मैसेंजर के मामले में आपको केवल एक लोडर को एक प्रक्रिया से दूसरे में मैसेंजर के माध्यम से पारित करने के लिए क्लास लोडर सेट करना होगा (यानी यदि आप 'Message.object' फ़ील्ड में प्रोसेस ए को प्रोसेस बी में परिभाषित कक्षा का उदाहरण देते हैं) । मेसेंजर को क्लास लोडर को सेट करने की आवश्यकता नहीं है और सिस्टम क्लास लोडर द्वारा लोड किए गए प्रकारों के प्राइमेटिव्स और ऑब्जेक्ट्स को पास करने के लिए सुरक्षित रूप से उपयोग किया जा सकता है, जैसे स्ट्रिंग, पॉइंट इत्यादि – Idolon

+0

दस्तावेज़ मैसेंजर सेवा (http: // डेवलपर) पर IntentService की सलाह देते हैं। android.com/reference/android/app/IntentService.html), जो एक-ऑफ अनुरोधों के लिए समझ में आता है जहां आपको चालू कनेक्शन की आवश्यकता नहीं है। यह समझ में नहीं आता है कि वे कहते हैं कि वास्तव में एक ही ऐप में होने के विशेष मामले के बाहर परिणाम कैसे भेजना है। –

18

मैं संकुल में ResultReceiver का उपयोग करना चाहता था और अन्य पैकेज के संदर्भ को लोड करना चाहता था, बस मुझे सही नहीं लगता ... आखिरकार, प्राप्त करने वाले पैकेज को ResultReceiver के विशेष उप-वर्ग को जानने की आवश्यकता नहीं है, इसे सिर्फ send() पर कॉल करने में सक्षम होना चाहिए और आईपीसी बाइंडर जादू होने दें। विशेष उपclass उपलब्ध होने की आवश्यकता एक डिजाइन दोष की तरह लग रहा है।

public static ResultReceiver receiverForSending(ResultReceiver actualReceiver) { 
    Parcel parcel = Parcel.obtain(); 
    actualReceiver.writeToParcel(parcel,0); 
    parcel.setDataPosition(0); 
    ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel); 
    parcel.recycle(); 
    return receiverForSending; 
} 

इस कोड ResultReceiver ही एक उदाहरण है, जो फिर भी अभी भी अपने मूल actualReceiver के परिणाम भेजता में ResultReceiver के कुछ उपवर्ग के अपने उदाहरण धर्मान्तरित:

एक समाधान नहीं है।receiverForSending को Intent में अन्य पैकेज में अतिरिक्त भेजा जा सकता है और इसे ठीक से अनारक्षित किया जा सकता है।

+0

धन्यवाद! बहुत अच्छा कार्यान्वयन! दरअसल, कुछ पैकेज के संदर्भ को लोड करने के लिए यह बुरा विचार है जब हम इसका उपयोग कर सकते हैं। –

+1

मैं आईपीसी का उपयोग भी नहीं कर रहा हूं और मुझे अभी भी इस दृष्टिकोण का उपयोग करना पड़ा। अच्छा समाधान .... और बल्कि दुर्भाग्यपूर्ण। – user123321

+0

मेरे आईपीसी परिदृश्य में पूरी तरह से काम किया :) –

0

किसी कारण से, मुझे यह त्रुटि केवल android.support.v4.os.ResultReceiver के साथ मिली थी। आयात को android.os.ResultReceiver में बदलकर आईपीसी परिणाम एक बार में काम करते हैं। कोई कामकाज की जरूरत नहीं है!

+1

'android.os.ResultReceiver' एपीआई 3 में जोड़ा गया था: https://developer.android.com/reference/android/os/ResultReceiver.html – Idolon

+0

आप सही हैं, मेरा जवाब संपादित करें। –

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