2015-04-15 2 views
18

मुझे डिवाइस पर स्थापित ऐप्स की एक सूची मिल रही है। यह एक महंगा ऑपरेशन है, इसलिए मैं इसके लिए आरएक्स का उपयोग कर रहा हूं:RxJava (एंड्रॉइड) के अंदर त्रुटि को सही ढंग से कैसे संभालें?

Observable<List> observable = Observable.create(subscriber -> { 
     List result = getUserApps(); 

     subscriber.onNext(result); 
     subscriber.onError(new Throwable()); 
     subscriber.onCompleted(); 
    }); 

    observable 
      .map(s -> { 
       ArrayList<String> list = new ArrayList<>(); 
       ArrayList<Application> applist = new ArrayList<>(); 
       for (Application p : (ArrayList<Application>) s) { 
        list.add(p.getAppName()); 
        applist.add(p); 
       } 
       return applist; 
      }) 
      .subscribeOn(Schedulers.newThread()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .doOnError(throwable -> L.e(TAG, "Throwable " + throwable.getMessage())) 
      .subscribe(s -> createListView(s, view)); 

हालांकि, मेरी समस्या त्रुटियों को संभालने के साथ है। आम तौर पर, उपयोगकर्ता इस स्क्रीन को लॉन्च करता है, ऐप्स को लोड करने की प्रतीक्षा करता है, सबसे अच्छा क्या चुनता है और अगले पृष्ठ पर जाता है। हालांकि, जब उपयोगकर्ता जल्दी से यूआई - ऐप क्रैश को नलपॉइंटर के साथ बदल देता है।

ठीक है, इसलिए मैंने इसे onError लागू किया। हालांकि यह अभी भी काम नहीं करता है, और इसके बाद के संस्करण USECASE साथ यह मुझे फेंकता इस:

04-15 18:12:42.530 22388-22388/pl.digitalvirgo.safemob E/AndroidRuntime﹕ FATAL EXCEPTION: main 
     java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling. 
       at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:52) 
       at android.os.Handler.handleCallback(Handler.java:730) 
       at android.os.Handler.dispatchMessage(Handler.java:92) 
       at android.os.Looper.loop(Looper.java:176) 
       at android.app.ActivityThread.main(ActivityThread.java:5419) 
       at java.lang.reflect.Method.invokeNative(Native Method) 
       at java.lang.reflect.Method.invoke(Method.java:525) 
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046) 
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862) 
       at dalvik.system.NativeStart.main(Native Method) 
     Caused by: rx.exceptions.OnErrorNotImplementedException 
       at rx.Observable$31.onError(Observable.java:7134) 
       at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:154) 
       at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111) 
       at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70) 
       at rx.internal.operators.NotificationLite.accept(NotificationLite.java:147) 
       at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:177) 
       at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.access$000(OperatorObserveOn.java:65) 
       at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:153) 
       at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47) 
                at android.os.Handler.handleCallback(Handler.java:730) 
                at android.os.Handler.dispatchMessage(Handler.java:92) 
                at android.os.Looper.loop(Looper.java:176) 
                at android.app.ActivityThread.main(ActivityThread.java:5419) 
                at java.lang.reflect.Method.invokeNative(Native Method) 
                at java.lang.reflect.Method.invoke(Method.java:525) 
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046) 
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862) 
                at dalvik.system.NativeStart.main(Native Method) 
     Caused by: java.lang.Throwable 
       at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment.lambda$getAppList$25(ApplicationsFragment.java:267) 
       at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment.access$lambda$2(ApplicationsFragment.java) 
       at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment$$Lambda$3.call(Unknown Source) 
       at rx.Observable$1.call(Observable.java:145) 
       at rx.Observable$1.call(Observable.java:137) 
       at rx.Observable.unsafeSubscribe(Observable.java:7304) 
       at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62) 
       at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47) 
       at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390) 
       at java.util.concurrent.FutureTask.run(FutureTask.java:234) 
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:153) 
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:267) 
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 
       at java.lang.Thread.run(Thread.java:841) 

मैं कैसे ठीक से इस समस्या को संभाल चाहिए?

+0

साथ

.doOnError(throwable -> L.e(TAG, "Throwable " + throwable.getMessage())) .subscribe(s -> createListView(s, view)) 

की जगह? – User9527

+0

'एप्लिकेशन' एक कस्टम मॉडल है? – Lobato

उत्तर

12

मेरे ले रहा है: आप शायद

.subscribe(s -> createListView(s, view)); 

में Action1 उपयोग कर रहे हैं आप सब्सक्राइबर या पर्यवेक्षक जो सार विधि onError है के साथ बदलने की जरूरत होगी। इस विधि को subscriber.onError(new Throwable());

