当前位置: 编程技术>移动开发
本页文章导读:
▪TextView url辨别,Spannable的使用 TextView url识别,Spannable的使用
首先看一个链接文本执行流程的大概示意图看了这个流程应该对大概URL, Email等的链接实现有所了解了,所以直接看代码把
TextView view1 = (TextView) findViewById( R.id.vi.........
▪ 数据储存之四ContentProvider 数据存储之四ContentProvider
早上我们简要的对SQLite进行回顾,然后将SQLite的事务管理和SQLiteDataBase提供的Insert、Update、Delete、Query方法进行了简单的讲解。 今日的重点内容是ContentPr.........
▪ 数据储存之五网络数据交互 数据存储之五网络数据交互
昨天我们只对Android接收网络数据进行了简单介绍,今天我们完成了Android数据存储网络部分的所有内容。在此我将对这非常重要的内容进行总结。 本.........
[1]TextView url辨别,Spannable的使用
来源: 互联网 发布时间: 2014-02-18
TextView url识别,Spannable的使用
首先看一个链接文本执行流程的大概示意图
看了这个流程应该对大概URL, Email等的链接实现有所了解了,所以直接看代码把
XML布局文件
默认的链接在点击时,只会跳转到响应的View,如点击URL时,打开浏览器,点击电话号码时,打开拨号界面。 如果我们要在点击某连接时,跳转到某个Activity呢。
URLSpan继承自ClickableSpan,所以我们的出发点也是这个类,然后重写其中的onClick
使用的话和URLSpan差不多
首先看一个链接文本执行流程的大概示意图
看了这个流程应该对大概URL, Email等的链接实现有所了解了,所以直接看代码把
TextView view1 = (TextView) findViewById( R.id.view1 ); TextView view2 = (TextView) findViewById( R.id.view2 ); TextView view3 = (TextView) findViewById( R.id.view3 ); TextView view4 = (TextView) findViewById( R.id.view4 ); TextView view5 = (TextView) findViewById( R.id.view5 ); TextView view6 = (TextView) findViewById( R.id.view6 ); SpannableString text1 = new SpannableString("red"); text1.setSpan(new ForegroundColorSpan(Color.RED), 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); view1.setText( text1 ); SpannableString text2 = new SpannableString("green"); text2.setSpan(new BackgroundColorSpan(Color.GREEN), 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); view2.setText( text2 ); SpannableString text3 = new SpannableString("i am bold"); text3.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 5, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); view3.setText( text3 ); SpannableString text4 = new SpannableString("underline"); text4.setSpan(new UnderlineSpan(), 0, 9, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); view4.setText( text4 ); SpannableString text5 = new SpannableString("delete line"); text5.setSpan(new StrikethroughSpan(), 7, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); view5.setText( text5 ); SpannableString text6 = new SpannableString("make a call"); text6.setSpan(new URLSpan("tel:123456789"), 7, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); view6.setText( text6 ); view6.setMovementMethod(LinkMovementMethod.getInstance()); // 还有ImageSpan等
XML布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/view1" android:layout_width="wrap_content" android:layout_height="50sp" android:gravity="center" /> <TextView android:id="@+id/view2" android:layout_width="wrap_content" android:layout_height="50sp" android:gravity="center" /> <TextView android:id="@+id/view3" android:layout_width="wrap_content" android:layout_height="50sp" android:gravity="center" /> <TextView android:id="@+id/view4" android:layout_width="wrap_content" android:layout_height="50sp" android:gravity="center" /> <TextView android:id="@+id/view5" android:layout_width="wrap_content" android:layout_height="50sp" android:gravity="center" /> <TextView android:id="@+id/view6" android:layout_width="wrap_content" android:layout_height="50sp" android:gravity="center" /> </LinearLayout>
默认的链接在点击时,只会跳转到响应的View,如点击URL时,打开浏览器,点击电话号码时,打开拨号界面。 如果我们要在点击某连接时,跳转到某个Activity呢。
URLSpan继承自ClickableSpan,所以我们的出发点也是这个类,然后重写其中的onClick
public class IntentSpan extends ClickableSpan implements ParcelableSpan { private Intent mIntent; public IntentSpan(Intent toActivity) { mIntent = toActivity; } @Override public void onClick(View sourceView) { Context context = sourceView.getContext(); context.startActivity( mIntent ); } @Override public int getSpanTypeId() { return 100; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flag) { // don't write to parcel } public Intent getIntent() { return mIntent; } }
使用的话和URLSpan差不多
SpannableString text6 = new SpannableString("make a call"); Intent intent = new Intent(context, SomActivity.class); text6.setSpan(new IntentSpan(intent), 7, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); view6.setText( text6 ); view6.setMovementMethod(LinkMovementMethod.getInstance());
1 楼
lenomon
2012-04-07
实现可点击文本。 android TextView 点击链接 无下划线
[2] 数据储存之四ContentProvider
来源: 互联网 发布时间: 2014-02-18
数据存储之四ContentProvider
早上我们简要的对SQLite进行回顾,然后将SQLite的事务管理和SQLiteDataBase提供的Insert、Update、Delete、Query方法进行了简单的讲解。
今日的重点内容是ContentProvider(内容提供者)和网络存储,我将对这两大内容进行总结。关于SQLiteDataBase提供的便捷方法,它们会在ContentProvider被使用。SQLite的事务管理比较简单,昨天有简要介绍,今日就不做总结了。
ContentProvider和网络存储将分为两篇日志,本篇总结ContentProvider。
一、ContentProvider简介
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
二、Uri类简介
Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。
2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
· 要操作contact表中id为10的记录,可以构建这样的路径:/contact/10
· 要操作contact表中id为10的记录的name字段, contact/10/name
· 要操作contact表中的所有记录,可以构建这样的路径:/contact
要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
要操作xml文件中contact节点下的name节点,可以构建这样的路径:/contact/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
三、UriMatcher、ContentUrist和ContentResolver简介
因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher:用于匹配Uri,它的用法如下:
1.首先把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回匹配码为1
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符
2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回的匹配码为1。
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
· withAppendedId(uri, id)用于为路径加上ID部分
· parseId(uri)方法用于从路径中获取ID部分
ContentResolver:当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,来操作数据。
四、ContentProvider示例程序
我们为昨天的SQLite示例程序添加一个ContentProvider,供其他应用来访问我们的数据。
1.为SQLite示例程序添加ContentProvider类
package com.changcheng.sqlite.provider;
import com.changcheng.sqlite.MyOpenHelper;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
public class ContactContentProvider extends ContentProvider {
// 通过UriMatcher匹配外部请求
private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 通过openHelper进行数据库读写
private MyOpenHelper openHelper;
// 匹配状态常量
private static final int CONTACT_LIST = 1;
private static final int CONTACT = 2;
// 表名
private static final String tableName = "contacts";
// 添加Uri
static {
uriMatcher.addURI("com.changcheng.sqlite.provider", "contact",
CONTACT_LIST);
uriMatcher.addURI("com.changcheng.sqlite.provider", "contact/#",
CONTACT);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
int result;
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
result = db.delete(tableName, selection, selectionArgs);
break;
case CONTACT:
long id = ContentUris.parseId(uri);
String where = "_id=" + id;
if (selection != null && !"".equals(selection)) {
where = where + " and " + selection;
}
result = db.delete(tableName, where, selectionArgs);
break;
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
return result;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:// 集合类型必须在前面加上vnd.android.cursor.dir/
return "vnd.android.cursor.dir/contactlist";
case CONTACT:// 非集合类型必须在前面加上vnd.android.cursor.item/
return "vnd.android.cursor.item/contact";
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
long id;
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
// 因为后台需要生成SQL语句,当values为null时,必须提第二个参数。生成的SQL语句才不会出错!
id = db.insert(tableName, "_id", values);
return ContentUris.withAppendedId(uri, id);
case CONTACT:
id = db.insert(tableName, "_id", values);
String uriPath = uri.toString();
String path = uriPath.substring(0, uriPath.lastIndexOf("/")) + id;
return Uri.parse(path);
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
}
@Override
public boolean onCreate() {
this.openHelper = new MyOpenHelper(this.getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
return db.query(tableName, projection, selection, selectionArgs,
null, null, sortOrder);
case CONTACT:
long id = ContentUris.parseId(uri);
String where = "_id=" + id;
if (selection != null && !"".equals(selection)) {
where = where + " and " + selection;
}
return db.query(tableName, projection, where, selectionArgs, null,
null, sortOrder);
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
int result;
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
result = db.update(selection, values, selection, selectionArgs);
break;
case CONTACT:
long id = ContentUris.parseId(uri);
String where = "_id=" + id;
if (selection != null && !"".equals(selection)) {
where = where + " and " + selection;
}
result = db.update(tableName, values, where, selectionArgs);
break;
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
return result;
}
}
2.添加ContentProvider配置
<provider android:name=".provider.ContactContentProvider" android:authorities="com.changcheng.sqlite.provider.contactprovider"/>
3.测试SQLite示例程序的ContentProvider
ContentProvider即然是提供给其他应用访问本应用数据的,所以我们需要另创建一个Android应用,来测试SQLite示例程序的ContentProvider。我在此只列出query的测试方法testQuery:
public void testQuery() throws Throwable {
ContentResolver contentResolver = this.getContext()
.getContentResolver();
Uri uri = Uri
.parse("content://com.changcheng.sqlite.provider/contact");
Cursor cursor = contentResolver.query(uri, new String[] { "_id",
"name", "phone" }, null, null, "_id desc");
while (cursor.moveToNext()) {
Log.i(TAG, "_id=" + cursor.getInt(0) + ",name="
+ cursor.getString(1) + ",phone=" + cursor.getString(2));
}
}
早上我们简要的对SQLite进行回顾,然后将SQLite的事务管理和SQLiteDataBase提供的Insert、Update、Delete、Query方法进行了简单的讲解。
今日的重点内容是ContentProvider(内容提供者)和网络存储,我将对这两大内容进行总结。关于SQLiteDataBase提供的便捷方法,它们会在ContentProvider被使用。SQLite的事务管理比较简单,昨天有简要介绍,今日就不做总结了。
ContentProvider和网络存储将分为两篇日志,本篇总结ContentProvider。
一、ContentProvider简介
当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。
二、Uri类简介
Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider ,2.对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
1.scheme:ContentProvider(内容提供者)的scheme已经由Android所规定为:content://。
2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
· 要操作contact表中id为10的记录,可以构建这样的路径:/contact/10
· 要操作contact表中id为10的记录的name字段, contact/10/name
· 要操作contact表中的所有记录,可以构建这样的路径:/contact
要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
要操作xml文件中contact节点下的name节点,可以构建这样的路径:/contact/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
三、UriMatcher、ContentUrist和ContentResolver简介
因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher:用于匹配Uri,它的用法如下:
1.首先把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回匹配码为1
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2
uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符
2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回的匹配码为1。
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
· withAppendedId(uri, id)用于为路径加上ID部分
· parseId(uri)方法用于从路径中获取ID部分
ContentResolver:当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,来操作数据。
四、ContentProvider示例程序
我们为昨天的SQLite示例程序添加一个ContentProvider,供其他应用来访问我们的数据。
1.为SQLite示例程序添加ContentProvider类
package com.changcheng.sqlite.provider;
import com.changcheng.sqlite.MyOpenHelper;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
public class ContactContentProvider extends ContentProvider {
// 通过UriMatcher匹配外部请求
private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 通过openHelper进行数据库读写
private MyOpenHelper openHelper;
// 匹配状态常量
private static final int CONTACT_LIST = 1;
private static final int CONTACT = 2;
// 表名
private static final String tableName = "contacts";
// 添加Uri
static {
uriMatcher.addURI("com.changcheng.sqlite.provider", "contact",
CONTACT_LIST);
uriMatcher.addURI("com.changcheng.sqlite.provider", "contact/#",
CONTACT);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
int result;
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
result = db.delete(tableName, selection, selectionArgs);
break;
case CONTACT:
long id = ContentUris.parseId(uri);
String where = "_id=" + id;
if (selection != null && !"".equals(selection)) {
where = where + " and " + selection;
}
result = db.delete(tableName, where, selectionArgs);
break;
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
return result;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:// 集合类型必须在前面加上vnd.android.cursor.dir/
return "vnd.android.cursor.dir/contactlist";
case CONTACT:// 非集合类型必须在前面加上vnd.android.cursor.item/
return "vnd.android.cursor.item/contact";
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
long id;
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
// 因为后台需要生成SQL语句,当values为null时,必须提第二个参数。生成的SQL语句才不会出错!
id = db.insert(tableName, "_id", values);
return ContentUris.withAppendedId(uri, id);
case CONTACT:
id = db.insert(tableName, "_id", values);
String uriPath = uri.toString();
String path = uriPath.substring(0, uriPath.lastIndexOf("/")) + id;
return Uri.parse(path);
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
}
@Override
public boolean onCreate() {
this.openHelper = new MyOpenHelper(this.getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
return db.query(tableName, projection, selection, selectionArgs,
null, null, sortOrder);
case CONTACT:
long id = ContentUris.parseId(uri);
String where = "_id=" + id;
if (selection != null && !"".equals(selection)) {
where = where + " and " + selection;
}
return db.query(tableName, projection, where, selectionArgs, null,
null, sortOrder);
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = this.openHelper.getWritableDatabase();
int result;
switch (uriMatcher.match(uri)) {
case CONTACT_LIST:
result = db.update(selection, values, selection, selectionArgs);
break;
case CONTACT:
long id = ContentUris.parseId(uri);
String where = "_id=" + id;
if (selection != null && !"".equals(selection)) {
where = where + " and " + selection;
}
result = db.update(tableName, values, where, selectionArgs);
break;
default:
throw new IllegalArgumentException("Uri IllegalArgument:" + uri);
}
return result;
}
}
2.添加ContentProvider配置
<provider android:name=".provider.ContactContentProvider" android:authorities="com.changcheng.sqlite.provider.contactprovider"/>
3.测试SQLite示例程序的ContentProvider
ContentProvider即然是提供给其他应用访问本应用数据的,所以我们需要另创建一个Android应用,来测试SQLite示例程序的ContentProvider。我在此只列出query的测试方法testQuery:
public void testQuery() throws Throwable {
ContentResolver contentResolver = this.getContext()
.getContentResolver();
Uri uri = Uri
.parse("content://com.changcheng.sqlite.provider/contact");
Cursor cursor = contentResolver.query(uri, new String[] { "_id",
"name", "phone" }, null, null, "_id desc");
while (cursor.moveToNext()) {
Log.i(TAG, "_id=" + cursor.getInt(0) + ",name="
+ cursor.getString(1) + ",phone=" + cursor.getString(2));
}
}
[3] 数据储存之五网络数据交互
来源: 互联网 发布时间: 2014-02-18
数据存储之五网络数据交互
昨天我们只对Android接收网络数据进行了简单介绍,今天我们完成了Android数据存储网络部分的所有内容。在此我将对这非常重要的内容进行总结。
本篇日志是对Android与WEB应用服务之间进行数据交互的总结,下篇日志是一个经典而又让人十分好奇的Android多线程断点下载应用的总结。下面我们开始Android与网络数据的交互。
一、创建WEB应用服务
使用eclipse3.5创建一个动态WEB应用,使用Struts1处理用户请求。我们此应用添加一个DispatchAction,并为它添加四个方法创建用于处理Android以各种方式提交的请求。
1.创建动态WEB工程
Project name:AndroidWebServer
Target runtime:Apache Tomcat v6.0
Dynamic web module version:2.5
Configuration:Default Configuration for Apache Tomcat v6.0
2.添加DispatchAction
package com.changcheng.web.struts.actions;
import java.io.File;
import java.io.FileOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import com.changcheng.web.struts.forms.DataForm;
public class AndroidWebServer extends DispatchAction {
// Andoird以Get方式发送的请求
public ActionForward sendDataByGet(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String name = request.getParameter("name");
request.setAttribute("message", "Hello " + name);
return mapping.findForward("success");
}
// Andoird以Post方式发送的请求
public ActionForward sendDataByPost(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String name = request.getParameter("name");
request.setAttribute("message", "Hello " + name);
return mapping.findForward("success");
}
// Andoird以表单方式发送的请求
public ActionForward sendDataByForm(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
DataForm formbean = (DataForm) form;
System.out.println("StrData:" + formbean.getStrData());
// 获取上传的文件
if (formbean.getFileData() != null
&& formbean.getFileData().getFileSize() > 0) {
// 设置保存目录
File dir = new File(request.getSession().getServletContext()
.getRealPath("/images"));
if (!dir.exists())
dir.mkdirs();
// 保存文件
FileOutputStream outStream = new FileOutputStream(new File(dir,
formbean.getFileData().getFileName()));
outStream.write(formbean.getFileData().getFileData());// 保存文件
outStream.close();
}
return null;
}
}
3.向web.xml添加Struts1的ActionServlet
<servlet>
<servlet-name>struts</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>struts</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
4.struts-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans>
<form-bean name="dataForm" type="com.changcheng.web.struts.forms.DataForm" />
</form-beans>
<action-mappings>
<action path="/server"
type="com.changcheng.web.struts.actions.AndroidWebServer" name="dataForm"
scope="request" parameter="method">
<forward name="success" path="/WEB-INF/pages/success.jsp"/>
</action>
</action-mappings>
</struts-config>
二、创建Android应用
1.创建Android工程
Project name:AndroidWebClient
BuildTarget:Android2.1
Application name:AndroidWEB应用客户端
Package name:com.changcheng.web.client
Create Activity:AndroidWebClient
Min SDK Version:7
2.AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.changcheng.web.client" android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<!-- 单元测试 -->
<uses-library android:name="android.test.runner" />
<activity android:name=".AndroidWebClient" 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>
<uses-sdk android:minSdkVersion="7" />
<!-- 访问internet权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 单元测试 -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.changcheng.web.client" android:label="Tests for My App" />
</manifest>
Android应用要访问Internet需要添加权限。
3.ClientService类
package com.changcheng.web.client.service;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import android.os.Environment;
import android.util.Log;
public class ClientService {
private static final String TAG = "ClientService";
// 以get方式发送请求
public static void sendDataToServerByGet() throws Exception {
// 主机地址不可以设置为localhost或127.0.0.1,必须是本机或其他机器所在Internet网或局域网地址。
String path = "http://192.168.0.2:8080/AndroidWebServer/server.do?"
+ "method=sendDataByGet&name=changcheng";
URL url = new URL(/blog_article/path/index.html);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6 * 1000);
// 请求成功
if (conn.getResponseCode() == 200) {
// 获取服务器返回的数据
byte[] data = readStream(conn.getInputStream());
Log.i(TAG, new String(data, "UTF-8"));
}
}
// 以Post方式发送请求,面向HTTP协议编程
public static void sendDataTOserverByPost() throws Exception {
String path = "http://192.168.0.2:8080/AndroidWebServer/server.do";
String params = "method=sendDataByPost&name=tingting";// 请求参数
byte[] data = params.getBytes();
URL url = new URL(/blog_article/path/index.html);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6 * 1000);
conn.setDoOutput(true);// 发送POST请求必须设置允许输出
conn.setUseCaches(false);// 不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
DataOutputStream outStream = new DataOutputStream(conn
.getOutputStream());
outStream.write(data);// 以内容实体方式发送请求参数
outStream.flush();
outStream.close();
// 请求成功
if (conn.getResponseCode() == 200) {
// 获取服务器返回的数据
byte[] html = readStream(conn.getInputStream());
Log.i(TAG, new String(html, "UTF-8"));
}
}
// 以表单方式发送请求
public static void sendDataToServerByForm() throws Exception {
Map<String, String> params = new HashMap<String, String>();
params.put("method", "sendDataByForm");
params.put("strData", "字符串数据");
// 获取SDCard中的good.jpg
File file = new File(Environment.getExternalStorageDirectory(),
"app_Goog_Android_w.png");
FormFile fileData = new FormFile("app_Goog_Android_w.png", new FileInputStream(file),
"fileData", "application/octet-stream");
HttpRequester.post(
"http://192.168.0.2:8080/AndroidWebServer/server.do", params,
fileData);
}
// 获取输入流数据
private static byte[] readStream(InputStream inStream) throws Exception {
byte[] buffer = new byte[1024];
int len = -1;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
byte[] data = outStream.toByteArray();
outStream.close();
inStream.close();
return data;
}
}
其中使用到的FormFile类:
package com.changcheng.web.client.service;
import java.io.InputStream;
/**
* 上传文件
*/
public class FormFile {
/* 上传文件的数据 */
private byte[] data;
private InputStream inStream;
/* 文件名称 */
private String filname;
/* 表单字段名称*/
private String formname;
/* 内容类型 */
private String contentType = "application/octet-stream";
public FormFile(String filname, byte[] data, String formname, String contentType) {
this.data = data;
this.filname = filname;
this.formname = formname;
if(contentType!=null) this.contentType = contentType;
}
public FormFile(String filname, InputStream inStream, String formname, String contentType) {
this.filname = filname;
this.formname = formname;
this.inStream = inStream;
if(contentType!=null) this.contentType = contentType;
}
public InputStream getInStream() {
return inStream;
}
public void setInStream(InputStream inStream) {
this.inStream = inStream;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public String getFilname() {
return filname;
}
public void setFilname(String filname) {
this.filname = filname;
}
public String getFormname() {
return formname;
}
public void setFormname(String formname) {
this.formname = formname;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}
其中使用到的HttpRequester类:
package com.changcheng.web.client.service;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import android.util.Log;
/**
* http请求发送器
*/
public class HttpRequester {
/**
* 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能:
* <FORM METHOD=POST ACTION="http://192.168.0.200:8080/ssi/fileload/test.do" enctype="multipart/form-data">
<INPUT TYPE="text" NAME="name">
<INPUT TYPE="text" NAME="id">
<input type="file" name="imagefile"/>
<input type="file" name="zip"/>
</FORM>
* @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
* @param file 上传文件
*/
public static String post(String actionUrl, Map<String, String> params, FormFile[] files) {
try {
String BOUNDARY = "---------7d 4a6d158c9"; //数据分隔线
String MULTIPART_FORM_DATA = "multipart/form-data";
URL url = new URL(/blog_article/actionUrl/index.html);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6* 1000);
conn.setDoInput(true);//允许输入
conn.setDoOutput(true);//允许输出
conn.setUseCaches(false);//不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {//构建表单字段内容
sb.append("--");
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data; name=\""+ entry.getKey() + "\"\r\n\r\n");
sb.append(entry.getValue());
sb.append("\r\n");
}
DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
outStream.write(sb.toString().getBytes());//发送表单字段数据
for(FormFile file : files){//发送文件数据
StringBuilder split = new StringBuilder();
split.append("--");
split.append(BOUNDARY);
split.append("\r\n");
split.append("Content-Disposition: form-data;name=\""+ file.getFormname()+"\";filename=\""+ file.getFilname() + "\"\r\n");
split.append("Content-Type: "+ file.getContentType()+"\r\n\r\n");
outStream.write(split.toString().getBytes());
if(file.getInStream()!=null){
byte[] buffer = new byte[1024];
int len = 0;
while((len = file.getInStream().read(buffer))!=-1){
outStream.write(buffer, 0, len);
}
file.getInStream().close();
}else{
outStream.write(file.getData(), 0, file.getData().length);
}
outStream.write("\r\n".getBytes());
}
byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();//数据结束标志
outStream.write(end_data);
outStream.flush();
int cah = conn.getResponseCode();
if (cah != 200) throw new RuntimeException("请求url失败");
InputStream is = conn.getInputStream();
int ch;
StringBuilder b = new StringBuilder();
while( (ch = is.read()) != -1 ){
b.append((char)ch);
}
Log.i("ItcastHttpPost", b.toString());
outStream.close();
conn.disconnect();
return b.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 提交数据到服务器
* @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
* @param file 上传文件
*/
public static String post(String actionUrl, Map<String, String> params, FormFile file) {
return post(actionUrl, params, new FormFile[]{file});
}
/**
* 提交数据到服务器
* @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
*/
public static String post(String actionUrl, Map<String, String> params) {
HttpPost httpPost = new HttpPost(actionUrl);
List<NameValuePair> list = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : params.entrySet()) {//构建表单字段内容
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
try {
httpPost.setEntity(new UrlEncodedFormEntity(list, HTTP.UTF_8));
HttpResponse httpResponse = new DefaultHttpClient().execute(httpPost);
if(httpResponse.getStatusLine().getStatusCode() == 200){
return EntityUtils.toString(httpResponse.getEntity());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
}
我们最好对HTTP协议有深入的了解,这样在编写简单数据交互应用时直接面向HTTP协议编程可以提高运行速度并减少资源的占用。
我们在最后一个方法中使用到的HttpPost类,是Apache开源组织提供的httpcomponents-client-4.0.1包。httpcomponents-client-4.0.1可以实现浏览器的大部分功能,但如果我们能不使用它就尽量不使用它,因为这会造成对手机硬件资源的占用,从而减慢应用程序的运行速度。
4.测试类
package com.changcheng.web.client.test;
import com.changcheng.web.client.service.ClientService;
import android.test.AndroidTestCase;
public class TestAndroidClientService extends AndroidTestCase {
public void testSendDataToServerByGet() throws Throwable {
ClientService.sendDataToServerByGet();
}
public void testSendDataToServerByPost() throws Throwable {
ClientService.sendDataTOserverByPost();
}
public void testSendDataToServerByForm() throws Throwable {
ClientService.sendDataToServerByForm();
}
}
5.运行
首先启动AndroidWebService应用程序,然后运行测试方法,查看运行结果。
昨天我们只对Android接收网络数据进行了简单介绍,今天我们完成了Android数据存储网络部分的所有内容。在此我将对这非常重要的内容进行总结。
本篇日志是对Android与WEB应用服务之间进行数据交互的总结,下篇日志是一个经典而又让人十分好奇的Android多线程断点下载应用的总结。下面我们开始Android与网络数据的交互。
一、创建WEB应用服务
使用eclipse3.5创建一个动态WEB应用,使用Struts1处理用户请求。我们此应用添加一个DispatchAction,并为它添加四个方法创建用于处理Android以各种方式提交的请求。
1.创建动态WEB工程
Project name:AndroidWebServer
Target runtime:Apache Tomcat v6.0
Dynamic web module version:2.5
Configuration:Default Configuration for Apache Tomcat v6.0
2.添加DispatchAction
package com.changcheng.web.struts.actions;
import java.io.File;
import java.io.FileOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import com.changcheng.web.struts.forms.DataForm;
public class AndroidWebServer extends DispatchAction {
// Andoird以Get方式发送的请求
public ActionForward sendDataByGet(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String name = request.getParameter("name");
request.setAttribute("message", "Hello " + name);
return mapping.findForward("success");
}
// Andoird以Post方式发送的请求
public ActionForward sendDataByPost(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String name = request.getParameter("name");
request.setAttribute("message", "Hello " + name);
return mapping.findForward("success");
}
// Andoird以表单方式发送的请求
public ActionForward sendDataByForm(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
DataForm formbean = (DataForm) form;
System.out.println("StrData:" + formbean.getStrData());
// 获取上传的文件
if (formbean.getFileData() != null
&& formbean.getFileData().getFileSize() > 0) {
// 设置保存目录
File dir = new File(request.getSession().getServletContext()
.getRealPath("/images"));
if (!dir.exists())
dir.mkdirs();
// 保存文件
FileOutputStream outStream = new FileOutputStream(new File(dir,
formbean.getFileData().getFileName()));
outStream.write(formbean.getFileData().getFileData());// 保存文件
outStream.close();
}
return null;
}
}
3.向web.xml添加Struts1的ActionServlet
<servlet>
<servlet-name>struts</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>struts</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
4.struts-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans>
<form-bean name="dataForm" type="com.changcheng.web.struts.forms.DataForm" />
</form-beans>
<action-mappings>
<action path="/server"
type="com.changcheng.web.struts.actions.AndroidWebServer" name="dataForm"
scope="request" parameter="method">
<forward name="success" path="/WEB-INF/pages/success.jsp"/>
</action>
</action-mappings>
</struts-config>
二、创建Android应用
1.创建Android工程
Project name:AndroidWebClient
BuildTarget:Android2.1
Application name:AndroidWEB应用客户端
Package name:com.changcheng.web.client
Create Activity:AndroidWebClient
Min SDK Version:7
2.AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.changcheng.web.client" android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<!-- 单元测试 -->
<uses-library android:name="android.test.runner" />
<activity android:name=".AndroidWebClient" 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>
<uses-sdk android:minSdkVersion="7" />
<!-- 访问internet权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 单元测试 -->
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.changcheng.web.client" android:label="Tests for My App" />
</manifest>
Android应用要访问Internet需要添加权限。
3.ClientService类
package com.changcheng.web.client.service;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import android.os.Environment;
import android.util.Log;
public class ClientService {
private static final String TAG = "ClientService";
// 以get方式发送请求
public static void sendDataToServerByGet() throws Exception {
// 主机地址不可以设置为localhost或127.0.0.1,必须是本机或其他机器所在Internet网或局域网地址。
String path = "http://192.168.0.2:8080/AndroidWebServer/server.do?"
+ "method=sendDataByGet&name=changcheng";
URL url = new URL(/blog_article/path/index.html);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6 * 1000);
// 请求成功
if (conn.getResponseCode() == 200) {
// 获取服务器返回的数据
byte[] data = readStream(conn.getInputStream());
Log.i(TAG, new String(data, "UTF-8"));
}
}
// 以Post方式发送请求,面向HTTP协议编程
public static void sendDataTOserverByPost() throws Exception {
String path = "http://192.168.0.2:8080/AndroidWebServer/server.do";
String params = "method=sendDataByPost&name=tingting";// 请求参数
byte[] data = params.getBytes();
URL url = new URL(/blog_article/path/index.html);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6 * 1000);
conn.setDoOutput(true);// 发送POST请求必须设置允许输出
conn.setUseCaches(false);// 不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
DataOutputStream outStream = new DataOutputStream(conn
.getOutputStream());
outStream.write(data);// 以内容实体方式发送请求参数
outStream.flush();
outStream.close();
// 请求成功
if (conn.getResponseCode() == 200) {
// 获取服务器返回的数据
byte[] html = readStream(conn.getInputStream());
Log.i(TAG, new String(html, "UTF-8"));
}
}
// 以表单方式发送请求
public static void sendDataToServerByForm() throws Exception {
Map<String, String> params = new HashMap<String, String>();
params.put("method", "sendDataByForm");
params.put("strData", "字符串数据");
// 获取SDCard中的good.jpg
File file = new File(Environment.getExternalStorageDirectory(),
"app_Goog_Android_w.png");
FormFile fileData = new FormFile("app_Goog_Android_w.png", new FileInputStream(file),
"fileData", "application/octet-stream");
HttpRequester.post(
"http://192.168.0.2:8080/AndroidWebServer/server.do", params,
fileData);
}
// 获取输入流数据
private static byte[] readStream(InputStream inStream) throws Exception {
byte[] buffer = new byte[1024];
int len = -1;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
byte[] data = outStream.toByteArray();
outStream.close();
inStream.close();
return data;
}
}
其中使用到的FormFile类:
package com.changcheng.web.client.service;
import java.io.InputStream;
/**
* 上传文件
*/
public class FormFile {
/* 上传文件的数据 */
private byte[] data;
private InputStream inStream;
/* 文件名称 */
private String filname;
/* 表单字段名称*/
private String formname;
/* 内容类型 */
private String contentType = "application/octet-stream";
public FormFile(String filname, byte[] data, String formname, String contentType) {
this.data = data;
this.filname = filname;
this.formname = formname;
if(contentType!=null) this.contentType = contentType;
}
public FormFile(String filname, InputStream inStream, String formname, String contentType) {
this.filname = filname;
this.formname = formname;
this.inStream = inStream;
if(contentType!=null) this.contentType = contentType;
}
public InputStream getInStream() {
return inStream;
}
public void setInStream(InputStream inStream) {
this.inStream = inStream;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public String getFilname() {
return filname;
}
public void setFilname(String filname) {
this.filname = filname;
}
public String getFormname() {
return formname;
}
public void setFormname(String formname) {
this.formname = formname;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}
其中使用到的HttpRequester类:
package com.changcheng.web.client.service;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import android.util.Log;
/**
* http请求发送器
*/
public class HttpRequester {
/**
* 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能:
* <FORM METHOD=POST ACTION="http://192.168.0.200:8080/ssi/fileload/test.do" enctype="multipart/form-data">
<INPUT TYPE="text" NAME="name">
<INPUT TYPE="text" NAME="id">
<input type="file" name="imagefile"/>
<input type="file" name="zip"/>
</FORM>
* @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
* @param file 上传文件
*/
public static String post(String actionUrl, Map<String, String> params, FormFile[] files) {
try {
String BOUNDARY = "---------7d 4a6d158c9"; //数据分隔线
String MULTIPART_FORM_DATA = "multipart/form-data";
URL url = new URL(/blog_article/actionUrl/index.html);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6* 1000);
conn.setDoInput(true);//允许输入
conn.setDoOutput(true);//允许输出
conn.setUseCaches(false);//不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {//构建表单字段内容
sb.append("--");
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data; name=\""+ entry.getKey() + "\"\r\n\r\n");
sb.append(entry.getValue());
sb.append("\r\n");
}
DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
outStream.write(sb.toString().getBytes());//发送表单字段数据
for(FormFile file : files){//发送文件数据
StringBuilder split = new StringBuilder();
split.append("--");
split.append(BOUNDARY);
split.append("\r\n");
split.append("Content-Disposition: form-data;name=\""+ file.getFormname()+"\";filename=\""+ file.getFilname() + "\"\r\n");
split.append("Content-Type: "+ file.getContentType()+"\r\n\r\n");
outStream.write(split.toString().getBytes());
if(file.getInStream()!=null){
byte[] buffer = new byte[1024];
int len = 0;
while((len = file.getInStream().read(buffer))!=-1){
outStream.write(buffer, 0, len);
}
file.getInStream().close();
}else{
outStream.write(file.getData(), 0, file.getData().length);
}
outStream.write("\r\n".getBytes());
}
byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();//数据结束标志
outStream.write(end_data);
outStream.flush();
int cah = conn.getResponseCode();
if (cah != 200) throw new RuntimeException("请求url失败");
InputStream is = conn.getInputStream();
int ch;
StringBuilder b = new StringBuilder();
while( (ch = is.read()) != -1 ){
b.append((char)ch);
}
Log.i("ItcastHttpPost", b.toString());
outStream.close();
conn.disconnect();
return b.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 提交数据到服务器
* @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
* @param file 上传文件
*/
public static String post(String actionUrl, Map<String, String> params, FormFile file) {
return post(actionUrl, params, new FormFile[]{file});
}
/**
* 提交数据到服务器
* @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
* @param params 请求参数 key为参数名,value为参数值
*/
public static String post(String actionUrl, Map<String, String> params) {
HttpPost httpPost = new HttpPost(actionUrl);
List<NameValuePair> list = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : params.entrySet()) {//构建表单字段内容
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
try {
httpPost.setEntity(new UrlEncodedFormEntity(list, HTTP.UTF_8));
HttpResponse httpResponse = new DefaultHttpClient().execute(httpPost);
if(httpResponse.getStatusLine().getStatusCode() == 200){
return EntityUtils.toString(httpResponse.getEntity());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
}
我们最好对HTTP协议有深入的了解,这样在编写简单数据交互应用时直接面向HTTP协议编程可以提高运行速度并减少资源的占用。
我们在最后一个方法中使用到的HttpPost类,是Apache开源组织提供的httpcomponents-client-4.0.1包。httpcomponents-client-4.0.1可以实现浏览器的大部分功能,但如果我们能不使用它就尽量不使用它,因为这会造成对手机硬件资源的占用,从而减慢应用程序的运行速度。
4.测试类
package com.changcheng.web.client.test;
import com.changcheng.web.client.service.ClientService;
import android.test.AndroidTestCase;
public class TestAndroidClientService extends AndroidTestCase {
public void testSendDataToServerByGet() throws Throwable {
ClientService.sendDataToServerByGet();
}
public void testSendDataToServerByPost() throws Throwable {
ClientService.sendDataTOserverByPost();
}
public void testSendDataToServerByForm() throws Throwable {
ClientService.sendDataToServerByForm();
}
}
5.运行
首先启动AndroidWebService应用程序,然后运行测试方法,查看运行结果。
最新技术文章: