NetworkOnMainThreadException或OnErrorNotImplementedException RxAndroid向绑定服务发送/接收数据

问题描述 投票:0回答:1

我正在使用此answer的更新版本将活动链接(绑定)到服务。

my service.Java

public class MyService extends Service {

   private LocalBinder binder = new LocalBinder();
   private Observable<Integer> responseObservable;
   private ObservableEmitter<Integer> responseObserver;

   public static boolean isRunning = false;

   @Nullable
   @Override
   public IBinder onBind(Intent intent) {
      return binder;
   }

   @Override
   public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
       GsonConverterFactory factory = GsonConverterFactory.create(new GsonBuilder()
            .setLenient()
            .create());

      HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
      interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

      Client client = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(new OkHttpClient.Builder()
                 .addInterceptor(interceptor)
                 .build())
            .addConverterFactory(factory)
            .build()
            .create(Client.class);

      for (//some loop) {
          Response<Result> response = client.search(//some params here)
                           .execute();
          responseObserver.onNext(response.code());
      }
      return START_NOT_STICKY;
   }

   @Override
   public void onDestroy() {
      super.onDestroy();
      isRunning = false;
   }

   public Observable<Message> observeResponse() {
      if (responseObservable == null) {
         responseObservable = Observable.create(em -> responseObserver = em);
         responseObservable = responseObservable.share();
      }
      return responseObservable;
   }


   public class LocalBinder extends Binder {

      public DService getService() {
         return MyService.this;
      }
   }

}

main activity.Java

public class MainActivityextends AppCompatActivity {

   private MyService service;
   private Disposable disposable;

   private ServiceConnection serviceConnection = new ServiceConnection() {
      @Override
      public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
         service = ((MyService.LocalBinder) iBinder).getService();
         disposable = service.observeResponse()
               .observeOn(Schedulers.newThread())
               .subscribe(responseCode -> updateUI()); //this must run on main thread
         startService(new Intent(MainActivity.this, MyService.class));
      }

      @Override
      public void onServiceDisconnected(ComponentName componentName) {
      }
   };

   @Override
   protected void onDestroy() {
      if (disposable != null)
         disposable.dispose();
      unbindService(serviceConnection);
      super.onDestroy();
   }

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       //....

       Button start = findViewById(R.id.start);
       start.setOnClickListener(v -> {
           Intent intent = new Intent(this, MyService.class);
           bindService(intent, serviceConnection, BIND_AUTO_CREATE);
       });

       //....
   }
}

如果我使用observeOn(AndroidSchedulers.mainThread()),我得到NetworkOnMainThreadException,如果我使用observeOn(Schedulers.newThread()),我得到OnErrorNotImplementedException: Only the original thread that created a view hierarchy can touch its views.

我知道这两个错误意味着什么,在正常情况下我可以很容易地解决它们,但这里没有我通常做的工作。

我需要服务中的网络请求同步执行,因为它处于循环中,我按顺序处理每个请求结果,异步调用对我来说不是一个选项。

我试过runOnUiThread(() -> updateUI()),但它会产生同样的错误。我也尝试在新线程上执行该服务,但仍然是同样的错误。

android retrofit rx-android synchronous okhttp3
1个回答
1
投票

Service的第一个在Main Thread上运行

服务在其托管过程的主线程中运行;除非另行指定,否则服务不会创建自己的线程,也不会在单独的进程中运行。如果您的服务要执行任何CPU密集型工作或阻止操作(如MP3播放或网络),则应在服务中创建新线程以完成该工作。通过使用单独的线程,您可以降低应用程序无响应(ANR)错误的风险,并且应用程序的主线程可以保持专用于用户与您的活动的交互。 REFERENCE

因此,在服务中直接进行api调用将导致所有情况下的NetworkOnMainThreadException

  1. 当你把qazxsw poi,你肯定会有qazxsw poi;上述原因
  2. 当你把observeOn(AndroidSchedulers.mainThread()),服务中的api调用导致NetworkOnMainThreadException;但由于您使用过observeOn(Schedulers.newThread()),它会向其订阅者返回错误消息;但在您的情况下,您没有添加错误部分。

你用过:

NetworkOnMainThreadException

为了防止应用程序崩溃,你必须使用

Rx

现在来解决这个问题:

  1. 在服务中,确保在新的服务线程上调用API;

要么

  1. 您还可以尝试使用对另一个类(如MVP中的Presenter)的引用进行API调用,您可以在其中使用以下命令进行API调用并直接向UI发送响应: subscribe(responseCode -> updateUI());
© www.soinside.com 2019 - 2024. All rights reserved.