一、排坑
static Handler handler;Handler内存泄漏
Handler要解决的根本问题是Android线程并发,如果没有相应的机制约束各线程的协作并发,很容易导致开发上和运行上的混乱。Android处理多线程的方式也不是传统上的加锁机制(性能因素吧),而是MessageQueue,即消息队列,开发者可以直接控制消息队列的显示顺序和方式,这样就不会产生数据的同步混乱的问题了。
1. 内存泄露原因分析
由于这个Handler作为内部类声明在Activity内部,普通的内部类对象隐式地保存了一个指向外部类对象的引用,所以这个Handler对象保存了一个指向Activity对象的引用。而这个Handler对象的生命周期可能比Activity生命周期长,比如当有一个后台线程持有该Handler,别且该线程在执行一个长时间任务。所以当该Handler没有被JVM垃圾回收器回收时,它就阻止了它引用的外部类Activity对象的回收,这里就导致了内存泄露。
2. 如何解决这种内存泄露问题
在该内存泄露的Lint Warning中给出了解决该问题的方法。将Handler类声明为静态内部类,即解除内部类对象与其外部类对象之间的联系。创建一个外部类的WeakReference,并在实例化Handler对象时使用它。代码实现如下:
private static class MyHandler extends Handler {
private WeakReference<MainActivity> activityWeakReference;
public MyHandler(MainActivity activity) {
activityWeakReference = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity = activityWeakReference.get();
if (activity != null) {
}
}
}
- handler造成内存泄漏是因为在Activity销毁的时候还有未执行完的任务
- 静态static可以解决内存泄漏
- 使用弱引用也可以解决内存泄漏,但是需要等到handler的中任务都执行完,才会释放activity内存,不如直接static释放的快
- handler造成内存泄漏有 两种方案:一种是业务逻辑上,在activity销毁的时候移除所有未执行的任务。一种是从GC上,通过static的Handler或者弱引用解决。但是单独的使用弱引用性能不是太高。
static MainActivity ma;
static变量所指向内存的引用,如果不把它设置为null ,GC是不会回收这个对象的,
所以为了让GC能够回收static变量 我们在使用完后将static变量设置为null
4种引用
SoftReference、WeakReference和PhantomReference
SoftReference、WeakReference和PhantomReference是java.lang.ref类库中的一组类。当垃圾回收器正在考察的对象只能通过某个Reference对象才“可获得”时,这3个类为垃圾回收器提供了不同级别的间接性提示。
对象是可获得的(reachable),是指此对象可在程序中的某处找到。这意味着你在栈中有一个普通的“引用A”,而它正指向此“对象A”,也可能是“引用B”指向“对象B”,而“对象B”含有“引用C”指向“对象A”,也可能是更多的中间链接。如果一个对象是“可获得的”,垃圾回收器就不能释放它,因为它仍然为你的程序所用。如果一个对象不是“可获得的”,那么你的程序将无法使用到它,所以将其回收是安全的。
如果想继续持有某个对象的引用,想以后还能够访问到该对象,同时也想在内存消耗殆尽的时候垃圾回收器回收它,这时就应该使用Reference对象。
SoftReference、WeakReference和PhantomReference由强到弱排列,表示不同级别的“可获得性”。
SoftReference用以实现内存敏感的高速缓存。
WeakReference是为实现“规范映射”(canonicalizing mappings)而设计的,它不妨碍垃圾回收器回收映射的“键”(或“值”)。“规范映射”中对象的实例可以在程序的多处被同时使用,以节省存储空间。
PhantomReference用以调度回收前的清理工作,它比Java终止机制更加灵活。
variable xxx is accessed from within inner class; needs to be declared final
在内部类当中不能引用本地变量,需要被声明为常量
Server Tomcat v7.0 Server at localhost failed to start
可以选择删除web.xml中的映射,也可以选择将servlet自动生成的注解注释掉,这样就不会有冲突了,二者选其一留下即可。
get方式中文乱码
在Get方式请求中request.setCharacterEncoding("UTF-8")不再起作用
String name = request.getParameter("name");
name = new String(name.getBytes("ISO-8859-1"),"UTF-8");
二、网络图片查看器
主线程不能被阻塞
- 在Android中,主线程被阻塞会导致应用不能刷新ui界面,不能响应用户操作,用户体验将非常差
- 主线程阻塞时间过长,系统会抛出ANR异常
- ANR:Application Not Response;应用无响应
- 任何耗时操作都不可以写在主线程
- 因为网络交互属于耗时操作,如果网速很慢,代码会阻塞,所以网络交互的代码不能运行在主线程
只有主线程能刷新ui
- 刷新ui的代码只能运行在主线程,运行在子线程是没有任何效果的
- 如果需要在子线程中刷新ui,使用消息队列机制
消息队列
- Looper一旦发现Message Queue中有消息,就会把消息取出,然后把消息扔给Handler对象,Handler会调用自己的handleMessage方法来处理这条消息
- handleMessage方法运行在主线程
- 主线程创建时,消息队列和轮询器对象就会被创建,但是消息处理器对象,需要使用时,自行创建
public class MainActivity extends Activity {
static ImageView iv;
static MainActivity ma;
static Handler handler = new Handler(){
//此方法在主线程中调用,可以用来刷新ui
public void handleMessage(Message msg) {
//处理消息时,需要知道到底是成功的消息,还是失败的消息
switch (msg.what) {
case 1:
//把位图对象显示至imageview
iv.setImageBitmap((Bitmap)msg.obj);
break;
case 0:
Toast.makeText(ma, "请求失败", Toast.LENGTH_SHORT).show();
break;
}
ma=null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView) findViewById(R.id.iv);
ma = this;
}
public void click(View v){
getpic("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1551414968179&di=2896146dee79c07b8a5ea400d35cd9ff&imgtype=0&src=http%3A%2F%2Fa.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F5243fbf2b211931330751d8b6b380cd791238dd3.jpg");
}
public void click2(View v){
getpic("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1551425560734&di=81f2206ede868b4ceb7d33a47f6f68f2&imgtype=0&src=http%3A%2F%2Fd.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2Fe7cd7b899e510fb3a4c06fa8d733c895d1430c37.jpg");
}
public void getpic(String path){
final String path1=path;
Thread t = new Thread(){
@Override
public void run() {
//下载图片
//1.确定网址
//String path = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1551414968179&di=2896146dee79c07b8a5ea400d35cd9ff&imgtype=0&src=http%3A%2F%2Fa.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F5243fbf2b211931330751d8b6b380cd791238dd3.jpg";
try {
//2.把网址封装成一个url对象
URL url = new URL(path1);
//3.获取客户端和服务器的连接对象,此时还没有建立连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//4.对连接对象进行初始化
//设置请求方法,注意大写
conn.setRequestMethod("GET");
//设置连接超时
conn.setConnectTimeout(5000);
//设置读取超时
conn.setReadTimeout(5000);
//5.发送请求,与服务器建立连接
conn.connect();
//如果响应码为200,说明请求成功
if(conn.getResponseCode() == 200){
//获取服务器响应头中的流,流里的数据就是客户端请求的数据
InputStream is = conn.getInputStream();
//读取出流里的数据,并构造成位图对象
Bitmap bm = BitmapFactory.decodeStream(is);
// ImageView iv = (ImageView) findViewById(R.id.iv);
// //把位图对象显示至imageview
// iv.setImageBitmap(bm);
Message msg = new Message();
//消息对象可以携带数据
msg.obj = bm;
msg.what = 1;
//把消息发送至主线程的消息队列
handler.sendMessage(msg);
}
else{
// Toast.makeText(MainActivity.this, "请求失败", 0).show();
Message msg = handler.obtainMessage();
msg.what = 0;
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
}
加入缓存图片的功能
public void getpic2(String path){
//下载图片
//1.确定网址
final String path1=path;
final File file = new File(getCacheDir(), getFileName(path));
//判断,缓存中是否存在该文件
if(file.exists()){
//如果缓存存在,从缓存读取图片
Log.e(TAG, "从缓存读取的: ");
Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
iv.setImageBitmap(bm);
}
else{
//如果缓存不存在,从网络下载
Log.e(TAG, "从网上下载的: ");
Thread t = new Thread(){
@Override
public void run() {
try {
//2.把网址封装成一个url对象
URL url = new URL(path1);
//3.获取客户端和服务器的连接对象,此时还没有建立连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//4.对连接对象进行初始化
//设置请求方法,注意大写
conn.setRequestMethod("GET");
//设置连接超时
conn.setConnectTimeout(5000);
//设置读取超时
conn.setReadTimeout(5000);
//5.发送请求,与服务器建立连接
conn.connect();
//如果响应码为200,说明请求成功
if(conn.getResponseCode() == 200){
//获取服务器响应头中的流,流里的数据就是客户端请求的数据
InputStream is = conn.getInputStream();
//读取服务器返回的流里的数据,把数据写到本地文件,缓存起来
FileOutputStream fos = new FileOutputStream(file);
byte[] b = new byte[1024];
int len = 0;
while((len = is.read(b)) != -1){
fos.write(b, 0, len);
}
fos.close();
//读取出流里的数据,并构造成位图对象
//流里已经没有数据了
// Bitmap bm = BitmapFactory.decodeStream(is);
Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
Message msg = new Message();
//消息对象可以携带数据
msg.obj = bm;
msg.what = 1;
//把消息发送至主线程的消息队列
handler.sendMessage(msg);
}
else{
// Toast.makeText(MainActivity.this, "请求失败", 0).show();
Message msg = handler.obtainMessage();
msg.what = 0;
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
}
public String getFileName(String path){
int index = path.lastIndexOf("/");
return path.substring(index + 1);
}
三、SmartImageView
源码:https://github.com/loopj/android-smart-image-view
开源项目SmartImageView的出现主要是为了加速从网络上加载图片,它继承自ImageView类,支持根据URL地址加载图片,支持异步加载图片,支持图片缓存等。
<RelativeLayout 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"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载图片"
android:onClick="click"
/>
<com.loopj.android.image.SmartImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View v){
//下载图片
//1.确定网址
String path = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1551414968179&di=2896146dee79c07b8a5ea400d35cd9ff&imgtype=0&src=http%3A%2F%2Fa.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F5243fbf2b211931330751d8b6b380cd791238dd3.jpg";
//2.找到智能图片查看器对象
SmartImageView siv = (SmartImageView) findViewById(R.id.iv);
//3.下载并显示图片
siv.setImageUrl(path);
}
}
四、Html源文件查看器
public class MainActivity extends Activity {
Handler handler = new Handler(){
public void handleMessage(Message msg) {
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText((String)msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View v){
Thread t = new Thread(){
@Override
public void run() {
String path = "";
try {
URL url = new URL(path);
//获取连接对象,此时还未建立连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//先建立连接,然后获取响应码
if(conn.getResponseCode() == 200){
//拿到服务器返回的输入流,流里的数据就是html的源文件
InputStream is = conn.getInputStream();
//从流里把文本数据取出来
String text = Utils.getTextFromStream(is);
//发送消息,让主线程刷新ui,显示源文件
Message msg = handler.obtainMessage();
msg.obj = text;
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
}
public class Utils {
public static String getTextFromStream(InputStream is){
byte[] b = new byte[1024];
int len = 0;
//创建字节数组输出流,读取输入流的文本数据时,同步把数据写入数组输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while((len = is.read(b)) != -1){
bos.write(b, 0, len);
}
//把字节数组输出流里的数据转换成字节数组
String text = new String(bos.toByteArray());
return text;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
五、小志新闻客户端
上传文件提供下载链接
public class MainActivity extends Activity {
List<News> newsList;
Handler handler = new Handler(){
public void handleMessage(Message msg) {
ListView lv = (ListView) findViewById(R.id.lv);
lv.setAdapter(new MyAdapter());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getNewsInfo();
// ListView lv = (ListView) findViewById(R.id.lv);
// //要保证在设置适配器时,新闻xml文件已经解析完毕了
// lv.setAdapter(new MyAdapter());
}
class MyAdapter extends BaseAdapter{
//得到模型层中元素的数量,用来确定listview需要有多少个条目
@Override
public int getCount() {
// TODO Auto-generated method stub
return newsList.size();
}
@Override
//返回一个View对象,作为listview的条目显示至界面
public View getView(int position, View convertView, ViewGroup parent) {
News news = newsList.get(position);
View v = null;
ViewHolder mHolder;
if(convertView == null){
v = View.inflate(MainActivity.this, R.layout.item_listview, null);
mHolder = new ViewHolder();
//把布局文件中所有组件的对象封装至ViewHolder对象中
mHolder.tv_title = (TextView) v.findViewById(R.id.tv_title);
mHolder.tv_detail = (TextView) v.findViewById(R.id.tv_detail);
mHolder.tv_comment = (TextView) v.findViewById(R.id.tv_comment);
mHolder.siv = (SmartImageView) v.findViewById(R.id.iv);
//把ViewHolder对象封装至View对象中
v.setTag(mHolder);
}
else{
v = convertView;
mHolder = (ViewHolder) v.getTag();
}
//给三个文本框设置内容
mHolder.tv_title.setText(news.getTitle());
mHolder.tv_detail.setText(news.getDetail());
mHolder.tv_comment.setText(news.getComment() + "条评论");
//给新闻图片imageview设置内容
mHolder.siv.setImageUrl(news.getImageUrl());
return v;
}
class ViewHolder{
//条目的布局文件中有什么组件,这里就定义什么属性
TextView tv_title;
TextView tv_detail;
TextView tv_comment;
SmartImageView siv;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
}
private void getNewsInfo() {
Thread t = new Thread(){
@Override
public void run() {
String path = "";
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//发送http GET请求,获取相应码
if(conn.getResponseCode() == 200){
InputStream is = conn.getInputStream();
//使用pull解析器,解析这个流
parseNewsXml(is);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
private void parseNewsXml(InputStream is) {
XmlPullParser xp = Xml.newPullParser();
try {
xp.setInput(is, "utf-8");
//对节点的事件类型进行判断,就可以知道当前节点是什么节点
int type = xp.getEventType();
News news = null;
while(type != XmlPullParser.END_DOCUMENT){
switch (type) {
case XmlPullParser.START_TAG:
if("newslist".equals(xp.getName())){
newsList = new ArrayList<News>();
}
else if("news".equals(xp.getName())){
news = new News();
}
else if("title".equals(xp.getName())){
String title = xp.nextText();
news.setTitle(title);
}
else if("detail".equals(xp.getName())){
String detail = xp.nextText();
news.setDetail(detail);
}
else if("comment".equals(xp.getName())){
String comment = xp.nextText();
news.setComment(comment);
}
else if("image".equals(xp.getName())){
String image = xp.nextText();
news.setImageUrl(image);
}
break;
case XmlPullParser.END_TAG:
if("news".equals(xp.getName())){
newsList.add(news);
}
break;
}
//解析完当前节点后,把指针移动至下一个节点,并返回它的事件类型
type = xp.next();
}
//发消息,让主线程设置listview的适配器,如果消息不需要携带数据,可以发送空消息
handler.sendEmptyMessage(1);
// for (News n : newsList) {
// System.out.println(n.toString());
// }
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class News {
private String title;
private String detail;
private String comment;
private String imageUrl;
@Override
public String toString() {
return "News [title=" + title + ", detail=" + detail + ", comment="
+ comment + ", imageUrl=" + imageUrl + "]";
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.loopj.android.image.SmartImageView
android:id="@+id/iv"
android:layout_width="90dp"
android:layout_height="70dp"
android:src="@drawable/ic_launcher_background"
android:layout_centerVertical="true"
/>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是大标题志哥教你上塑料adasfsadfdsfdsgsd"
android:layout_toRightOf="@id/iv"
android:textSize="22sp"
android:singleLine="true"
/>
<TextView
android:id="@+id/tv_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是正文志哥教你带崩三路adasfsadasdasdasdasidhsakjhdkjashdkjahskjdhsakjdfdsfdsgsd"
android:layout_toRightOf="@id/iv"
android:layout_below="@id/tv_title"
android:textSize="15sp"
android:textColor="@android:color/darker_gray"
android:lines="2"
/>
<TextView
android:id="@+id/tv_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="65031条评论"
android:textColor="#ff0000"
android:layout_alignParentRight="true"
android:layout_below="@id/tv_detail"
/>
</RelativeLayout>
六、提交数据
本地网站服务器准备工作
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request,response);
//response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
String username = request.getParameter("username");
String username1 =new String(username.getBytes("ISO-8859-1"),"UTF-8");
String password = request.getParameter("password");
PrintWriter out = response.getWriter();
out.println("<p>"+username1+"</p>");
out.println("<p>"+password+"</p>");
if(username.equals("admin")&&password.equals("123456")){
out.println("<p>登录成功!"+"</p>");
}
else{
out.println("<p>用户名或密码错误!"+"</p>");
}
out.flush();
out.close();
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<form action="/d0301/LoginServlet" method="post">
<p>用户名:<input name="username" type="text"><p>
<p>密 码:<input name="password" type="password"></p>
<p><input type="submit" value="提交"/> <input type="reset" value="重置"></p>
</form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name></display-name>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>hmk.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
可用电脑上的安卓模拟器调试
GET方式提交数据
浏览器在发送请求携带数据时会对数据进行URL编码,我们写代码时也需要为中文进行URL编码
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
Handler handler = new Handler(){
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, (String)msg.obj, Toast.LENGTH_SHORT).show();
}
};
public void click(View v){
EditText et_name = (EditText) findViewById(R.id.et_name);
EditText et_pass = (EditText) findViewById(R.id.et_pass);
final String name = et_name.getText().toString();
final String pass = et_pass.getText().toString();
Thread t = new Thread(){
@Override
public void run() {
//提交的数据需要经过url编码,英文和数字编码后不变
@SuppressWarnings("deprecation")
String path = "http://10.32.189.73:8080/d0301/LoginServlet?username=" + URLEncoder.encode(name) + "&password=" + pass;
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
if(conn.getResponseCode() == 200){
InputStream is =conn.getInputStream();
String text = Utils.getTextFromStream(is);
Message msg = handler.obtainMessage();
msg.obj = text;
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
}
POST方式提交数据
- post提交数据是用流写给服务器的
- 协议头中多了两个属性
- Content-Type: application/x-www-form-urlencoded,描述提交的数据的mimetype
- Content-Length: 32,描述提交的数据的长度
public void click2(View v){
EditText et_name = (EditText) findViewById(R.id.et_name);
EditText et_pass = (EditText) findViewById(R.id.et_pass);
final String name = et_name.getText().toString();
final String pass = et_pass.getText().toString();
Thread t = new Thread(){
@Override
public void run() {
//提交的数据需要经过url编码,英文和数字编码后不变
@SuppressWarnings("deprecation")
String path = "http://10.32.189.73:8080/d0301/LoginServlet";
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//拼接出要提交的数据的字符串
String data = "username=" + URLEncoder.encode(name) + "&password=" + pass;
//添加post请求的两行属性
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", data.length() + "");
//设置打开输出流
conn.setDoOutput(true);
//拿到输出流
OutputStream os = conn.getOutputStream();
//使用输出流往服务器提交数据
os.write(data.getBytes());
if(conn.getResponseCode() == 200){
InputStream is = conn.getInputStream();
String text = Utils.getTextFromStream(is);
Message msg = handler.obtainMessage();
msg.obj = text;
handler.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
}