之前学习了通过Openfire+spark+smack的模式来完成我们的即时通讯软件,上次我们已经完成了Openfire的安装和配置,这次我们继续完成我们的客户端部分。
1.首先我们通过百度smack来下载我们所需要的jar包,将下载好的jar包导入到我们的工程中,创建一个工具类XmppTool:
package com.xmpp.client.util;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.json.JSONArray;
public class XmppTool {
private static XMPPConnection con = null;
private static void openConnection(String url, String pcName) {
try {
// url、端口,也可以设置连接的服务器名字,地址,端口,用户。
ConnectionConfiguration connConfig = new ConnectionConfiguration(
"192.168.2.113", 5222, "JEREHEDU");
con = new XMPPConnection(connConfig);
con.connect();
} catch (XMPPException xe) {
xe.printStackTrace();
}
}
private static void openOffConnection(String url, String pcName) {
try {
ConnectionConfiguration connConfig = new ConnectionConfiguration(
url, 5222, pcName);
connConfig.setSendPresence(false);
con = new XMPPConnection(connConfig);
con.connect();
} catch (XMPPException xe) {
xe.printStackTrace();
}
}
public static XMPPConnection getOffConnection(String url, String pcName) {
if (con == null) {
openOffConnection(url, pcName);
}
return con;
}
public static XMPPConnection getConnection(String url, String pcName) {
if (con == null) {
openConnection(url, pcName);
}
return con;
}
public static void closeConnection() {
con.disconnect();
con = null;
}
}
工具类XmppTool
主要还是通过ConnectionConfiguration来连接服务器,传入三个参数(地址,端口,用户名)
2.登陆界面
package com.xmpp.client; import java.util.Iterator; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smackx.OfflineMessageManager; import com.xmpp.client.util.XmppTool; import com.xmpp.client.R; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.Toast; public class FormLogin extends Activity implements OnClickListener { private EditText useridText, pwdText, urlText, pcnameText;; private LinearLayout layout1, layout2; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.formlogin); // 获取用户和密码 this.useridText = (EditText) findViewById(R.id.formlogin_userid); this.pwdText = (EditText) findViewById(R.id.formlogin_pwd); this.urlText = (EditText) findViewById(R.id.formlogin_url); this.pcnameText = (EditText) findViewById(R.id.formlogin_pcname); // 正在登录 this.layout1 = (LinearLayout) findViewById(R.id.formlogin_layout1); // 登录界面 this.layout2 = (LinearLayout) findViewById(R.id.formlogin_layout2); Button btsave = (Button) findViewById(R.id.formlogin_btsubmit); btsave.setOnClickListener(this); Button btcancel = (Button) findViewById(R.id.formlogin_btcancel); btcancel.setOnClickListener(this); } @Override public void onClick(View v) { // 根据ID来进行提交或者取消 switch (v.getId()) { case R.id.formlogin_btsubmit: // 取得填入的用户和密码 // 取得填入的用户和密码 final String USERID = this.useridText.getText().toString(); final String PWD = this.pwdText.getText().toString(); final String URL = this.urlText.getText().toString(); final String PCNAME = this.pcnameText.getText().toString(); Thread t = new Thread(new Runnable() { public void run() { // sendEmptyMessage:发送一条消息 handler.sendEmptyMessage(1); try { // 连接 XmppTool.getOffConnection(URL, PCNAME).login(USERID, PWD); getOfflineMessage(); // 状态 Presence presence = new Presence( Presence.Type.available); XmppTool.getConnection(URL, PCNAME) .sendPacket(presence); Intent intent = new Intent(); intent.setClass(FormLogin.this, FormClient.class); intent.putExtra("USERID", USERID); intent.putExtra("URL", URL); intent.putExtra("PCNAME", PCNAME); FormLogin.this.startActivity(intent); FormLogin.this.finish(); } catch (XMPPException e) { XmppTool.closeConnection(); handler.sendEmptyMessage(2); } } }); t.start(); break; case R.id.formlogin_btcancel: finish(); break; } } /** * 获取离线消息 */ private void getOfflineMessage() { OfflineMessageManager offlineManager = new OfflineMessageManager( XmppTool.getConnection(this.urlText.getText().toString(), this.pcnameText.getText().toString())); Iterator<org.jivesoftware.smack.packet.Message> it; try { it = offlineManager.getMessages(); while (it.hasNext()) { org.jivesoftware.smack.packet.Message message = it.next(); Log.i("离线消息", "收到离线消息, Received from 【" + message.getFrom() + "】 message: " + message.getBody()); } // 删除离线消息 offlineManager.deleteMessages(); } catch (XMPPException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == 1) { layout1.setVisibility(View.VISIBLE); layout2.setVisibility(View.GONE); } else if (msg.what == 2) { layout1.setVisibility(View.GONE); layout2.setVisibility(View.VISIBLE); Toast.makeText(FormLogin.this, "登录失败!", Toast.LENGTH_SHORT) .show(); } }; }; }
3.聊天客户端
package com.xmpp.client; import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.ChatManager; import org.jivesoftware.smack.ChatManagerListener; import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smackx.filetransfer.FileTransfer; import org.jivesoftware.smackx.filetransfer.FileTransfer.Status; import org.jivesoftware.smackx.filetransfer.FileTransferListener; import org.jivesoftware.smackx.filetransfer.FileTransferManager; import org.jivesoftware.smackx.filetransfer.FileTransferRequest; import org.jivesoftware.smackx.filetransfer.IncomingFileTransfer; import org.jivesoftware.smackx.filetransfer.OutgoingFileTransfer; import org.jivesoftware.smackx.muc.MultiUserChat; import org.jivesoftware.smackx.packet.DelayInformation; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.lidroid.xutils.HttpUtils; import com.lidroid.xutils.exception.HttpException; import com.lidroid.xutils.http.RequestParams; import com.lidroid.xutils.http.ResponseInfo; import com.lidroid.xutils.http.callback.RequestCallBack; import com.lidroid.xutils.http.client.HttpRequest.HttpMethod; import com.xmpp.client.util.ScreenShot; import com.xmpp.client.util.TimeRender; import com.xmpp.client.util.XmppTool; public class FormClient extends Activity { private MyAdapter adapter; private List<Msg> listMsg = new ArrayList<Msg>(); private String pUSERID; private EditText msgText, toText; private ProgressBar pb; private Button btsend; private TextView waitpb; private String URL; private String PCNAME; private String PERSON; private Chat mychat; private ChatManager cm; public class Msg { String userid; String msg; String date; String from; public Msg(String userid, String msg, String date, String from) { this.userid = userid; this.msg = msg; this.date = date; this.from = from; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.formclient); // 获取Intent传过来的用户名,url,pcname this.pUSERID = getIntent().getStringExtra("USERID"); this.URL = getIntent().getStringExtra("URL"); this.PCNAME = getIntent().getStringExtra("PCNAME"); ListView listview = (ListView) findViewById(R.id.formclient_listview); listview.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL); this.adapter = new MyAdapter(this); listview.setAdapter(adapter); // 获取文本信息 this.msgText = (EditText) findViewById(R.id.formclient_text); // 获取聊天对象 this.toText = (EditText) findViewById(R.id.formclient_to); // 发送消息给water-pc服务器water(获取自己的服务器,和好友) // 消息监听 cm = XmppTool.getConnection(URL, PCNAME).getChatManager(); chatListener(); // 发送消息 btsend = (Button) findViewById(R.id.formclient_btsend); sendChatMessage(); } /** * send chat message * */ private void sendChatMessage() { btsend.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 获取text文本 String msg = msgText.getText().toString(); PERSON = toText.getText().toString(); mychat = cm.createChat(PERSON + "@" + PCNAME, null); if (msg.length() > 0) { // 发送消息 listMsg.add(new Msg(pUSERID, msg, TimeRender.getDate(), "OUT")); // 刷新适配器 adapter.notifyDataSetChanged(); try { // 发送消息给指定人 mychat.sendMessage(msg); } catch (XMPPException e) { e.printStackTrace(); } } else { Toast.makeText(FormClient.this, "请输入信息", Toast.LENGTH_SHORT) .show(); } // 清空text msgText.setText(""); } }); } /** * 监听单人消息 */ private void chatListener() { cm.addChatListener(new ChatManagerListener() { @Override public void chatCreated(Chat chat, boolean able) { chat.addMessageListener(new MessageListener() { @Override public void processMessage(Chat chat2, Message message) { Log.v("--tags--", "--tags-form--" + message.getFrom()); Log.v("--tags--", "--tags-message--" + message.getBody()); // 收到来自water-pc服务器water的消息(获取自己的服务器,和好友) if (message.getFrom().contains(pUSERID + "@keyi-pc")) { // 获取用户、消息、时间、IN String[] args = new String[] { pUSERID, message.getBody(), TimeRender.getDate(), "IN" }; android.os.Message msg = handler.obtainMessage(); msg.what = 1; msg.obj = args; msg.sendToTarget(); } else { } Log.i("json", "b " + message.getBody()); String amsg = message.getBody(); String[] args = null; args = new String[] { message.getFrom(), amsg, TimeRender.getDate(), "IN" }; android.os.Message msg = handler .obtainMessage(); msg.what = 1; msg.obj = args; msg.sendToTarget(); } }); } }); } private OutgoingFileTransfer fileTransfer; Handler outHandler = new Handler(); Runnable outrunnable = new Runnable() { @Override public void run() { if (fileTransfer.getProgress() == 1) { pb.setVisibility(View.GONE); outHandler.removeCallbacks(outrunnable); } outHandler.postDelayed(outrunnable, 100); } }; private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case 1: // 获取消息并显示 String[] args = (String[]) msg.obj; listMsg.add(new Msg(args[0], args[1], args[2], args[3])); // 刷新适配器 adapter.notifyDataSetChanged(); break; case 2: // 附件进度条 if (pb.getVisibility() == View.GONE) { pb.setVisibility(View.VISIBLE); waitpb.setVisibility(View.VISIBLE); } break; case 3: pb.setProgress(msg.arg1); break; case 4: pb.setVisibility(View.GONE); waitpb.setVisibility(View.GONE); break; default: break; } }; }; // 退出 @Override public void onBackPressed() { super.onBackPressed(); XmppTool.closeConnection(); System.exit(0); android.os.Process.killProcess(android.os.Process.myPid()); } class MyAdapter extends BaseAdapter { private Context cxt; private LayoutInflater inflater; public MyAdapter(FormClient formClient) { this.cxt = formClient; } @Override public int getCount() { return listMsg.size(); } @Override public Object getItem(int position) { return listMsg.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // 显示消息的布局:内容、背景、用户、时间 this.inflater = (LayoutInflater) this.cxt .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // IN,OUT的图片 if (listMsg.get(position).from.equals("IN")) { convertView = this.inflater.inflate( R.layout.formclient_chat_in, null); } else { convertView = this.inflater.inflate( R.layout.formclient_chat_out, null); } TextView useridView = (TextView) convertView .findViewById(R.id.formclient_row_userid); TextView dateView = (TextView) convertView .findViewById(R.id.formclient_row_date); TextView msgView = (TextView) convertView .findViewById(R.id.formclient_row_msg); useridView.setText(listMsg.get(position).userid); dateView.setText(listMsg.get(position).date); msgView.setText(listMsg.get(position).msg); return convertView; } } }
其中有好多类都是自带的我们只需要实现它就可以了。