android菜鸟学习笔记24----与服务器端交互(一)使用HttpURLConnection和HttpClient请求服务端数据
主要是基于HTTP协议与服务端进行交互。
涉及到的类和接口有:URL、HttpURLConnection、HttpClient等
URL:
使用一个String类型的url构造一个URL对象,如:
URL url = new URL(http://10.0.2.2/index.php);
openConnection()方法返回一个对指定url的资源的连接。返回类型是URLConnection,但是,由于这里我们一般用的是http协议,所以返回的实际是HttpURLConnection对象,故一般可以进行类型转换。
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
HttpURLConnection:
继承自URLConnection,常用方法有:
getInputStream()方法用来获取用来从网络连接中读取数据的输入流。
getOutputStream()方法用于获取用于向网络连接中写入数据的输出流。
setDoOutput()和setDoInput()方法分别用来设置是否允许向网络写入或读取数据。
setReadTimeout()方法用于设置读取数据超时时限。
setConnectTimeout()方法用于设置网络连接超时时限。
setRequestMethod()方法用于设置请求的方法,一般常用”GET”或”POST”。
getResponseCode()和getResponseMessage()方法分别用来获取服务端的响应码及响应信息字符串描述。
Disconnect()方法用于关闭网络连接。
1.使用HttpURLConnection与服务端进行交互:
布局文件代码:
<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" tools:context="cn.csc.start.MainActivity" > <EditText android:id="@+id/et_username" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/et_username_text"/> <EditText android:id="@+id/et_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="@string/et_password_text"/> <Button android:id="@+id/btn_login" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_text" /> </LinearLayout>
一个简单的php文件,模拟服务器端:
<?php if(isset($_REQUEST["username"])&& isset($_REQUEST["password"])){ $username = $_REQUEST["username"]; $password = $_REQUEST["password"]; if($username == "zhangsan" && $password == "123"){ echo "login success"; }else{ echo "login failure"; } }else{ echo "no field allowed empty string"; } ?>
客户端提交用户名密码,客户端返回登录的结果。
注意,在模拟器中用IP:10.0.2.2代表电脑的IP地址。
1.1使用GET方式与服务端进行交互:
public class MainActivity extends ActionBarActivity implements OnClickListener { protected static final int OK = 0; protected static final String TAG = "MYLOG"; private EditText et_username; private EditText et_password; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btn = (Button) findViewById(R.id.btn_login); btn.setOnClickListener(this); et_username = (EditText) findViewById(R.id.et_username); et_password = (EditText) findViewById(R.id.et_password); } @Override public void onClick(View view) { // TODO Auto-generated method stub if(view.getId() == R.id.btn_login){ get_test(); } } private void get_test() { // TODO Auto-generated method stub String username = et_username.getText().toString(); String password = et_password.getText().toString(); try { URL url = new URL("http://10.0.2.2/index.php?username="+username+"&password="+password); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); if(conn.getResponseCode() == 200){ InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String result = br.readLine(); Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show(); conn.disconnect(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
1.2使用POST方式与服务端进行交互:
添加一个post_test方法:
private void post_test(){ try { URL url = new URL("http://10.0.2.2/index.php"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); String username = et_username.getText().toString(); String password = et_password.getText().toString(); OutputStream os = conn.getOutputStream(); String req = "username="+username+"&password="+password; os.write(req.getBytes()); if(conn.getResponseCode()== 200){ InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String result = br.readLine(); Toast.makeText(this, result, Toast.LENGTH_LONG).show(); is.close(); os.close(); conn.disconnect(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
然后在onClick()中调用该方法。
注意到,这里由于只有一个线程,即在主线程(UI线程)中请求服务器,若有耗时操作,此时应用是不会响应用户操作的,这就是传说中的ANR异常。
所以,就必须新建一个子线程执行耗时操作。
修改get_test()方法,新建一个线程执行该方法中的操作:
private void get_test() { new Thread(new Runnable() { @Override public void run() { String username = et_username.getText().toString(); String password = et_password.getText().toString(); try { URL url = new URL("http://10.0.2.2/index.php?username="+username+"&password="+password); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); if(conn.getResponseCode() == 200){ InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String result = br.readLine(); Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show(); conn.disconnect(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); }
这时重新运行程序,会发现新的问题:
提示,无法在非UI线程中进行UI操作,因为这样不安全。
为了解决这个问题,android提供了一套消息处理机制,很像win32中的消息循环机制。
下面简单说明下这套机制:
引入消息机制后:
这套消息机制主要涉及到两个类:Handler和Message
Handler:
一般需要自定义Handler继承Handler类,并重写消息处理方法,一般将其对象在UI线程中定义,这样就可以在其消息处理方法中进行UI操作了。
常用方法:
消息处理回调函数,一般自定义的Handler类都要重写该方法,添加自己需要的消息处理业务逻辑。
sendMessage(Message msg)发送一条消息。
Message:
消息类,其对象作为消息实体被handler对象发送或者接收处理。
使用无参构造创建一个消息对象,一般在发送之前还需要设置其两个主要的属性:
what属性,可以用来存放消息的类型
obj属性,可以用来存放想要传送的消息内容或者传递的其他参数等。
修改上面的应用,添加消息处理机制:
在MainActivity中添加个Handler类型的私有属性:
private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { if(msg.what == OK){ String str = msg.obj.toString(); Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show(); } } };
重写的消息处理函数,很简单,就是把服务端返回的信息通过Toast显示出来。
添加一个方法,新建线程请求服务端数据,并通过消息机制发送消息:
private void multi_thread_test(){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { URL url = new URL("http://10.0.2.2/index.php"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); String username = et_username.getText().toString(); String password = et_password.getText().toString(); OutputStream os = conn.getOutputStream(); String req = "username="+username+"&password="+password; os.write(req.getBytes()); if(conn.getResponseCode()== 200){ InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String result = br.readLine(); Message msg = new Message(); msg.what = OK; msg.obj = result; handler.sendMessage(msg); is.close(); os.close(); conn.disconnect(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); }
这样,在请求服务端数据时,应用还能响应用户的交互。
2.还有另一种与服务端进行交互的方式,那就是使用HttpClient:
一般通过:
HttpClient client = new defaultHttpClient() 构造出HttpClient对象。
HttpClient类最主要的一个方法就是execute()方法。
常用的是只有一个参数的重载形式,注意到其参数类型是HttpUriRequest类型。
查看帮助手册:
HttpUriRequest是一个接口
已知的直接实现类,有那么多个,最常用的是HttpGet和HttpPost,从名字中便可知道,一个用于get方式与服务端交互,一个用于post方式与服务端交互。
HttpGet的使用比较简单
一般直接使用传入String类型的url构造出HttpGet对象,然后作为execute()的参数即可完成get方式请求。
HttpPost的使用要稍微麻烦一点,因为GET方式直接在URL中传入了请求参数,而POST方式需要另外一种传参方式。
POST方式的参数需要使用一个List<NameValuePair>类型的对象传递,
NameValuePair是一个接口,一般使用的是其直接实现类BasicNameValuPair类:
如:
List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("username", username)); params.add(new BasicNameValuePair("password", password));
要POST的参数存储完成,如何通过HttpPost提交呢?
注意到,帮助手册中关于HttpPost的信息:
HttpPost是通过继承HttpEntitiyEnclosingRequestBase类间接实现HttpUriRequest接口的。
该类中有一个方法:
可以通过setEntity()方法将参数传递给HttpPost对象,具体做法如下:
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,"utf-8"); httppost.setEntity(entity);
下面在MainActivity中添加方法,通过HttpClient方法与服务端进行交互:
private void client_get_test(){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub String username = et_username.getText().toString(); String password = et_password.getText().toString(); HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet("http://10.0.2.2/index.php?username="+username+"&password="+password); try { HttpResponse response = client.execute(get); if(response.getStatusLine().getStatusCode() == 200){ HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity, "utf-8"); Message msg = new Message(); msg.what = OK; msg.obj = result; handler.sendMessage(msg); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); }
使用HttpClient采用GET方式向服务端请求数据
private void client_post_test(){ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { String username = et_username.getText().toString(); String password = et_password.getText().toString(); HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost("http://10.0.2.2/index.php"); List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("username", username)); params.add(new BasicNameValuePair("password", password)); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,"utf-8"); post.setEntity(entity); HttpResponse response = client.execute(post); if(response.getStatusLine().getStatusCode() == 200){ HttpEntity entity1 = response.getEntity(); String result = EntityUtils.toString(entity1, "utf-8"); Message msg = new Message(); msg.what = OK; msg.obj = result; handler.sendMessage(msg); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); }
使用HttpClient采用POST方式向服务端请求数据。
以上就是向服务端请求数据的简单学习。
android菜鸟学习笔记24----与服务器端交互(一)使用HttpURLConnection和HttpClient请求服务端数据的更多相关文章
- android菜鸟学习笔记25----与服务器端交互(二)解析服务端返回的json数据及使用一个开源组件请求服务端数据
补充:关于PHP服务端可能出现的问题: 如果你刚好也像我一样,用php实现的服务端程序,采用的是apache服务器,那么虚拟主机的配置可能会影响到android应用的调试!! 在android应用中访 ...
- android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人
要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上 ...
- android菜鸟学习笔记28----Android中的Service生命周期及本地和远程服务绑定的实现
Service是Android中长期在后台运行的没有界面的组件,使用服务的优势在于:能够提高进程的优先级,系统不容易回收掉进程,即便回收了,内存充足的时候,会把进程重新创建. 1.服务的简单使用示例: ...
- android菜鸟学习笔记21----ContentProvider(一)ContentProvider的简单使用
ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用.只有当需要在多个应用之间共享数据时才会用到ContentPro ...
- android菜鸟学习笔记20----Android数据存储(四))Android数据库操作
Android内置了一个名为SQLite的关系型数据库,这是一款轻量型的数据库,操作十分简便.SQLite与别的数据库不同的是,它没有数据类型.可以保存任何类型的数据到你所想要保存的任何表的任何列中. ...
- android菜鸟学习笔记30----Android使用百度地图API(一)准备工作及在应用中显示地图
1.准备工作: 百度地图API是免费开放的,但是需要申请API Key: 1)先注册一个百度开发者帐号 2)进入百度开放服务平台http://developer.baidu.com/ 3)进入LBS云 ...
- android菜鸟学习笔记29----Android应用向用户发送提示信息的方式总结
常见的向用户发送提示信息的方式有3种,分别为: 1)发送Toast信息 2)弹出对话框 3)发送通知 总结如下: 方式1:发送Toast信息: 这种方式最简单,在之前的学习中多次使用过.Toast是在 ...
- android菜鸟学习笔记27----Fragment的简单使用
1.Fragment的生命周期: 简单在新建一个MyFragment继承自Fragment,重写各个生命周期回调方法,各个方法中直接输出标识相关函数被调用的信息. 重写MainActivity的各个生 ...
- android菜鸟学习笔记22----ContentProvider(二)ContentObserver的简单使用
现在有这样一个应用A通过ContentProvider提供自己的数据给其他应用,应用B通过ContentResolver获取应用A中提供的数据,并将其展示在ListView中,而应用C通过Conten ...
随机推荐
- asp.net使用母版页以及Jquery和prototype要注意的问题
在母版页中引用了js,css或者其他外部文件之后,子页面就不必再重新引用,否则可能出错 prototype.js和jquery.js冲突的解决方案: <script type="tex ...
- 我与小娜(36):人机大战第五局,AlphaGo必胜!
我与小娜(36):人机大战第五局,AlphaGo必胜! 小娜知道,细致阅读论文"Mastering the game of Go with deep neural network ...
- Activity和Service交互之bindService(回调更新UI)
一.回调接口 public interface OnProgressListener { void onProgress(int progress); } 二.Service代码 public cla ...
- PIVOT 和 UPIVOT 的使用(行转列)
PIVOT 通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列值执行聚合.UNPIVOT 与 PIVOT 执行相反的操作,将表值表达式的列转换为列 ...
- 【原创】Loadrunner使用json格式请求数据并参数化
(2015-04-10 16:10:41) 转载▼ 标签: loadrunner json 参数化 web_custom_request 分类: 性能测试 请求自定义的http文件用函数:web_cu ...
- shell脚本检测网络是否畅通
shell初始化安装脚本执行时,需从网络上安装一些rpm包,所有需要先检测网络的畅通性, 代码 #检测网络链接&&ftp上传数据 function networkAndFtp() { ...
- requests ssl 报错
使用requests下载日志出现HTTPSConnectionPool(host='***', port=443): Max retries exceeded with url: ******(Cau ...
- Maximum sum-动态规划
A - Maximum sum Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Sub ...
- 在jfinal的Controller中接受json数据
JFinal中接收URL中的参数或者model中的参数是很方便的,但是对于web2.0的网站来说,经常会以json方式提交比较复杂的数据,比如一个查询,包含了各种过滤条件和排序分页,前端脚本可能提交的 ...
- 查看cup是32位还是64位
1#echo $HOSTTYPE 2#uname -a 3#getconf LONG_BIT