【发布时间】:2016-04-18 06:20:10
【问题描述】:
抱歉标题过长,但我不知道该怎么做。我正在开发一个 Android 项目,在该项目中我试图使用一个名为 Cometd 的 PUSH 框架。现在 Cometd 使用 Bayuex API/规范来实现 PUSH 服务。
当您考虑用户登录或服务器端可扩展异步应用程序的普通网站部分时,Cometd 的工作简直太棒了,没有抱怨。我们面临的问题是在应用程序方面。没有可用的支持或文档。
经过一些努力,我能够编写代码以在 Android 应用程序中使用 Cometd,但不幸的是,它存在错误且不稳定。我将描述我如何构建它的结构,描述问题并展示代码。
有 2 个主要的 Activity 类,ConversationActivity 和 ChatMessagesActivity。在 ConversationActivity 中,我启动 httpclient 并通过握手连接到 PUSH 服务。
在同一个类中,有一个 ClientSessionChannel 监听器不断监听新消息。在 ConversationActivity 类中,我从服务器的数据库中检索登录用户的所有对话。这完成了,所以用户可以决定他/她想和谁聊天。
现在,当点击对话时,我会在另一个活动中为这两个用户打开聊天消息。
现在,不要忘记每个新消息都到达 ConversationActivity 中的 ClientSessionChannel 监听器,这就是为什么我必须在 ConversationActivity 和 ChatMessagesActivity 之间保持通信链接的原因,这会导致各种不稳定。
现在,我想做的是将监听器和 httpclient 推送到另一个线程/类/背景等中。 完成后,如何保持聊天消息之间的开放通信它们被打开,因此消息被更新。我希望问题很清楚。我现在将发布代码。请看:
public class ConversationActivity extends ApplicationDrawerLoader {
static Context context;
List<PrivateChannel> privateChannelList = new ArrayList<>();
List<Long> groupAccountList = new ArrayList<>();
List<String> pushPrivateChannelList = new ArrayList<>();
ListView conversationsList;
ConversationAdapter conversationAdapter;
protected static volatile BayeuxClient client;
private ChatListener chatListener = new ChatListener();
HttpClient httpClient = StaticRestTemplate.getHttpClient();
String defaultURL = StaticRestTemplate.baseURL + "/cometd";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_conversations);
context = this;
try {
httpClient.start();
} catch (Exception e) {
e.printStackTrace();
}
if (isOnline()) {
new getConversationsForLoggedInUser(this).execute();
ClientTransport clientTransport = new LongPollingTransport(null, httpClient);
client = new BayeuxClient(defaultURL, clientTransport);
client.putCookie(new HttpCookie("JSESSIONID", StaticRestTemplate.getJsessionid()));
client.getChannel(Channel.META_HANDSHAKE).addListener(new InitializerListener());
client.getChannel(Channel.META_CONNECT).addListener(new ConnectionListener());
client.handshake();
boolean success = client.waitFor(2000, BayeuxClient.State.CONNECTED);
if (!success) {
Toast.makeText(getApplicationContext(), "Could not connect to PUSH service", Toast.LENGTH_LONG).show();
}
public class getConversationsForLoggedInUser extends AsyncTask<Void, Void, ResponseEntity<PrivateChannel[]>> {
client.getChannel("/person/"+privateChannel.getPrivateChannelName()).subscribe(chatListener);
// Here I get all conversations for user and load them in ListView using adapter
}
public void sendMessageToChatActivity(final String channelName, final Map<String,Object> outputData) {
// Here send the message to Chat activity.
Log.d("Msg",String.valueOf(outputData.toString()));
runOnUiThread(new Runnable() {
public void run() {
ChatMessagesActivity.recieveUpdatedMessage(channelName, outputData);
}
});
}
public static void recieveMessageFromChatActivity(String channelName, Map<String, Object> inputData){
//client.putCookie(new HttpCookie("JSESSIONID", StaticRestTemplate.getJsessionid()));
client.getChannel(channelName).publish(inputData);
}
private void initialize() {
}
private void connectionEstablished() {
System.err.printf("system: Connection to Server Opened%n");
}
private void connectionClosed() {
System.err.printf("system: Connection to Server Closed%n");
}
private void connectionBroken() {
System.err.printf("system: Connection to Server Broken%n");
}
private class InitializerListener implements ClientSessionChannel.MessageListener {
@Override
public void onMessage(ClientSessionChannel channel, Message message) {
if (message.isSuccessful()) {
initialize();
}
}
}
private class ConnectionListener implements ClientSessionChannel.MessageListener {
private boolean wasConnected;
private boolean connected;
public void onMessage(ClientSessionChannel channel, Message message) {
if (client.isDisconnected()) {
connected = false;
connectionClosed();
return;
}
wasConnected = connected;
connected = message.isSuccessful();
if (!wasConnected && connected) {
connectionEstablished();
} else if (wasConnected && !connected) {
connectionBroken();
}
}
}
// THe below method sends message to the ChatMessagesActivity.
public class ChatListener implements ClientSessionChannel.MessageListener {
public void onMessage(ClientSessionChannel channel, Message message) {
sendMessageToChatActivity(channel.toString(),message);
}
}
ChatMessagesActivity :
public class ChatMessagesActivity extends ApplicationDrawerLoader {
Context context;
public ListView chatList;
protected static ChatMessagesAdapter chatMessagesAdapter = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_messages);
chatList = (ListView) findViewById(R.id.chatList);
context = this;
sendMessageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Here I send message to ConversationActivity, which in turn sends it via CometdD.
sendMessageToConversationsActivity("/service/person/" + String.valueOf(conversationId), outputData);
}
public static void recieveUpdatedMessage(String channelName, Map<String, Object> input) {
// Here I recieve the new message and add it to adapter.
HashMap<String, String> insertMap = new HashMap<>();
// Add data to hashmap and add it to adapter
chatMessagesAdapter.add(insertMap);
chatMessagesAdapter.notifyDataSetChanged();
}
public void sendMessageToConversationsActivity(String channelName, Map<String, Object> output) {
ConversationActivity.recieveMessageFromChatActivity(channelName, output);
}
public class getPrivateChatsForUser extends AsyncTask<Void, Void, ResponseEntity<RestReplies[]>> {
ChatMessagesActivity chatMessagesActivity = null;
getPrivateChatsForUser(ChatMessagesActivity chatMessagesActivity) {
this.chatMessagesActivity = chatMessagesActivity;
}
// Here i get chat messages from network and load it in list-view using adapter.,
public class ChatMessagesAdapter extends BaseAdapter {
// Adapter code to display, nothing fancy.
}
}
我知道代码似乎有点长,但问题也是如此。我将不胜感激这方面的任何帮助。我不是 Android 专家,但只是想整合它。谢谢你。 :-)
编辑
public class CometdService extends Service {
protected static volatile BayeuxClient client;
String defaultURL = StaticRestTemplate.baseURL + "/cometd";
HttpClient httpClient = StaticRestTemplate.getHttpClient();
private ChatListener chatListener = new ChatListener();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
httpClient.start();
} catch (Exception e) {
e.printStackTrace();
}
ClientTransport clientTransport = new LongPollingTransport(null, httpClient);
client = new BayeuxClient(defaultURL, clientTransport);
client.putCookie(new HttpCookie("JSESSIONID", StaticRestTemplate.getJsessionid()));
client.getChannel(Channel.META_HANDSHAKE).addListener(new InitializerListener());
client.getChannel(Channel.META_CONNECT).addListener(new ConnectionListener());
client.handshake();
boolean success = client.waitFor(2000, BayeuxClient.State.CONNECTED);
if (!success) {
Toast.makeText(getApplicationContext(), "Could not connect to PUSH service", Toast.LENGTH_LONG).show();
}
return Service.START_REDELIVER_INTENT;
}
@Override
public void onDestroy() {
}
private class InitializerListener implements ClientSessionChannel.MessageListener {
@Override
public void onMessage(ClientSessionChannel channel, Message message) {
if (message.isSuccessful()) {
initialize();
}
}
}
private class ConnectionListener implements ClientSessionChannel.MessageListener {
private boolean wasConnected;
private boolean connected;
public void onMessage(ClientSessionChannel channel, Message message) {
if (client.isDisconnected()) {
connected = false;
connectionClosed();
return;
}
wasConnected = connected;
connected = message.isSuccessful();
if (!wasConnected && connected) {
connectionEstablished();
} else if (wasConnected && !connected) {
connectionBroken();
}
}
}
private void initialize() {
}
private void connectionEstablished() {
System.err.printf("system: Connection to Server Opened%n");
}
private void connectionClosed() {
System.err.printf("system: Connection to Server Closed%n");
}
private void connectionBroken() {
System.err.printf("system: Connection to Server Broken%n");
}
public class ChatListener implements ClientSessionChannel.MessageListener {
public void onMessage(ClientSessionChannel channel, Message message) {
// sendMessageToChatActivity(channel.toString(), message);
}
}
}
一个新创建的服务,正在进行中。
【问题讨论】:
-
In ConversationActivity, I start a httpclient and connect to the PUSH service by performing a handshake.错误,这是一个应该启动这样一个连接的Service -
@pskink :好的,正如 csenga 也提到的,我应该在服务中启动 httpclient。只有一件事,ConnectionListener 类是否也应该在 Service 中?
-
是的,不像其他人说不要使用
BroadcastReceivers,而是阅读“绑定服务” -
@pskink :好的,这肯定需要一些时间来实现,我会随着时间的推移进行编辑。非常感谢。 :-)
-
@pskink :我创建了一个新服务并将连接和相关代码放在那里。要使用 PUSH 框架,我必须订阅频道。现在的问题是,我必须使用 BayeuxClient 实例化,但是因为它已移至 Service,所以我无法订阅 ConversationActivity 中的频道。您能否检查一下 ConversationActivity 中的 AsyncTask 和我添加的 Service 类。谢谢.. :-)
标签: java android push comet cometd