关于Rxjava
作为EventBus
的使用情况,我已经阅读了this和this等几个教程。但是,它们并没有解决我的问题。
我正在使用自己的自定义nodejs服务器和socket.io制作聊天应用。授权通过改造(使用gson)完成。即使应用程序已关闭,用户也应该收到消息,因此与socket.io的连接通过常年服务进行维护,该服务将信息转发给活动,如果它显示给用户,否则它只显示通知并写入到SQL db(TODO)。我的Service
接收来自socket.io
的呼叫并解析有效负载。当发生这种情况时,它需要向活动发送一条消息以及收到的有效负载。
MyEventBus.class
public class MyRxBus {
private static MyRxBus instance;
private PublishSubject<Object> subject = PublishSubject.create();
public static MyRxBus instanceOf() {
if (instance == null) {
instance = new MyRxBus();
}
return instance;
}
/**
* Pass any event down to event listeners.
*/
public void setString(Object object) {
subject.onNext(object);
}
/**
* Subscribe to this Observable. On event, do something
* e.g. replace a fragment
*/
public Observable<Object> getEvents() {
return subject;
}
}
SocketService类
public class SocketService extends Service {
private Socket mSocket;
public SocketService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.d("SERVICE ","SOCKET SERVICE WAS CALLED");
mSocket=SocketSingleton.getSocket("8080");
mSocket.on(Socket.EVENT_CONNECT,onConnect);
mSocket.on("new_message",onNewMessage);
mSocket.connect();
}
private Emitter.Listener onNewMessage = new Emitter.Listener() {
@Override
public void call(Object... args) {
Log.d("Received from socket ",args[0].toString());
try {
final JSONObject object = new JSONObject((String) args[0]);
//Send this object to all subscribers
//TODO: add rxjava eventbus to 1)add info to db, 2)update activity IF it is displayed
MyRxBus.instanceOf()
.setEvent(object);
} catch (JSONException e) {
e.printStackTrace();
}
}
};
//some other functions (not related at all)
}
MainActivity.class
public class MainActivity extends VesicaActivity {
private Socket mSocketOne;
private Gson gson = new Gson();
private List<ChatMessage> mMessages = new ArrayList<ChatMessage>();
private List<String> mListOfUsers = new ArrayList<String>();
Boolean isNodeOne;
String username;
private JSONArray arrayOfUsers=null;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private Boolean _isConnected=false;
private String socketIdtoSend;
@BindView(R.id.et_text)EditText etText;
@BindView(R.id.tv_user_list)TextView tvListUsers;
@BindView(R.id.tv_status)TextView tvStatus;
@BindView(R.id.toolbar)Toolbar toolbar;
@BindView(R.id.et_self_destruct_time)EditText etSelfDestructTimer;
@BindView(R.id.cb_self_destruct)CheckBox cbSelfDestruct;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
if (getSupportActionBar()!=null){
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
tvStatus.setText("checking connection...");
username = Constants.getUsername();
Integer portNumber = Constants.getPortNumber();
socketIdtoSend = getIntent().getStringExtra("socketId");
mMessages.add(createMessage("Sample Name","Sample Text",0));
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ChatAdapter(mMessages, username);
mRecyclerView.setAdapter(mAdapter);
//-----------------------------------------------------------------
MyRxBus.instanceOf()
.getEvents()
.subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
final JSONObject object = new JSONObject((String) o)
ChatMessage message = createMessage(object.getString("user")
,Encryption.Decrypt(object.getString("message"))
,object.getInt("selfDestructTime"));
mMessages.add(message);
mAdapter.notifyDataSetChanged();
Toast.makeText(MainActivity.this," new message received ", Toast.LENGTH_SHORT).show();
}
});
}
public ChatMessage createMessage(String user, String message, Integer time){
return new ChatMessage.ChatMessageBuilder()
.message(message)
.user(user)
.type("newMessage")
.selfDestructTime(time)
.sendToSocketId(socketIdtoSend)
.build();
}
public void showDialogBoxToClearHistory(){
new AlertDialog.Builder(MainActivity.this)
.setTitle("Wipe Chat History")
.setMessage("This will delete the entire chat history of this thread. It is irreversible. Do you want to continue?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
mMessages.clear();
mAdapter.notifyDataSetChanged();
Toast.makeText(MainActivity.this, "Cleared entire history", Toast.LENGTH_LONG).show();
}
})
.setNegativeButton("Skip", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try{
dialog.dismiss();
}catch (Exception e){e.printStackTrace();}
}
})
.setCancelable(false)
.show();
}
private void ScrollToBottom(){
mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount());
}
}
当我运行此代码时,出现以下错误
rx.exceptions.OnErrorNotImplementedException: Can't create handler inside thread that has not called Looper.prepare()
指向
at com.example.varun.vesica.eventbus.MyRxBus.setEvent(MyRxBus.java:26)
我知道可以将observables和观察者设置为发出/观察不同的线程,但经过大量的反复试验后,我已经放弃并需要一些帮助。
任何帮助/链接将不胜感激。谢谢!
答案 0 :(得分:0)
维持连接所有时间都会耗尽用户的电池电量。您应该考虑在设备被阻止或应用程序最小化时使用推送通知。 在活动中订阅Observable时,保存订阅并在onPause中关闭它,否则将会出现设备轮换导致的延迟连接。 考虑使用GreenRobot事件总线而不是重新发明轮子,它是非常方便的连接服务和活动的库:http://www.andreas-schrade.de/2015/11/28/android-how-to-use-the-greenrobot-eventbus/
答案 1 :(得分:0)
您试图在调用adapter.notifyDataSetChanged()
/ Toast.makeText()
的任意线程上调用setEvent()
和setString()
。
当您以更新Android UI为目标订阅getEvents()
observable时,您需要在主线程调度程序上观察:
MyRxBus.instanceOf()
.getEvents()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
final JSONObject object = new JSONObject((String) o)
ChatMessage message = createMessage(object.getString("user")
,Encryption.Decrypt(object.getString("message"))
,object.getInt("selfDestructTime"));
mMessages.add(message);
mAdapter.notifyDataSetChanged();
Toast.makeText(MainActivity.this," new message received ", Toast.LENGTH_SHORT).show();
}
});