Android系统只能是简单的客户端,原因
1 . 计算能力有限(CPU、内存空间都很难提升)
2 . 数据存储空间有限。
最可能出现的软件架构:
Android客户端 + 服务器
Android只需要通过网络与服务器交互,所有数据的计算、存储都放在服务器上
Android的网络支持:
1、支持Java原来的提供的基于TCP协议的网络通信、
也支持基于UDP协议的网络通信。
2、还支持使用HttpURLConnection然后基于HTTP协议进行网络通信。
3、也支持基于蓝牙的网络通信。
4、集成了HttpClient开源框架,主要也是基于HTTP协议进行网络通信。
5、通过ksoap-android项目,还可以支持Web Service。
一,基于TCP协议的网络通信
1. 编写服务器端。
(1)建立ServerSocket
(2)使用ServerSocket的accept接受来自于客户端的连接。
(3)一旦建立连接,服务器端会获得与客户端通信的Socket。
通过Socket就可以获得IO流,剩下的事情就是IO操作。
2. 编写客户端。
(1)通过Socket建立与服务器的连接。
(2)一旦建立连接,客户端会获得与服务器端通信的Socket。
通过Socket就可以获得IO流,剩下的事情就是IO操作。
代码:
服务端:
public class Server
{
public static void main(String[] args)
throws Exception
{
ServerSocket ss = new ServerSocket(30000);//在服务器的30000端口监听,这是方便内网沟通,其实在外网都是有一个固定的端口号
// 接受一次客户端的连接
Socket socket = ss.accept();
// 获取服务器端的输入流
BufferedReader br = new BufferedReader(new InputStreamReader(
socket.getInputStream() , "utf-8"));//安卓支持的中文字符:utf-8
String line = null;
while((line = br.readLine()) != null)//读取信息
{
System.out.println("line:" + line);
}
}
}
客户端核心代码:
public class TcpClientActivity extends Activity
{
Socket socket;
EditText etInput , etShow;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etInput = (EditText) findViewById(R.id.input);
etShow = (EditText) findViewById(R.id.show);
try
{ //本地的IP地址,可在命令行中输入ipconfig /all得到本机的IP,或者直接用10.0.2.2(不推荐)
socket = new Socket("192.168.1.102" , 30000); }
catch (Exception e)
{
e.printStackTrace();
}
}
public void send(View source)throws Exception
{
// 得到Socket的输出流,发送到服务端
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.print(etInput.getText().toString() + "\r\n");
}
}
这只是一个简单的客户端与服务端的通信,进一步可以深化为他们之间的互动,抑或是通过多线程与多个客户端同时保持通信,更进一步可以在服务端设置与数据库的联接,形成一个即时聊天工具.
此节是简要介绍安卓网络通信,不便深入,欲知更多详情,可关注笔者的更多博客文章.
二, 使用HttpURLConnection进行网络通信
主要是可以进行基于HTTP协议的通信
其实它是java的一个类,安卓只是进行了简单的改进
使用HttpURLConnection编程的步骤是:
(1) 创建URL对象
(2) 调用URL对象的openConnection打开HttpURLConnection
(3) 调用HttpURLConnection的方法设置一些常用的请求属性。
(4) 调用HttpURLConnection的connect()建立与服务器连接。
(5) 调用HttpURLConnection的getInputStream得到IO流,
剩下的就是IO操作了。
闲话少说,看一个实例先:
public class HttpTestActivity extends Activity
{
HttpURLConnection conn;
TextView tvShow;
URL url;
Handler handler = new Handler()//用来刷新主线程,一般写在onCreate的外面
{
public void handleMessage(Message msg)
{
if(msg.what == 0x123)
{
tvShow.setText(msg.getData().getString("line")//显示从网络返回的内容,用append方法可以通过追加的方式显示
+ "\n");
}
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvShow = (TextView) findViewById(R.id.show);
// 设置我们要访问的网络地址
try
{//这是一笔者在本地建立的一个java web项目的地址,读者可以自行写一个网址,效果不同而已
url = new URL("http://10.43.8.188:8888/abc/xyz.jsp");
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void getRes(View source)
{//新建一个线程不宜把网络编程放到主线程中(其实Android4.1以上已经禁止联网放入到主线程),因为连网一般都比较费时,简单点的就像这样整一个匿名线程
new Thread()
{
public void run()
{
try
{
conn = (HttpURLConnection) url.openConnection();
// // 设置发送GET请求
conn.setRequestMethod("GET");
conn.setRequestProperty("connection", "Keep-Alive");
// 设置下面这些请求属性,是为了模拟IE 8的浏览器,网上可以找到一个模拟登录人人网的过程与这有些相似
conn.setRequestProperty("accept" , "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
+ "application/x-shockwa-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, "
+ "application/mord, */*");
conn.setRequestProperty("user-agent" ,"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; "
+ "Trident/4.0; .NCLR 2.0.50727");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("accept-language", "zh-cn");
conn.connect();
System.out.println("--------------");
// 说明服务器响应是正常的。
BufferedReader br = new BufferedReader(//流入的IO,"GBK"是相关网址使用的字符编码
new InputStreamReader(conn.getInputStream() , "GBK"));
System.out.println("=====" + br);
String line = null;
StringBuilder sb = new StringBuilder();
// 把服务器的响应都收集到StringBuilder中
while((line = br.readLine()) != null)
{
sb.append(line + "\n");
}
Message msg = new Message();//发送信息刷新主线程
msg.what = 0x123;
Bundle data = new Bundle();
data.putString("line" , sb.toString());
msg.setData(data);
handler.sendMessage(msg);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}.start();//一定要记得启动
}
}
其实如果说仅仅是想得到一个网址的显示内容没有这么复杂,想要像浏览器一样显示网页可以用Android支持的webkit内核,
然后用webview显示出来,如果仅仅是要得到某个网站的html文字内容的话通过如下方法:
URL url = new URL("网址");
HttpURLConnection huc = (HttpURLConnection) url.openConnection;
huc.setRequestMethod("GET");//通常都是GET
InputStream is = huc.getInputStream;//得到输入流,然后做相应的操作,通过这种方法可以得到网页的整个html,然后进行筛选,获得我们要想的信息
实际从网络上下载一个图片或从一个下载链接下载一个文件的思想跟这个极为相似
三, HttpClient
其实是一个Apache的开源项目,Android默认已经集成了这个开源项目。
主要是可以进行基于HTTP协议的通信。
如果服务器端资源需要进行“登录之后”才能访问,
此时就需要进行Session管理。
对于浏览器来讲,当它第一次访问某站点时,站点会为之分配jsessionid等。
浏览器要去接受这些数据。
只要浏览器不关闭,浏览器下次发送请求时,
还应该将这些数据以请求头的再次发送到服务器端,
以便服务器能准确地识别这个浏览器。
借助于HttpClient,可以更好地管理Session等状态。
从名字上来看,HttpClient就是一个简单“浏览器”,它的作用:
A。 能模拟浏览器发送请求,Get、POST都行。
B。 能模拟浏览器读取服务器响应。
HttpClient不能:
A。 它不能呈现数据。
B。 它也不能解释、执行JavaScript脚本。
HttpClient的编程步骤:
(1)创建HttpClient。
(2)如果要发送GET请求,就创建HttpGet对象;
如果要发送POST请求,就创建HttpPost对象;
(3)如果要发送请求参数,可以调用setParams方法设置请求参数。
对于POST请求,一般通过setEntity()方法来设置请求参数。
(4)调用HttpClient的execute()发送请求。
该方法需要HttpUriRequest对象(HttpGet、HttpPost都是)。
(5)获取服务器响应。
发送GET请求
1. 准备HttpGet对象。
2. 使用HttpClient的execute()发送请求,得到HttpResponse对象。
发送POST请求
1. 准备HttpPost对象。通过HttpPost设置请求参数。
2. 使用HttpClient的execute()发送请求,得到HttpResponse对象。
public class HttpClientTestActivity extends Activity
{
HttpClient httpClient;
TextView tvShow;
LayoutInflater inflater;
EditText etName , etPass;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tvShow = (TextView) findViewById(R.id.show);
httpClient = new DefaultHttpClient();
inflater = LayoutInflater.from(this);
}
public void getAccount(View source) throws ClientProtocolException, IOException
{
// 代表我们要发送的Get请求,发送请求到服务器的jsp,然后jsp通过控制器(servlet)对数据库等进行操作,并返回结果
HttpGet get = new HttpGet("http://10.43.8.188:8888/abc/secrit.jsp");
HttpResponse response = httpClient.execute(get);
// 使用tvShow组件显示结果。
showResult(response);
}
public void showLogin(View source)
{
final View loginView = inflater.inflate(R.layout.login, null);
openDialog(loginView
, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
// 代表我们要发送的Post请求(向处理登录请求的Servlet发送请求)
HttpPost post = new HttpPost("http://10.43.8.188:8888/abc/login");
// 得到用户输入的两个组件
etName = (EditText)loginView.findViewById(R.id.name);
etPass = (EditText)loginView.findViewById(R.id.pass);
//NameValuePair可以想像成post中的HashMap,一对键值对
List<NameValuePair> params = new ArrayList<NameValuePair>();
// name代表了请求参数的名字
params.add(new BasicNameValuePair("username"//登录要用到的用户名
, etName.getText().toString()));
params.add(new BasicNameValuePair("password"//登录密码
, etPass.getText().toString()));
try
{
//设置请求参数
post.setEntity(new UrlEncodedFormEntity(params , "utf-8"));
HttpResponse response = httpClient.execute(post);//执行请求
// 使用tvShow组件显示结果。
showResult(response);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}, null);
}
private void openDialog(View view ,
DialogInterface.OnClickListener positiveListener,
DialogInterface.OnClickListener negativeListener)
{
new AlertDialog.Builder(this)
.setTitle("登录系统")
.setView(view)
.setPositiveButton("确定", positiveListener)
.setNegativeButton("取消", negativeListener)
.create()
.show();
}
// 这是一个工具方法,它会负责把HttpResponse里的数据显示tvShow组件中
private void showResult(HttpResponse response)
throws UnsupportedEncodingException, IllegalStateException, IOException
{
HttpEntity entity = response.getEntity();
BufferedReader br = new BufferedReader(new
InputStreamReader(entity.getContent(), "gbk"));
StringBuilder sb = new StringBuilder();
String line = null;
while((line = br.readLine()) != null)
{
sb.append(line + "\n");
}
tvShow.setText(sb);
}
}
Android网络编程的内容大致就这些,本文章相关源代码下载:
本文章内容涉及到的源代码:
http://download.csdn.net/detail/zxjzzg/5169947
Android简易聊天室源代码(基本实现了聊天室的功能,包括好友列表,信息列表,Android相关数据库,Socket编程以及java端sqlite数据库的使用):