RxJava 无法在未调用 Looper.prepare() 的线程内创建处理程序

Posted

技术标签:

【中文标题】RxJava 无法在未调用 Looper.prepare() 的线程内创建处理程序【英文标题】:RxJava Can't create handler inside thread that has not called Looper.prepare() 【发布时间】:2015-11-07 03:43:50 【问题描述】:

好的,所以我在我的 android 应用程序中使用的 RxJava Observable 有点麻烦。这非常令人沮丧,因为这已经工作了一段时间,现在才抛出上面的错误。我知道这意味着我正在从另一个线程执行 UI 操作,但我看不到发生了什么。所以这是可观察的:

 ConnectionsList.getInstance(this).getConnectionsFromParse(mCurrentUser)
            .delay(3, TimeUnit.SECONDS)
            .flatMap(s -> mainData.getDataFromNetwork(this, mCurrentUser, mSimpleFacebook))
            .flatMap(s -> mainData.getPictureFromUrl(s))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<Bitmap>() 
                @Override
                public void onCompleted() 
                    if (mCurrentUser.get(Constants.NAME) != null) 
                        mNavNameField.setText((String) mCurrentUser.get(Constants.NAME));
                    
                    mSearchFragment.setupActivity();
                

                @Override
                public void onError(Throwable e) 
                    e.printStackTrace();
                    mSearchFragment.setEmptyView();
                

                @Override
                public void onNext(Bitmap bitmap) 
                    mNavProfImageField.setImageBitmap(bitmap);
                    mainData.saveImageToParse(bitmap); //save the image to Parse backend
                
            );

经过一些调试,我发现这个平面图是错误发生的地方:

.flatMap(s -> mainData.getDataFromNetwork(this, mCurrentUser, mSimpleFacebook))

在其中,我在抛出错误的地方添加了一条注释:

 return Observable.create(subscriber -> 
            //set the username field if ParseUser is not null
            if(currentUser != null) 
                username = (String) currentUser.get(Constants.NAME);
            

            //if prof pic is null then request from facebook. Should only be on the first login
            if (currentUser != null && currentUser.getParseFile(Constants.PROFILE_IMAGE) == null) 
                if (AccessToken.getCurrentAccessToken() != null)  //check if session opened properly
                    //get simple facebook and add the user properties we are looking to retrieve
                    Profile.Properties properties = new Profile.Properties.Builder()
                            .add(Profile.Properties.FIRST_NAME)
                            .add(Profile.Properties.GENDER)
                            .add(Profile.Properties.BIRTHDAY)
                            .add(Profile.Properties.ID)
                            .add(Profile.Properties.EMAIL)
                            .build();

                    //The following line is where the debugger stops 
                    //and the error gets thrown
                    simpleFacebook.getProfile(properties, new OnProfileListener() 
                        @Override
                        public void onComplete(Profile response) 
                            String id = response.getId();
                            String name = response.getFirstName();
                            String gender = response.getGender();
                            String birthday = response.getBirthday();
                            String email = response.getEmail();
                            String age = getAge(birthday);

                            currentUser.put(Constants.NAME, name);
                            currentUser.put(Constants.AGE, age);
                            currentUser.put(Constants.GENDER, gender);
                            currentUser.put(Constants.EMAIL, email);
                            currentUser.saveInBackground();

                            if (id != null)  //display the profile image from facebook
                                subscriber.onNext("https://graph.facebook.com/" + id + "/picture?type=large");
                            
                        

这是怎么回事?它按原样工作正常,现在它说我在一些帮助线程上。就我而言,到目前为止,我一直在 UI 线程上。如果有人可以帮助我,那就太好了,否则我可能不得不暂时放弃 RxJava,因为它不适合我。提前致谢!

【问题讨论】:

我怀疑问题出在:.subscribeOn(Schedulers.io())。您应该订阅主线程调度程序,因为您的网络操作似乎是异步的。 你能发布堆栈跟踪吗?是不是因为getProfile需要在主线程中调用? 我怀疑 getprofile 需要在主线程上调用,但它让我困惑为什么它之前工作。我应该订阅 (AndroidSchedulers.MainThread) 吗? @RichLuick:AsyncTask 中的 Handler 初始化是静态完成的,因此如果您之前运行了另一个 AsyncTask 实例,那么它已经被初始化了。同样从 Lollipop MR 1 (5.1) 开始,它会延迟初始化 Handler,因此根本不会遇到此问题。是的,在这种情况下你应该使用subscribeOn(AndroidSchedulers.mainThread()) 好的,非常感谢!我今天下班后试一试 【参考方案1】:

看起来simpleFacebook.getProfile(properties, listener) 调用在内部有自己的线程。通常,您不希望使用 rxjava。您希望 rxjava 处理线程,并且您编写的所有代码都应该是同步的。

我不熟悉 Facebook SDK,但我会寻找同步执行请求的调用。所以一种看起来像 public Profile getProfile(Properties properties) 的方法,而不是返回 void 并需要一个监听器的方法。

希望这会有所帮助..

【讨论】:

以上是关于RxJava 无法在未调用 Looper.prepare() 的线程内创建处理程序的主要内容,如果未能解决你的问题,请参考以下文章

CountDownTimer:“无法在未调用 Looper.prepare() 的线程内创建处理程序”

无法在未调用 Looper 准备的线程内创建处理程序 [重复]

运行时异常“无法在未调用 looper.prepare() 的线程内创建处理程序”

无法在未调用 Looper 的线程内创建处理程序 [重复]

无法在未调用 Looper.prepare()3 的线程内创建处理程序

无法在未调用 Looper.prepare() 的线程内创建处理程序