EDIT: से यह कहा जाएगा कि मैं इसे कैसे करूंगा। नज़दीकी रूप से मुझे लगता है कि आपके कोड में मुख्य समस्या प्रारंभिक भाग है जहां आप कोई त्रुटि नहीं होने पर भी subscriber.onError पर कॉल करते हैं। आपको शायद map की आवश्यकता नहीं है क्योंकि आप तकनीकी रूप से डेटा पास कर रहे हैं-बिना हेरफेर के। लेकिन अगर इसे बाद में जरूरी है तो मैंने इसे छोड़ दिया।

 Observable.create(new Observable.OnSubscribe<Application>() { 
     @Override 
     public void call(Subscriber<? super Application> subscriber) { 
      List result = getUserApps(); 
      if (result != null){ 
       for (Application app : result){ 
        subscriber.onNext(app); 
       } 
       subscriber.onComplete(); 
      }else{ 
       subscriber.onError(new IOException("no permission/no internet/etc")); 
       //or if this is a try catch event you can pass the exception 
      }  
     } 
    }) 
    .subscribeOn(Schedulers.io())//the thread *observer* runs in 
    .observeOn(AndroidSchedulers.mainThread())//the thread *subscriber* runs in 
    .map(new Func1<Application, String>() { 

     // Mapping methods are where data are manipulated. 
     // You can simply skip this and 
     //do the same thing in Subscriber implementation 
     @Override 
     public String call(Application application) { 
      return application.getName(); 
     } 
    }).subscribe(new Subscriber<String>() { 
     @Override 
     public void onCompleted() { 
      Toast.makeText(context, "completed", Toast.LENGTH_SHORT).show(); 
      //because subscriber runs in main UI thread it's ok to do UI stuff 
      //raise Toast, play sound, etc 
     } 

     @Override 
     public void onError(Throwable e) { 
      Log.e("getAppsError", e.getMessage()); 
      //raise Toast, play sound, etc 
     } 

     @Override 
     public void onNext(String s) { 
      listAdapter.add(s); 
     } 
    }); 
+1

क्या आप किसी प्रकार का उदाहरण पोस्ट कर सकते हैं? मैं प्रतिक्रियाशील प्रोग्रामिंग में नया हूं, इसलिए मेरे अधिकांश कार्यान्वयन हिट और मिस की तरह हैं;) –

+0

मैंने एक उदाहरण शामिल करने के लिए अपना जवाब संपादित किया। – inmyth

+0

क्या यह लैम्ब्डा अभिव्यक्तियों के साथ करने योग्य है? –

4

यहाँ नौसिखिया प्रतिक्रिया है (क्योंकि मैं javarx में नया हूँ और अंत में इस समस्या को हल):,

Observable.create(new Observable.OnSubscribe<RegionItem>() { 
       @Override 
       public void call(Subscriber<? super RegionItem> subscriber) { 
        subscriber.onError(new Exception("TADA !")); 
       } 
      }) 
      .doOnNext(actionNext) 
      .doOnError(actionError) 
      .doOnCompleted(actionCompleted) 
      .subscribe(); 

यह पिछले कार्यान्वयन में जब मैं सदस्यता:

यहाँ अपने कार्यान्वयन है मैं त्रुटि प्रवाह ट्रिगर करता हूं ... और मुझे एक एप्लिकेशन क्रैश मिलता है।

समस्या यह है कि आपको सब्सक्राइब() कॉल से त्रुटि का प्रबंधन करना है। "DoOnError (...)" सिर्फ एक प्रकार का सहायक है जो त्रुटि को क्लोन करता है और आपको त्रुटि के बाद कुछ क्रिया करने के लिए एक नया स्थान देता है। लेकिन यह त्रुटि को संभाल नहीं करता है।

तो तुम उस के साथ अपने कोड बदलने के लिए:

Observable.create(new Observable.OnSubscribe<RegionItem>() { 
       @Override 
       public void call(Subscriber<? super RegionItem> subscriber) { 
        subscriber.onError(new Exception("TADA !")); 
       } 
      }) 
      .subscribe(actionNext, actionError, actionCompleted); 

वास्तविक विवरण के बारे में सुनिश्चित नहीं हैं, लेकिन यह है कि कैसे मैं इसे ठीक कर। उम्मीद है कि यह मदद करेगा।

6

.doOnError() एक ऑपरेटर है, और Subscriber का ऐसा हिस्सा नहीं है।

इसलिए, .doOnError() होने पर onError() लागू नहीं किया गया है।

टिप्पणियों में से एक में सवाल के बारे में, निश्चित रूप से लैम्बडा का उपयोग करना संभव है।

इस मामले में बस समस्या ठीक कर लेने

.subscribe(s -> createListView(s, view), 
    throwable -> L.e(TAG, "Throwable " + throwable.getMessage())) 
संबंधित मुद्दे