- 浏览: 8094 次
- 性别:
- 来自: 武汉
文章分类
最新评论
[size=x-small]
初学android,没有急于去了解android各种图形类的用法,毕竟每个学Android都有一颗做游戏的心。但是通讯这一块才是一个移动终端最需要去了解的有关socket,由于之前没有怎么接触,这次借着学android的机遇学习了一下,下面就讲我我自己一个简单的socket例子。
之前是想写一个建议聊天室的,网上有很多人都实现了,但是文章都是抄来抄去,代码也都稀稀散散不完全,给很多初学的人很莫名的感觉,在做点对点聊天之前,先明白socket怎么样通讯才是至关重要的。在做socket之前或许,用httpclient访问下PC服务器这些例子也可以尝试下,起码能熟悉android通讯中流的一些用法。
我做了一个简单的app,毕竟是给手机之间用,它肯定有一个server端,一个client端。先把界面展示一下。
如果是server端,载入界面后就点击server端按钮,服务器就阻塞直到客户端请求,然后进入本地联系人查询页面,选好本地联系人,将联系人发送给请求端。
服务器端代码:
client端载入页面选择好请求方的IP地址点击建立连接,完成一次请求。
客户端代码:
MainActivity.java
Object流对象:
界面布局:
activity_main.xml:
联系人选择布局:
conperson.xml
AndroidManifest.xml
备注:有些权限没有用到,可适当更改,有预留给其他功能开发用。[/size]
初学android,没有急于去了解android各种图形类的用法,毕竟每个学Android都有一颗做游戏的心。但是通讯这一块才是一个移动终端最需要去了解的有关socket,由于之前没有怎么接触,这次借着学android的机遇学习了一下,下面就讲我我自己一个简单的socket例子。
之前是想写一个建议聊天室的,网上有很多人都实现了,但是文章都是抄来抄去,代码也都稀稀散散不完全,给很多初学的人很莫名的感觉,在做点对点聊天之前,先明白socket怎么样通讯才是至关重要的。在做socket之前或许,用httpclient访问下PC服务器这些例子也可以尝试下,起码能熟悉android通讯中流的一些用法。
我做了一个简单的app,毕竟是给手机之间用,它肯定有一个server端,一个client端。先把界面展示一下。
如果是server端,载入界面后就点击server端按钮,服务器就阻塞直到客户端请求,然后进入本地联系人查询页面,选好本地联系人,将联系人发送给请求端。
服务器端代码:
package com.exmessage; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Activity; import android.app.AlertDialog; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; public class PServer implements Runnable { private TextView meesage;//聊天记录 private int zsflag=0;//阻塞flag private ServerSocket server; private Activity context; private Handler handler; int count = 1; private ListView listview; private Allmessageobj messageobj =new Allmessageobj();//传输信息对象载体 private Map objmap=new HashMap(); private Allmessageobj returnobj=new Allmessageobj(); private OnItemClickListener myonclister; private Socket client=new Socket(); private OutputStream outdata ; public PServer(Activity contextarg) { try { context=contextarg; meesage=(TextView)context.findViewById(R.id.textView1);//连接信息框 //创建属于主线程的handler handler=new Handler(); server=new ServerSocket(10010); new Thread(this).start(); context.setContentView(R.layout.conperson); listview=(ListView)context.findViewById(R.id.listView1); myonclister=new OnItemClickListener(){//添加事件 public void onItemClick(AdapterView<?> arg0, View arg1,int arg2, long arg3) { // OutputStream outdata = client.getOutputStream(); try { Object objs=objmap.get(arg2); returnobj=(Allmessageobj)objs; zsflag=1; context.setContentView(R.layout.activity_main); TextView tsmessag=(TextView)context.findViewById(R.id.textView1); EditText etx=(EditText)context.findViewById(R.id.search); etx.setCursorVisible(false); etx.setFocusable(false); etx.setFocusableInTouchMode(false); tsmessag.setText("发送<"+returnobj.getName()+":"+returnobj.getPhonenum()+">成功!目标IP<"+String.valueOf(client.getInetAddress())+">"); java.io.ByteArrayOutputStream bop = new java.io.ByteArrayOutputStream(); java.io.ObjectOutputStream oop; oop = new java.io.ObjectOutputStream(bop); oop.writeObject(returnobj); outdata.write(bop.toByteArray()); outdata.flush(); outdata.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}; listview.setOnItemClickListener(myonclister); } catch (IOException e) { // TODO Auto-generated catch block new AlertDialog.Builder(context).setTitle("提示").setMessage(String.valueOf(e)).setPositiveButton("OK", null).show(); } } public void run() { try { // handler.post(runnableUi); while(true){ client=server.accept(); handler.post(listviewUi); outdata = client.getOutputStream(); } } catch (Exception e) { e.printStackTrace(); System.out.println("服务器 run 异常: " + e.getMessage()); } } /* 读取命令 */ public static String readCMDFromSocket(InputStream in) { int MAX_BUFFER_BYTES = 2048; String msg = ""; byte[] tempbuffer = new byte[MAX_BUFFER_BYTES]; try { int numReadedBytes = in.read(tempbuffer, 0, tempbuffer.length); msg = new String(tempbuffer, 0, numReadedBytes, "utf-8"); tempbuffer = null; } catch (Exception e) { e.printStackTrace(); } return msg; } Runnable runnableUi=new Runnable(){ public void run() { //更新界面 meesage.setText("信息:"+messageobj.getMessage()+"...."); //meesage.setText(meesage.getText()+"\n"+messageobj.getIpaddress()+":"+messageobj.getMessage()); } }; Runnable listviewUi=new Runnable(){ public void run() { context.setContentView(R.layout.conperson); listview=(ListView)context.findViewById(R.id.listView1); listview.setOnItemClickListener(myonclister); //更新界面 List list=new ArrayList(); Uri uri = Uri.parse("content://com.android.contacts/contacts"); //String selection = "mimetype='vnd.android.cursor.item/contact_event' and data2='3'"; Cursor cursor = context.getContentResolver().query(uri, new String[]{"_id"}, null, null, null); //Cursor cur = MainActivity.this.getContentResolver().query(ContactsContract.Data.CONTENT_URI, projection, selection, null, null); List params=new ArrayList(); List datalist=new ArrayList(); while (cursor.moveToNext()) { messageobj=new Allmessageobj(); int contractID = cursor.getInt(0); StringBuilder sb = new StringBuilder(); // sb.append(contractID); // Uri uri11 = ContactsContract.Contacts.CONTENT_URI; uri = Uri.parse("content://com.android.contacts/contacts/" + contractID + "/data"); Cursor cursor1 = context.getContentResolver().query(uri, new String[]{"mimetype", "data1", "data2"}, null, null, null); //UserPhoneVO vo=new UserPhoneVO(); while (cursor1.moveToNext()) { String data1 = cursor1.getString(cursor1.getColumnIndex("data1")); String mimeType = cursor1.getString(cursor1.getColumnIndex("mimetype")); if ("vnd.android.cursor.item/name".equals(mimeType)) { messageobj.setName(data1); sb.append(data1+"-"); } else if ("vnd.android.cursor.item/email_v2".equals(mimeType)) { sb.append( data1+"-"); } else if ("vnd.android.cursor.item/phone_v2".equals(mimeType)) { sb.append(data1+"-"); messageobj.setPhonenum(data1); } } datalist.add(messageobj); cursor1.close(); } cursor.close(); for(int i=0;i<datalist.size();i++){ Allmessageobj messavo=(Allmessageobj)datalist.get(i); objmap.put(i,messavo); params.add(messavo.getName()+":"+messavo.getPhonenum()); } listview.setAdapter(new ArrayAdapter (context,android.R.layout.simple_list_item_1,params)); //listview.setAdapter(adapter); // meesage.setText("信息:"+messageobj.getMessage()+"...."); //meesage.setText(meesage.getText()+"\n"+messageobj.getIpaddress()+":"+messageobj.getMessage()); } }; }
client端载入页面选择好请求方的IP地址点击建立连接,完成一次请求。
客户端代码:
package com.exmessage; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import android.app.Activity; import android.app.AlertDialog; import android.os.Handler; import android.widget.EditText; import android.widget.TextView; public class Client implements Runnable{ /** 端口号 */ public static final int PORT = 10010; private Activity context; private EditText txtvs; private TextView dismes;//显示连接信息 /** ip 地址 */ public String IP; private Allmessageobj returnobj=new Allmessageobj(); private Handler handler=new Handler(); public Client(Activity contextarg) { context=contextarg; txtvs=(EditText)context.findViewById(R.id.search); dismes=(TextView)context.findViewById(R.id.textView1); IP=String.valueOf(txtvs.getText()); //handler=new Handler(); //new AlertDialog.Builder(context).setTitle("提示").setMessage("连接:"+IP+"....").setPositiveButton("OK", null).show(); run(); } public void run() { Socket socket = null; try { // 创建一个流套接字并将其连接到指定主机上的指定端口号 //while (true) { // 创建一个流套接字并将其连接到指定主机上的指定端口号 socket = new Socket(IP, PORT); // 读取服务器端数据 //System.out.println("是否连接"+socket.isConnected()); // System.out.println("BufferSize"+socket.getReceiveBufferSize()); // String inputstr = new BufferedReader(new InputStreamReader(System.in)).readLine(); // InputStream inputStream = new ByteArrayInputStream(abc.toString().getBytes()); //String str = new BufferedReader(new InputStreamReader(inputStream)).readLine(); //ObjectOutputStream output=new ObjectOutputStream(socket.getOutputStream()); InputStream indata=socket.getInputStream(); //DataOutputStream outdata=new DataOutputStream(socket.getOutputStream()); //Allmessageobj outmessage=new Allmessageobj(); //outmessage.setMessage("已响应"); //outdata.writeObject(outmessage); //outdata.writeUTF("请求中。。。"); //indata.read(); //byte b[] = utfstring.getBytes(); //String usus=indata.read(); //byte[] bytess=usus.getBytes(); java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); byte[] bt = new byte[2014]; //while(indata.read(bt)!= -1) // { indata.read(bt); bout.write(bt,0,bt.length); //} java.io.ByteArrayInputStream biin = new ByteArrayInputStream(bout.toByteArray()); java.io.ObjectInputStream isr=new java.io.ObjectInputStream(biin); Object obj = isr.readObject(); returnobj=(Allmessageobj)obj; //dismes.setText(returnobj.getName()+"--"+returnobj.getPhonenum()); dismes.setText(returnobj.getName()+"--"+returnobj.getPhonenum()); new AlertDialog.Builder(context).setTitle("提示").setMessage(returnobj.getName()+"--"+returnobj.getPhonenum()).setPositiveButton("OK", null).show(); // handler.post(runnableUi); //} } catch (Exception e) { new AlertDialog.Builder(context).setTitle("提示").setMessage(String.valueOf(e)).setPositiveButton("OK", null).show(); } finally { if (socket != null) { try { socket.close(); } catch (Exception e) { socket = null; System.out.println("客户端 finally 异常: " + e.getMessage()); } } } } Runnable runnableUi=new Runnable(){ public void run() { //更新界面 new AlertDialog.Builder(context).setTitle("提示").setMessage(returnobj.getName()+"--"+returnobj.getPhonenum()).setPositiveButton("OK", null).show(); //meesage.setText(meesage.getText()+"\n"+messageobj.getIpaddress()+":"+messageobj.getMessage()); } }; }
MainActivity.java
package com.exmessage; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { private EditText etx;//IP地址 private TextView txtvs;//显示连接信息 private Button btsend;//建立连接 private String IPAddress; private Button btserver;//server按钮 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btsend=(Button)findViewById(R.id.button1); etx=(EditText)findViewById(R.id.search); txtvs=(TextView)findViewById(R.id.textView1); IPAddress=getlocalip(); txtvs.setText("本地WIFI-IP地址:"+IPAddress);//初始显示本地IP btserver=(Button)findViewById(R.id.button2); /** * SERVER端事件 */ btserver.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { /** * IP输入只读 */ etx.setCursorVisible(false); etx.setFocusable(false); etx.setFocusableInTouchMode(false); //开启server端线程 new AlertDialog.Builder(MainActivity.this).setTitle("提示").setMessage("启动server端监听").setPositiveButton("OK", null).show(); new PServer(MainActivity.this); } }); /** * client端事件 */ btsend.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { /** * IP输入只读 */ etx.setCursorVisible(false); etx.setFocusable(false); etx.setFocusableInTouchMode(false); //开启server端线程 //new AlertDialog.Builder(MainActivity.this).setTitle("提示").setMessage("启动请求......").setPositiveButton("OK", null).show(); new Client(MainActivity.this); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } /** * 通过wifi连接获取IP地址 * @return */ private String getlocalip(){ WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); int ipAddress = wifiInfo.getIpAddress(); // Log.d(Tag, "int ip "+ipAddress); if(ipAddress==0)return null; return ((ipAddress & 0xff)+"."+(ipAddress>>8 & 0xff)+"." +(ipAddress>>16 & 0xff)+"."+(ipAddress>>24 & 0xff)); } }
Object流对象:
package com.exmessage; import java.io.Serializable; public class Allmessageobj implements Serializable{ /** * */ private static final long serialVersionUID = 1579114883234266292L; public String ipaddress; public String message; public String flagcode; public String name; public String phonenum; public String getIpaddress() { return ipaddress; } public void setIpaddress(String ipaddress) { this.ipaddress = ipaddress; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getFlagcode() { return flagcode; } public void setFlagcode(String flagcode) { this.flagcode = flagcode; } public String toString(){ return name+"----"+phonenum; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhonenum() { return phonenum; } public void setPhonenum(String phonenum) { this.phonenum = phonenum; } }
界面布局:
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TableRow android:id="@+id/tableRow1" android:layout_width="match_parent" android:layout_height="wrap_content" > <EditText android:id="@+id/search" android:layout_width="140dip" android:layout_height="wrap_content" android:hint="@string/search_hint" android:imeOptions="actionSend" android:inputType="text" android:singleLine="true" > <requestFocus /> </EditText> <Button android:id="@+id/button1" style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/connbegain" /> <Button android:id="@+id/button2" style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/asserver" /> </TableRow> <TableRow android:id="@+id/tableRow2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.01" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </TableRow> </LinearLayout>
联系人选择布局:
conperson.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.exmessage" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <!-- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <!-- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" /> --> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.exmessage.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
备注:有些权限没有用到,可适当更改,有预留给其他功能开发用。[/size]
相关推荐
6. 推送服务:考虑到电池效率和用户体验,源码可能利用Google Firebase Cloud Messaging (FCM) 或其他第三方推送服务,实现在后台接收服务器推送的消息。 二、Openfire服务器 1. 开源IM服务器:Openfire是一款基于...
对于移动设备间的即时通信,MQTT也是一个选择。 3. WebSocket:提供全双工通信,一旦建立连接,客户端和服务器可以双向发送数据。WebSocket更适合需要持续连接的即时通信场景。 四、多线程与异步处理 即时通信系统...
10. **推送通知**:虽然未明确提及,但一个完整的聊天应用可能还包含了Google Firebase Cloud Messaging (FCM) 或其他推送服务,用于在用户不活跃时发送新消息的通知。 通过研究这个源码,开发者可以学习到Android...
应急通信系统Android客户端是一个专为计算机科学、软件工程和通信工程专业的学生设计的项目,旨在帮助他们进行课程设计和毕业设计。这个系统的核心是利用Android平台构建一个能够应对紧急情况的通信工具。以下是对这...
这不仅仅是一个简单的用户界面模仿,而是需要构建一个完整的、可靠的实时通信系统。以下是一些核心的技术点和知识点: 1. **Android SDK**: 开发任何Android应用的基础,包括Java或Kotlin编程语言,Android Studio...
总之,构建一个Android仿QQ聊天系统涵盖了Android基础组件的使用、数据库操作、网络编程、推送服务、用户体验设计等多个方面,对开发者的技术全面性和实践经验都有较高的要求。通过这个项目,开发者可以深入理解...
2. **客户端架构**:手机QQ的客户端部分可能包含多个模块,如登录注册、聊天界面、联系人管理、消息推送等。这些模块可能采用MVP(Model-View-Presenter)或MVVM(Model-View-ViewModel)设计模式实现,有助于代码的...
9. 手机远程监控:此应用可能实现远程摄像头监控,涉及网络编程,使用Socket通信,处理视频流,以及可能的推送通知服务。 10. 贪吃蛇游戏:贪吃蛇是经典的休闲游戏,开发时会用到SurfaceView或GLSurfaceView进行...
【标题】"仿微信android APP" 是一个专为Android平台设计的应用程序开发项目,旨在为初学者提供一个学习和实践的机会,让他们能够了解并掌握如何创建类似微信的用户界面。这个项目的重点在于实现微信的外观和基本...
本项目“android仿微信客户端”旨在为开发者提供一个可运行的、高度仿真的微信应用示例,帮助他们理解和掌握Android平台上类似应用的开发技术。 首先,我们要理解Android开发的基础。Android是由Google主导的开源...
综上所述,开发一个具备私聊和群聊功能的Android聊天应用,需要掌握多种技术,包括但不限于用户界面设计、数据库管理、网络通信、实时性处理、安全性策略、多线程编程、国际化、测试和版本控制。每一个环节都是确保...
这个压缩包文件“Android_EduChat_社区APP源码_一个社区聊天APP源码_android_安卓社区源码_AndroidIM通讯.zip”包含了Android EduChat社区应用程序的源代码,这是一个专为教育领域设计的社交聊天应用。通过分析这个...
本文将深入剖析一款名为“jchat4”的Android手机聊天程序的源码,帮助开发者理解和学习如何构建一个完整的聊天应用。 首先,我们要明白的是,一个聊天应用程序的核心功能包括用户注册与登录、消息发送与接收、群组...
在IT领域,局域网(LAN)WiFi Android聊天应用程序是一个常见的项目,它允许在同一网络下的Android设备之间进行即时通信。这个应用通常利用Wi-Fi连接,而不是依赖于互联网,因此可以在没有移动数据的情况下进行本地...
设计一个合理的消息模型对于聊天应用至关重要,包括消息类型(文本、图片、语音等)、发送状态(已发送、已读等)和时间戳等字段。数据库设计也需要考虑到高效查询和更新。 6. **数据库存储**: 使用SQLite数据库...
在Android平台上,构建一个仿微信聊天软件涉及到许多技术点,主要集中在网络通信方面,特别是使用Socket进行实时数据传输。本文将深入探讨如何利用Android的Socket编程来实现类似微信的聊天功能。 首先,我们需要...
3. **Android UI设计**:为了实现类似微信的聊天界面,开发者需要理解并使用Android的布局管理器,如LinearLayout、RelativeLayout、ConstraintLayout等,以及自定义View和Adapter来创建消息气泡、联系人列表等元素...
本文将深入探讨基于XMPP协议的Socket通信在Android上的实现,以及EntboostIM在其中的角色。 首先,我们需要理解XMPP(Extensible Messaging and Presence Protocol)协议。XMPP是一种基于XML的即时通讯协议,广泛...
【Android局域网聊天工具源码(类飞秋)】是一个专门为Android平台设计的应用程序,其功能类似于知名的局域网聊天软件“飞秋”。这款应用允许用户在同一个WiFi网络环境下进行实时通信,无需依赖互联网连接,非常适合...
4. Android推送服务:如Google的Firebase Cloud Messaging (FCM),用于实现实时消息推送,提高用户体验。 通过对这个仿QQ客户端及服务端源码的学习,开发者不仅能了解Android应用的基本架构,还能深入理解即时通讯...