我正在使用此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())
,但它会产生同样的错误。我也尝试在新线程上执行该服务,但仍然是同样的错误。
Service
的第一个在Main Thread上运行
服务在其托管过程的主线程中运行;除非另行指定,否则服务不会创建自己的线程,也不会在单独的进程中运行。如果您的服务要执行任何CPU密集型工作或阻止操作(如MP3播放或网络),则应在服务中创建新线程以完成该工作。通过使用单独的线程,您可以降低应用程序无响应(ANR)错误的风险,并且应用程序的主线程可以保持专用于用户与您的活动的交互。 REFERENCE
因此,在服务中直接进行api调用将导致所有情况下的NetworkOnMainThreadException
。
observeOn(AndroidSchedulers.mainThread())
,服务中的api调用导致NetworkOnMainThreadException
;但由于您使用过observeOn(Schedulers.newThread())
,它会向其订阅者返回错误消息;但在您的情况下,您没有添加错误部分。你用过:
NetworkOnMainThreadException
为了防止应用程序崩溃,你必须使用
Rx
现在来解决这个问题:
要么
subscribe(responseCode -> updateUI());