2024年6月12日发(作者:)
………
PROGRAM LANGUAG E -“……~…………~ … ……………………… … ………… ……………
apIdres/android“
andrO d:OrientatiOn="vertical'。
android:layout
_
width=”ifll
一_
parent。'。android
Iayout height= fil Iparent”>
<ListView android:id= @id/android:list”
android:layout
width=。'fill
_
一.
parent。。android
PJayout height=”filI parent”'
andrOid:fastScrOllEnabled=”true“andrOid:fOcusable=“'true“
android:padding=“8px“/>
<TextView android:id=“@id/android:empty“android
text=“无数据“
android:Iayout
width
=
"lil
}
parent android
layout height= fill
—
parent”/>
</LinearLayout>
主界面的选项菜单定义如代码2所示
代码2分享信息平台移动客户端主界面选项菜单定义
文件名:menu/clps.一menu.xml
<menu xmlns:android=“http://schemas.android.com/apk/res/
android“>
<item android:id=“@+ld/'mi
—
refresh”android:icon=”
@drawable ̄/refresh‘’
android:title=”最新分享“,>
<item android:icon=“@!drawable/add”android:id=”@+id/
mi
—
create。 。
android:title--“发起分享“/>
<item android:id=“@+id/m__nearby"android:icon=”
@drawable,/nearby'。
android:title=”附近分享。l/>
<item android:id=”@+id/mi—my“android:icon=“
@drawable/my“
android:title= 我的分享”/>
<item android:id=”@+idlm__setting'。android:icon=
@drawable/setting'‘
android:title=”系统设置“,>
<item android:id=”@+id/m__exit'’android:icon=“
@drawable/exit。 。
android:title=”退出系统“/>
</menu>
3.1.2分享发布界面
分享发布界面如图2(右)所示,其界面主要内容包含3
部分:类型选择器、主题输入框、图片选择按钮、地理位置信
息栏、发布按钮、图片预览区。限于篇幅,分享发布界面的布
局定义请参考附带代码。
3.1.3分享列表界面
无论是我的分享界面还是附近分享界面,其主要内容还是
分享列表.所以其界面布局与主界面的分享列表相同,在此不
再赘述。
3.2数据接口定义
在本案例中,数据内容不仅包括文本还包括图片;不仅需
要获取数据,而且还需要上传数据。不仅如此,应用程序还需
要调用外部接El来获取手机的经纬度坐标。所以文中的移动应
用所涉及的接13包括数据获取和发布接口、图片下载以及地理
位置查询接口
3.2.1数据获取接口(dataset.WS)
数据获取接13是手机移动客户端获取服务端分享信息的接
口,其通过H 兀P协议,以JSON格式(JSON数组)作为数据
交换格式。其输人数据项定义如下:
{ds—id:<数据集标识>,pl:<参数1>【Jp2:<参数2>._】】
其输出数据项定义参见数据库设计中【分享信息表】。
3_2_2数据发布接口(ins.WS)
数据发布接口是手机移动客户端向服务端上传分享信息的
接口,其也通过H1TrP协议,按照HTITP实体的格式,将文本
内容进行包装.上传至服务端。其输人数据项定义如下:
{tbl:<数据表>.cols:<插入列名>,vals:<插入列值>)
其输出数据项定义如下:
{RESULT:<执行结果>)
3_2_3图片下载接口('download.WS)
图片下载接El用于手机移动客户端从服务端数据库中获取
BLOB字段中的图片信息并保存到本地存储设备上。其通过
H,rTP协议,以JSON格式(JSON数组)作为请求发送格式,
客户端将获取图片内容流。其输人数据项定义如下:
{tbl:<数据表>,col<BLOB字段列名>,pk:<主键列名>.
pkval:<主键列值>)
其输出数据项定义如下:
{RESULT:<执行结果>)
3.2.4图片上传接口(upload.WS)
图片上传接El用于手机移动客户端将客户端获取的照片
(本地照片或相机即时获取的照片)上传并保存到服务端数据库
中。其通过H 兀IP协议,以多部分实体的格式,将图片和文本
内容进行组合包装,上传至服务器。其输入数据项定义如下:
{tbl:<数据表>,col:<BLOB字段列名>,pk:<主键列名>.
pkval:<主键列值>}
其输出数据项定义如下:
{RESULT:<执行结果>)
3_2.5地理位置查询接口
地理位置查询接13是指手机移动客户端将手机的基站定位
信息通过该接El进行查询并获取到对应的全球经纬度信息。其
通过HrITrP协议.以JSON格式作为数据交换格式。其接13的
地址信息参见代码。
4数据库设计
4.1分享信息表
分享信息表主要用于存放移动客户端所发布的分享信息,
黼 31
PROGRAM LANGUAGE
{R.drawable.green));
…m … … m m m … …… …
DefaultHttpC¨ent client=new DefauItHttpC¨ent():
HttpPost post=new HttpPost(ur1); getListView0.setDividerHeightI1 0):
}
∥包装请求参数
代码3中,主Activity先通过共享列表管理器的方法获取
if(params!:null&&params.size()>0){
List<BasicNameValuePair>pairs=new ArrayList<
最新的分享信息,再将数据集与列表视图适配器进行绑定。代
码4是获取最新分享信息的关键代码:
代码4获取最新分享信息
文件名:SharingMgr.java
public void updLatestList(Context ctx){
//填充参数
Hashtable<String.String>params=new Hashtable<
String,String>();
params.put(”ds—id”,“sharing—latest_sel“):
/,更新服务接口的URL
final String urt=FooPrefsUtil.getlnstance().updateUrl
(ctx,IDef.Url—Model—Read);
∥启动数据请求线程
HttpReqThread t=new HttpReqThread(ctx,url,
params,IDef.Flag
—
Latest);
t.start0;
}
代码4中,使用H,ITI1P请求线程发出数据请求,代码5是
该线程的执行代码:
代码5 HTTP请求线程执行代码
文件名:HttpReqThread.java
@Override
public void run(){
JSONArray arr=FooHttpUtil.getlnstance{).doPost2(urt
params);
if(arr==nul1){return;)
switch(typeFlag){
case IDef.Flag
—
Latest:{getLatest(this.ctx,arr);break;)
case IDef.Flag
—
My:{getMy(this.ctx,arr);break;)
case IDef.Flag
—
Nearby:(getNearby(this.ctx,arr);break;
)
default:(break;}
)
)
代码5中。HTrP请求线程先发送请求并获取记录集
(JSON数组),再依据请求主体的类型标识的不同而更新不同
的数据集(最新的、当前用户的、当前用户附件的)。代码6
是发送H1TrP请求并获取记录集(JSON数组)的主要代码:
代码6发送HTTP请求获取记录集
文件名:FooHttpUtil.java
public JSONArray doPost2(String url,Map<String,String>
params){
//幸刀始化字符串缓冲(用于拼凑记录集)
StringBuffer sb=new StringBuffer0;
try{
,/创建连接,发送请求并接受回应
BasicNameValuePair>(params.size()):
Set<String>keys:params.keySet0;
for(String key:keys){
pairs.add(new BasicNameValuePair(key,params.get(key)));
)
post.setEntity(new UrlEncodedFormEntity(pairs,“utf-8“)):
)
HttpResponse resp=client.execute(post);
//返回状态
int statusCode=resp.getStatusLine【)_getStatusC0de():
if(statusCode==HttpStatus.SC—OK){
//获取回应条目(JSON格式)
HttpEntity entity=resp.getEntity0;
if(entity i=nul1){
InputStream iS=entity.getContent0;
BufferedReader br= new BufferedReader(new
InputStreamReader(is));
∥获取服务端返回内容
String line=null;
while((1ine=br.readLine0)!=nul1){
sb.append(1ine);
)
br.close();
)
)
post.abort();
∥构建JSON数组
JSONArray arr=new JSONArray(sb.toString0);
return(arr);
)catch(CIientProtocoIException e){e.printStackTrace():
】catch(IOExce ption e){e.p rintStackTrace():
)catch(JSON E×ception e){e.printStackTrace{):
)
return{nul1);
)
代码6中.使用Apache提供的HrIrI1P客户端工具类进行
请求的发送和接收。代码7是代码5中H rI1P请求线程更新最
新分享信息的关键代码:
代码7更新最新分享信息
文件名:HttpReqThread.java
private void getLatest(Context ctx,JSONArray arr)(
#POJO对象数组
ArrayList<Sharing>ds=new ArrayList<Sharing>(art.
1ength());
for(int i=0:i<arr.1ength();++i){
JSONObject obj=null;
目 … …H H 、… f1l 目 i… “{ H 。 …
实用第一 智慧密集
… ~ … .. …一… … ~ …
tn,{
obj=《JSON0bject)(a rr.get(
)catch(JSONException e){
e.p rintStackTrace():
)
//将JSON对象转换成Pojo类
Sharing sharing=Json2Pojo(ctx,obj,IDef Flag_Latest);
if(sharing!=nul1){
Log.d(IDef.App_Tag,sharing.toString()):
ds.add(sharing);
)
)
//更新主Activity的数据集
MainAct.updData(ds);
,/通知主Activity的数据集更新
Message msg=new Message();
msg.what:IDef.MsgData
Upd;
——
MainAct.postMessage(msg);
)
代码7中,需要现将JSON对象转换成POJO类对象,然
后用该类数组来更新对应Activity的数据集(此处是主
Activity)并向该Activity发送数据存在更新的消息。代码8是
将JSON对象转换成POJO类的主要代码:
代码8将JSON对象转换成POJO类
文件名:HttpReqThread.java
//JSON对象转换成POJO(Plain Old Java Objects)类
private Sharing Json2Pojo(Context ctx,JSONObject obj,int
typeFlag){
if(obj==nul1){return(nul1);}
try{
final String id=obj.getString(“S—ID”):
final String type=obj.getString(“S_] PE“):
final String title=obj.getString(”S_TITLE”):
final String user=obj.getString(“S—USER ):
final String tsp=obj.getString(”S_TSP“):
final int lat=obj.getlnt(“S—LA :
ifnal int Ion=obj.getlnt(“S—LON“):
//添加到列表中
Sharing jobj=new Sharing(ctx,id,type,title,user,
tsp,lat,Ion,typeFlag);
return(jobj);
}catch(JS0NException e){e.printStackTrace():
}
return(nul1);
}
(2)获取图片
分享信息的图片信息存放在BLOB字段中 需要通过下载
接口去获取并保存为本地文件。代码9是分享信息POJO类构
造函数,图片下载在其中调用:
代码9分享信息POJO类构造函数
电 与罐
文件名:Sharing.java
public Sharing(Context ctx,String id.String type,String title,
String user,String tsp,
int Iat,int Ion,int typeFlag)(
this.id=id;
this.type:type;
this.title=title;
this.user=user;
this.tsp=tsp;
this.1at=lat;
this.Ion=Ion;
his.picFilePath=FooPrefsUtil.getlnstance0.getDownloadDir()
+File.separator+id+".Jpg”:
,/下载图片信息
DownloadThread t=new DownloadThread(ctx,this,typeFlag);
t.start0;
)
代码9中.分享信息类通过调用下载线程来启动对分享图
片的下载。代码10是图片文件下载线程的执行代码:
代码1 0图片文件下载线程执行代码
文件名:DownloadThread.java
@Override
public void run(){
//获取分享记录ID
final String id=sharing.getld0;
,/获取图片保存路径
File dir=new File(destDir);
ifI!dir.exists()){
return;
)
File destFile=new FiIe(destDir+F_le.separator+id+".Jpg“):
if(destFile.exists()){
return;
)
//发送下载请求
Hashtable<String.String>params=new Hashtable<
String,String>();
params.put(“tbl“,”TAB
—
SHARING“l:
params.put(”col“, S—PIC”):
params.put(“pk”, S—ID”)
params.put(“pkval“.id):
//更新下载接口URL
final String url=FooPrefsUtil.getlnstance().updateU rl
(ctx,IDef.Url
—
Model
—
Download);
∥调用Web Service下载图片
boolean result=FooHttpUtil.getlnstance0.download(url,
params,destFile);
if《result==true){
this.sharing.setP cF.1ePath(destFlle.getAbsoIutePath())
Log.d(IDef App_Tag,“下载图片【“+destFile
getAbsolutePath0+”】完成。”)
……
PROGRA啊LANG卟G ……………………………………~……………………………… … …………………
switch(this.typeFlag){
case IDef.Flag
—
Latest:{∥向主Activity发送消息
Message msg=new Message();
msg.what=IDef.Msg
Img
——
Upd;
MainAct.postMessage(msg);
break;
}
case IDef.Flag
—
My:{∥向我的分享Activity发送消息
case IDef.Flag
—
Nearby:{//f象附近分享
//Activity发送消息
)
default:{break;
)
)
)
)
代码10中,图片文件下载线程通过HrITrP工具类发起文
件下载请求,下载完毕后向各数据展示Activity发送消息,通
知其更新数据集。限于篇幅,HrITrP类中文件下载的处理请参
考附带代码。
(3)对数据获取完毕的响应
在代码l0和代码7中,当分享信息的数据获取完毕后,
执行线程都会向相应的Activity发送消息。那么作为消息接收
方的Activity又是如何响应的呢?代码11是主Activity中初始
化线程消息处理器的主要代码:
代码1 1 主Activity中初始化线程消息处理器
文件名:MainAct.java
,/初始化线程消息队列处理器
handler=new Handler(){
@Override
public void handleMessage(Message msg){
switch(msg.what){
case IDef.Msg
—
Data
—
Upd:{mListAdapter.
notjfyDataSetChanged();break;
)
case IDef.Msg
—
Img
—
Upd: {mListAdapter.
notifyDataSetChanged() break;
}
case IDef.Msg
—
Loc
_
Upd:{
Toast.makeText(MainAct.this. 地址获取成功!“,
Toast.LENGTH
—
LONG).show();
break;
)
case IDef.Msg
Loc
—_
Service:{initLocationO;break;
)
default:{break;)
1
)
):
代码l1中.主Activity使用线程消息处理器来接收消息.
并按照消息类型进行不同的处理。当收到数据存在更新和图片
存在更新的消息后的处理是通知列表适配器更新数据集:收到
位置服务启动完毕的消息后的处理时初始化位置信息。
5.2.2发布分享信息到服务端
(1)发布文本信息
代码12是发布分享信息的主要代码:
代码12发布分享信息
文件名:PushAct.java
private void pushSharing(){
String title=titles.getTextO.toString0.trim();
//发布内容的有效性检查
.f((t e==n ul1)lI(title!=null&&title.1engthO<2)){
Toast.makeText(this,“主题不能为空!li,Toast.
LENGTH SHORT).show();
return;
)
Location Ioc:MainAct.getLocation0;
//数据准备
final String cols=”S
ID,S
TYPE,STITLE,SUSER,
————
S
_
TSP,S
—
LA丁 S
—
LON”:
final String tjd= ((id==nuII)?FOOSVsUt getlnstance《).
getldOfTspO:id);
final SharingType type = (SharingType)types.
getSetectedltemO;
final String user=MainAct.getUserldO;
final String tsp=FooSysUtil.getlnstanceO.getTspO;
final String location= +loc.getLatO+n,il+loc.getLon0;
finaI String vals=“ +tid+ , +type.getld 0+ , +
URLEncoder.encOde(titIe)+III,Jn+
user+ ,to
_
date( +URLEncoder.encode(tsp)+ , ”+
URLEncoder.encode(“yyyy—mm—dd hh24:mi:ss“)+ ),“+
location;
//包装参数
Hashtable<String.String>params=new Hashtable<
String,String>();
params.put( tbl”,“TAB—SHARING“):
params.put(‘。cols“,cols);
,/更新发布接口的URL
final String url=FooPrefsUtil.getlnstance0.updateUrl(this.
IDef.Url Model Create+”?vals= +vals);
Log.d(IDef.ApQjag。ur1);
∥调用信息发布接口进行发布
JSONObject obj=FooHttpUtil.getlnstance().doPost(url,
params);
if(obi=:nul1){return;)
try{∥若文本内容发送成功,则即可发布图片
String resuit=obj.getString(IDataSpec.RESULT);
翔 脑螭程2埂。t钉3习.瓢 、 3 .5
… ……… … … ’ 一 ……… …
实用第一 智慧密集
… 一 :. …… …
if(result.compareTo(IDataSpec.RESULT—OK)==O){
||上传图
uptoadPic(tid);
,/通知主Activity更新
Message msg=new Message();
msg.what=IDef.Msg
—
Data
—
Upd;
MainAct.postMessage(msg);
Toast.makeText(this,“分享发布成功!“,Toast.
LENGTH
—
LONG).show();
finish();
)
)catch(JSONException e){e.printStackTrace():
)
)
代码12中,其思路是先获取发布信息内容(分享标识、
类型、用户、时间戳等),再包装成接13参数,最后调用服务
端发布接口进行信息的发布。限于篇幅.调用服务端发布接口
的代码请参考附带代码。
(2)发布图片信息
若文本信息发布成功则即可发布图片信息,代码13是代
码l2中发布图片的主要代码:
代码13发布图片信息
文件名:PushAct.java
private void uploadPic(Str ing id){
if(picFilePath==nuII){return;)
//包装参数
Hashtable<String.String>params=new Hashtable<
String,String>();
params.put( tbl“,“TAB—SHARING“):
params.put(”col”,”S—PIC ):
params put(“pk“,“S—ID“):
params.put(”pkval“,id):
||
File f=new File(picFllePath):
final String url:FooPrefsUtil.getlnstance《).updateUrl
(this,IDef.U rl—Model—Upload);
,/调用Web Service上传图片
JSONObject obj=FooHttpUtil.getlnstance().upload(url,
params,f):
if(obi=:nul1)(
Toast.makeText(this.“图片发送失败!II,Toast.
LENGTH
——
SHORT).show();
return;
)
trv(
String result=obj.getst g(1DataSpec.RESULT);
if(result.compareTo(IDataSpec.RESULT_0K)=:O){
//Toast.makeText (this, result,Toast.
LENGTH SHORT).show();
)
)catch(JSONException e){
36 电 品与雏
e.printStackTraceO;
Toast.makeText(this.“图片发送失败!II,Toast.
LENGTH
——
SHORT).show();
)
)
代码13中,共享发布Activity通过调用图片I 传接13完成
图片信息的发布。
(3)对信息发布完毕的响应
在代码12中,当分享信息发布完毕后即向主Activity发送了
一
条数据存在更新的消息,用以通知主Activity更新其数据集。
5-2.3移动客户端展示分享信息
分享信息的展示可以考虑从分享信息列表视图的行布局
(对应列表视图中的每一行的布局)和分享信息列表适配器
(将数据显示到布局中)。
(1)分享信息列表视图的行布局
分享信息列表视图的行视图效果如图2(左)中的每一项,
限于篇幅.分享信息列表视图的行布局定义请参考附带代码。
(2)分享信息列表适配器
代码14是分享信息列表适配器的关键代码,其巾主要是
如何更新其行布局:
代码14分享信息列表适配器
文件名:F0oListAdapter.java
@Override
public View getView(int pos,View convertView,ViewGroup
parent){
if(conver[View==nullJ{
final Layoutlnfiater inflater=ctx.getLayoutInflater()
∥获取项目View(每一行)
convertView=inflater.infIate(1aVoutId,null,false);
)
//按照行属性设置其背景
if(pos==selectedPos)(
convertView.setBackgrOundResOurce(R.drawable.Iorange);
)else{
if((pos%2)>O)(,/奇数
convertV Jew.setBackgroundResource(R.drawable.gray);
)else{∥偶数
conveRView.setBackgrOundResource(R.drawable.silver);
)
)
if(items!=nul1){∥将分享对象的属性信息展示到行布局
,/所定义的组件中
final Sharing item=items.get(pos);
《(TextView)convertView.findViewByld
(this.to【O】))
setText(item.getTypeO);
((TextView)convertView.findViewByld
setText(item.getTitle0);
((TextView)convertView.findViewByld 《this.to【21) )
setText(item.getUserO);
…
PROGRAM LANGUAGE - , r -
((T extView)conve ̄View.findViewByld(this.to【31)) l
setText(item.getTsp0);
final String location=“(”+item.getLatF()+“, +item。
getLonFO+”)“:
《(TextView)convertView.findViewByld(this.to【4】)).
setText(tocation);
∥显示分享图片的缩略图
final int width=(int)ctx.getResources().
getDimension(R.dimen.img_width);
final int height=(int)ctx.getResources
《).getDimension(R.dimen.img—height);
final Bitmap bitmap=
FooPicUtil.getlnstance().getLocalBitmap(item.
getPic ePath(),width.height);
i(ImageView)convertView.findViewByld(this.to【5】)).
setlmageBitmap(bitmap);
//Log.d(IDef.App_Tag,item.toString0);
}
return(convertView);
)
代码14中,适配器依据回调函数中记录行位置参数
(pos)获取对应的记录对象,然后获取记录对象的属性信息并
设置给行布局中的显示组件。
5.2.4移动客户端获取本地信息
在移动客户端所发布的信息中,相机即时拍照所获取的照
片以及手机设备的位置和标识信息,这些都是在桌面客户端中
无法获取的内容,而正是这些手机平台特有的信息,让移动客
户端的应用变得丰富多彩。
(1)获取即时拍照照片
代码15是调用系统相机拍摄分享照片的主要代码:
代码15调用系统相机拍摄分享照片
文件名:PushAct.java
private void takePic(){
id=FooSysUtit.getlnstanceO.getldOfTspO;
final String filePath:FooPrefsUt
getlnstance 0・
getUpIoadDir()+File.separator+id+".Jpg”:
Intent i:new Intent fMediaStore.
ACTION IMAGE CAPTURE):
i.putExtra(MediaStore.EXTRA OUTPUT,Uri.from e《new
e( ePath))):
this.startActivityForResult(i,IDef.Req. Code Camera);
)
代码15中,通过指定输出路径的方式调用系统相机,当
调用成功,则指定路径即为拍照照片的路径。对于使用不指定
输出路径的方式调用系统相机,在回调函数中将直接获取照片
的位图信息,而且该位图不是实际照片的内容,而是缩略图。
(2)获取设备标识及位置信息
对于手机设备标识及位置信息,需要使用电话系统服务
(TelephonyManager)的相关接13,代码16是获取设备标识及
… … … … … n
位置信息的主要代码:
代码1 6获取设备标识及位置信息
文件名:LocationService.java
public void updateLocation(){
if(telMgr==nul1){return;)
CellLocation Ioc=telMgr.getCelJLocatj0n():
if(Ioc==nul1){return;)
updateLocation(10c);
)
public void updateLocatiOn《CellLocatiOn Ioc){
if(Ioc==nul1){return;)
,/获取用户标识(电话号码或lM EI)
userld=telMgr.getLinel Number();
if(userld==nul1){userld=telMgr.getDeviceldO;)
lf(userld==nul1){return;)
//获取手机当前的位置区域识别信息
final String operator=this.teIMgr.getNetworkOperator0;
final int mcc:Integer.parseInt(ope阳tor.substring(0,3)):
final int mnc=Integer.parseInt《operator.substring(3));
final int lac=((GsmCellLocation)loc).getLac0;
finaI int cid=f(GsmCellLocation)loc).getCid0;
∥判断定位信息合法性
if((1ac==0)&&(cid==0)){return;)
if((Iac<0)ll(Iac>=Oxffff)II(cid<0)Il(cid>=0xffff))(
return;
}
lai.setMCC(mcc);lai.setMnc(mnc);Iai.setLac(1ac);lai.
setCid(cid);
)
代码16中,使用系统电话管理器的相关API可以获取位置
信息(基站位置信息)、手机号码、设备IMEI和网络标识。需
要注意的是当前的位置信息还仅仅是手机网络的基站位置信息,
还需要调用互联网服务接口通过基站位置信息获取全球经纬度信
息。限于篇幅,该互联网服务接El的调用过程请参考附带代码。
6结语
对该分享信息平台移动客户端的部分功能细节.并没有给
予详细的介绍(例如:通过电话基站位置信息获取全球经纬度
信息、获取分享类型信息、上传及下载图片的细节控制、获取
附近分享信息等),读者可以通过配套代码进行理解。
该开发实例涵盖了移动客户端应用的常见模式,例如:数
据的获取和发布、图片的下载及上传、获取手机位置信息、调用
系统相机拍照、基于地理位置的信息关联分析等。在数据的获取
过程中.详细介绍了使用线程消息队列机制实现数据获取的异步
操作.这些技巧都是在商业项目开发中常用的方式。
该开发案例经Android 2.3.6和4.0.4版本的实机验证.希
望对读者有所参考。
(收稿日期:2013—03—29)
发布者:admin,转转请注明出处:http://www.yc00.com/web/1718131971a2747033.html
评论列表(0条)