最近天气真他娘的热,炸鸡啤酒,我觉得如果不演那么什么我从来都不看的韩剧,绝对没有人喜欢这种吃法。好了,废话不多说,天这么热,我只能晚上腾出时间来写这个东东,顺便引用吉日嘎拉的博客上面的一句话"每天进步一点点"。
OK,我们这次是要把这个界面翻成Android版,大家看过我的博客都知道我一直都是拿这几个界面再弄,
什么java实战篇也是用这个界面,唉,没办法,我只有这个界面。
先上一张Android版的图,吊胃口,下面的这张是模拟器上的图,怎么样,还像个app的样子吧。
首先我们来看一下.net webService端,在webService中我新增了一个方法
[WebMethod] public CommonResponse UserInfoModify(UserInfoEntity userInfoEntity) { return UserInfoBiz.GetInstance().ModifyUserInfo(userInfoEntity); }
接下里看一下Biz层
public CommonResponse ModifyUserInfo(UserInfoEntity userInfoEntity) { try { int suc = UserInfoMngDAL.GetInstance().ModifyUserInfo(userInfoEntity); if (suc > 0) { return new CommonResponse() { IsSuccess = true }; } return new CommonResponse() { IsSuccess = false, ErrorMessage = SaveFailed }; } catch (Exception ex) { return new CommonResponse() { IsSuccess = false, ErrorMessage = ex.Message }; } }
最后看一下DAL层
public int ModifyUserInfo(UserInfoEntity userInfoEntity) { using (BonusEntities bonusEntities = new BonusEntities()) { if (bonusEntities.UerInfo.Any(u => u.UseNo == userInfoEntity.UserNo)) //has existed { UerInfo uerInfoModify = bonusEntities.UerInfo.SingleOrDefault(u => u.UseNo == userInfoEntity.UserNo); uerInfoModify.Name = userInfoEntity.UserName; uerInfoModify.Sex = userInfoEntity.UserSex == "男" ? "1" : "2"; uerInfoModify.Age = userInfoEntity.UserAge; uerInfoModify.Temper = userInfoEntity.Temper; uerInfoModify.BirthDay = DateTime.Parse(string.Concat(userInfoEntity.BirthDay, " 00:00:01")); if (!string.IsNullOrWhiteSpace(userInfoEntity.UserPhoto)) { uerInfoModify.Photo = Convert.FromBase64String(userInfoEntity.UserPhoto); } } else { UerInfo uerInfo = new UerInfo(); uerInfo.UseNo = userInfoEntity.UserNo; uerInfo.Name = userInfoEntity.UserName; uerInfo.Sex = userInfoEntity.UserSex == "男" ? "1" : "2"; uerInfo.Age = userInfoEntity.UserAge; uerInfo.Temper = userInfoEntity.Temper; uerInfo.BirthDay = DateTime.Parse(string.Concat(userInfoEntity.BirthDay, " 00:00:01")); if (!string.IsNullOrWhiteSpace(userInfoEntity.UserPhoto)) { uerInfo.Photo = Convert.FromBase64String(userInfoEntity.UserPhoto); } bonusEntities.UerInfo.Add(uerInfo); } return bonusEntities.SaveChanges(); } }
非常的简单,如果存在就是修改,否则是新建。在这里需要注意的是下面这句
uerInfo.Photo = Convert.FromBase64String()
这个解释的话先看一下我们的EF实体
我们的Photo是byte[]类型,因为Ksoap是无法传递byte[]的,所以在android客户端,我们要先将byte[]编码成string,然后在.net wenservice端再反编码。好了,这里就是webservice端。
接着就到了我们的android客户端了,他才是我们这篇文章的重头戏。先上一张真机上的图,开启笔记本wifi,手机连接wifi,更换代码中的IP,OK,运行
就是这张图,大家可能会问,那右边的那个东西是什么,是鸟的翅膀吗,不是,是一个人
这边的功能是如果用户勾选checkBox,则保存的时候会将图片一并提交webservice去做保存。
图也看了,那么先看一下页面布局
<?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"> <HorizontalScrollView android:layout_height="wrap_content" android:layout_width="fill_parent" android:scrollbarAlwaysDrawHorizontalTrack="false"> <TableLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/blue1" android:stretchColumns="0"> <TableRow> <TableLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:stretchColumns="1" android:padding="3dp" android:layout_column="0" android:layout_margin="1dp" android:background="@color/teal"> <TableRow> <TextView android:text="@string/userName" android:gravity="right" android:textSize="8pt"></TextView> <EditText android:id="@+id/txtUserName" android:drawableLeft="@drawable/userhint" android:hint="@string/hintInputUserName" android:textColorHint="@color/hintColor" android:width="200dp" android:singleLine="true" android:maxLength="25"></EditText> </TableRow> <TableRow> <TextView android:text="@string/userSex" android:layout_gravity="center_vertical" android:textSize="8pt"> </TextView> <Spinner android:id="@+id/cmbUserSex" android:layout_width="fill_parent" android:layout_height="wrap_content"></Spinner> </TableRow> <TableRow> <TextView android:text="@string/userAge" android:gravity="right" android:textSize="8pt"></TextView> <EditText android:id="@+id/txtUserAge" android:editable="false"></EditText> </TableRow> <TableRow> <TextView android:text="@string/userBirthDay" android:gravity="right" android:textSize="8pt" android:layout_gravity="center_vertical"></TextView> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <EditText android:id="@+id/txtUserBirthDay" android:editable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:width="140dp" android:hint="@string/hintChooseBirth" android:textColorHint="@color/hintColor" android:drawableLeft="@drawable/calander" android:singleLine="true"></EditText> <Button android:id="@+id/btnChoose" android:layout_width="80dp" android:layout_height="45dp" android:drawableLeft="@drawable/pencil" android:layout_gravity="center_vertical" android:text="@string/btnChoose" android:textStyle="bold"></Button> </LinearLayout> </TableRow> <TableRow> <TextView android:text="@string/userTemper" android:gravity="right" android:textSize="8pt" android:layout_gravity="center_vertical"></TextView> <RadioGroup android:id="@+id/radioGroup" android:contentDescription="脾气" android:layout_width="wrap_content" android:orientation="horizontal" android:layout_height="wrap_content"> <RadioButton android:layout_width="wrap_content" android:textColor="@color/red1" android:layout_height="wrap_content" android:id="@+id/radioTemper1" android:text="@string/userTemper1" android:checked="true"></RadioButton> <RadioButton android:layout_width="wrap_content" android:textColor="@color/red1" android:layout_height="wrap_content" android:id="@+id/radioTemper2" android:text="@string/userTemper2"></RadioButton> </RadioGroup> </TableRow> <TableRow> <LinearLayout android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_span="2"> <Button android:id="@+id/btnSave" android:text="@string/btnSave" android:textColor="@color/blue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textStyle="bold"></Button> <Button android:text="@string/btnCancelText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:id="@+id/btnCancel" android:textColor="@color/blue" android:textStyle="bold" ></Button> </LinearLayout> </TableRow> </TableLayout> <TableLayout android:layout_width="wrap_content" android:background="@color/teal" android:layout_margin="1dp" android:layout_height="wrap_content" android:layout_column="1"> <TableRow> <ImageView android:id="@+id/imgUserPhoto" android:background="@color/imgBg" android:layout_marginLeft="10dp" android:layout_marginTop="5dp" android:layout_marginRight="5dp" android:layout_width="160dp" android:layout_height="240dp" android:src="@drawable/deaultphoto" android:scaleType="fitCenter" android:layout_span="2" /> </TableRow> <TableRow> <CheckBox android:id="@+id/chkChoosePhoto" android:layout_marginLeft="10dp" android:layout_column="0"></CheckBox> <Button android:id="@+id/btnBrowser" android:text="@string/btnChoosePhoto" android:textStyle="bold" android:layout_width="150dp" android:layout_height="45dp" android:layout_marginTop="1dp" android:textColor="@color/blue" android:layout_column="1"></Button> </TableRow> </TableLayout> </TableRow> </TableLayout> </HorizontalScrollView> </LinearLayout>
布局的话主要有以下几点,第一,这个布局总体采用TableLayout,因为我们的界面的宽度的缘故,所以我在table的外层加了个HorizontalScrollView,用来左右滚动。第二,这个界面的布局是采用左右各占一列, 在列中又嵌套了Table。做过Silverlight的人都知道,Grid布局是很好用的,这个和Silverlight的Grid布局有点像。布局的话其实都很简单,也没啥看点。
在界面中,大家都看到了有个下拉列表样子的东西,那是什么,是ComboBox?我靠,你以为这是在做Silverlight呢。这个是Android中的Spinner控件。我们来看一下他是如何加载下拉数据和响应事件的。
首先我们在string.xml文件中新增了一个string-array资源,用来加载到下拉列表。
在代码中,我们会构造一个Spinner加载数据的一个适配器,如下
private void InitData() { // ArrayAdapter<String> adapter; // adapter = new ArrayAdapter<String>(this, // android.R.layout.simple_spinner_item, sexArray); final ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(this, R.array.sexArray, android.R.layout.simple_spinner_item); adapter .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spnUserSex.setAdapter(adapter); // spnUserSex.setOnItemSelectedListener(new OnItemSelectedListener() { // public void onItemSelected(AdapterView<?> arg0, View arg1, // int arg2, long arg3) { // String selectedItem = adapter.getItem(arg2).toString(); // } // // public void onNothingSelected(AdapterView<?> arg0) { // } // }); }
看到了吧,那句R.Array.SexArray就是从资源文件取出性别集合的。
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
这句是表示我们的下拉列表展示简单的项(只有文子字),如果你想让你的下拉列表更生动,你可以去加载模版,比如在男选项前面放一个男人头像,女选项前面放一个女头像。这个其实和Silverlight的ComboBox的模版类似。OK,最后给Spinner设置适配器。我注释的上面部分是当不从资源文件加载数据的时候的代码,下面部分是下拉事件响应的代码。我们看一下下拉效果
此时,就可以在界面选择你想要的结果。
好了,那我们接下来看这个出生日期,为什么要先看出生日期呢,因为年龄是根据出生日期算出来的,难道您刚才没注意那个年龄的文本框是设置为不能编辑的吗(android:editable="false")。
出生日期后面的那个选择按钮完成的功能是弹出日期选择界面。看代码
this.btnChoose.setOnClickListener(new OnClickListener() { public void onClick(View view) { Calendar calendar = Calendar.getInstance(); DatePickerDialog dialog = new DatePickerDialog(owner, new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker dp, int year, int month, int dayOfMonth) { txtBirthDay.setText(year + "-" + month + "-" + dayOfMonth); SimpleDateFormat df = new SimpleDateFormat(); df.applyPattern("yyyy-MM-dd hh:mm:ss"); try { Date dt = df.parse(year + "-" + month + "-" + dayOfMonth + " 00:00:01"); int age = new Date().getYear() - dt.getYear(); txtAge.setText(String.valueOf(age)); } catch (ParseException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }, calendar.get(Calendar.YEAR), calendar .get(Calendar.MONTH), calendar .get(Calendar.DAY_OF_MONTH)); dialog.show(); } });
看到了吧,我们直接弹出android内置的Dialog(DatePickerDialog),看一下效果
在他的日期设置事件(onDateSet)中,我们拿到选择的日期,先赋给出生日期文本框,然后再用当前的年份减去选择的年份,算出来就是年龄,把年龄赋给年龄文本框。如果你想设置初始化的日期的话,需要注意他DatePickerDialog的构造函数最后三个参数,来自API的解释
OK,日期看完之后,就是右边的图片了,首先我们要知道图片从哪里来,当然是从手机里来,是个人都知道。我们看一下点击浏览按钮做的事情。
this.btnBrowser.setOnClickListener(new OnClickListener() { public void onClick(View view) { Intent intent = new Intent(); intent.setType("p_w_picpath/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(intent, 1); } });
看到了吧,启动手机的图片照片搜索界面,如下
选择一张照片,图片就会显示到图片框中,如下
那么图片是怎么显示到图片框中的,第一步,我们要重写当前Activity的onActivityResult方法。
protected void onActivityResult(int requestCode, int resultCode, android.content.Intent data) { if (resultCode == RESULT_OK) { Uri uri = data.getData(); ContentResolver contentResolver = this.getContentResolver(); try { Bitmap bitmap = BitmapFactory.decodeStream(contentResolver .openInputStream(uri)); imgUserPhoto.setImageBitmap(bitmap); } catch (FileNotFoundException e) { } } super.onActivityResult(requestCode, resultCode, data); }
我们拿到图片的资源地址后,转化成Bitmap,赋给图片框。在这里图片框有多种显示拉伸方式,我就不多说了,自己查吧。OK,图片也显示完了,我们看最后的保存。
在看保存之前,我们先看一下取消
this.btnCancel.setOnClickListener(new OnClickListener() { public void onClick(View view) { final AlertDialog.Builder builder = new AlertDialog.Builder( owner); builder.setIcon(R.drawable.info); builder.setTitle(R.string.titleSystemCodeModifyName); builder.setMessage("您确定要退出修改吗?"); builder.setPositiveButton(R.string.btnSure, null); builder.setNegativeButton(R.string.btnCancelText, null); final AlertDialog dialog = builder.create(); dialog.show(); dialog.getButton(AlertDialog.BUTTON_POSITIVE) .setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { userinfomanage.this.setResult(RESULT_OK); userinfomanage.this.finish(); } }); } });
取消这个很简单,就是构造一个弹出框,点击确定关闭当前Activity,点击取消,不关闭界面
OK,最后我们看一下我们的save。
this.btnSave.setOnClickListener((new OnClickListener() { public void onClick(View view) { if (!CheckUserInput()) return; UserInfoEntity userInfoEntity = GetUserInfoEntity(); SoapObject soapObject = ModifyUserInfoEntty(userInfoEntity); Boolean isSuccess = Boolean.valueOf(soapObject.getProperty( "IsSuccess").toString()); if (isSuccess) { ShowMessage(R.string.SaveSuccess); } else { String errorMsg = soapObject.getProperty("ErrorMessage") .toString(); ShowMessage(errorMsg); } } }));
首先是check,如下,很简单
private Boolean CheckUserInput() { String userName = this.txtUserName.getText().toString().trim(); if (userName.length() == 0) { this.ShowMessage("姓名不能为空!"); this.txtUserName.requestFocus(); return false; } String birthDay = this.txtBirthDay.getText().toString().trim(); if (birthDay.length() == 0) { this.ShowMessage("出生日期不能为空!"); this.btnBrowser.requestFocus(); return false; } return true; }
接着是拿到要保存的实体GetUserInfoEntity
private UserInfoEntity GetUserInfoEntity() { UserInfoEntity userInfoEntity = new UserInfoEntity(); userInfoEntity.setProperty(1, txtUserName.getText().toString()); userInfoEntity.setProperty(0, userNo); userInfoEntity.setProperty(2, spnUserSex.getSelectedItem()); userInfoEntity.setProperty(3, txtAge.getText()); userInfoEntity.setProperty(4, txtBirthDay.getText()); userInfoEntity.setProperty(5, radiobtnTemper1.isChecked() ? "1" : "2"); if (chkPhoto.isChecked()) { String strByte = Base64.encode(GetImageByteArray()); userInfoEntity.setProperty(6, strByte); } return userInfoEntity; }
需要注意的是这里Base64.encode(GetImageByteArray()),这个就是刚才说的KSoap不支持直接传byte[],而是要转码。GetImageByteArray这个方法是将图片框中的图片转化成byte[]。
private byte[] GetImageByteArray() { byte[] compressData = null; imgUserPhoto.setDrawingCacheEnabled(true); Bitmap bmp = Bitmap.createBitmap(imgUserPhoto.getDrawingCache()); imgUserPhoto.setDrawingCacheEnabled(false); if (bmp != null) { compressData = GetByteArrayByBitmap(bmp); } return compressData; } private byte[] GetByteArrayByBitmap(Bitmap bmp) { byte[] compressData = null; ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.JPEG, 100, byteOutputStream); compressData = byteOutputStream.toByteArray(); try { byteOutputStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return compressData; }
这都是固定写法,不多做解释。OK,我们看一下实体的定义,免得看得人摸不着头脑
public class UserInfoEntity implements KvmSerializable { private String UserNo; private String UserName; private String UserSex; private int UserAge; private String BirthDay; private String Temper; private String UserPhoto; @Override public Object getProperty(int arg0) { // TODO Auto-generated method stub Object property = null; switch (arg0) { case 0: property = this.UserNo; break; case 1: property = this.UserName; break; case 2: property = this.UserSex; break; case 3: property = this.UserAge; break; case 4: property = this.BirthDay; break; case 5: property = this.Temper; break; case 6: property = this.UserPhoto; break; default: break; } return property; } @Override public int getPropertyCount() { // TODO Auto-generated method stub return 7; } @Override public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) { // TODO Auto-generated method stub switch (arg0) { case 0: arg2.type = PropertyInfo.STRING_CLASS; arg2.name = "UserNo"; break; case 1: arg2.type = PropertyInfo.STRING_CLASS; arg2.name = "UserName"; break; case 2: arg2.type = PropertyInfo.STRING_CLASS; arg2.name = "UserSex"; break; case 3: arg2.type = PropertyInfo.INTEGER_CLASS; arg2.name = "UserAge"; break; case 4: arg2.type = PropertyInfo.STRING_CLASS; arg2.name = "BirthDay"; break; case 5: arg2.type = PropertyInfo.STRING_CLASS; arg2.name = "Temper"; break; case 6: arg2.type = PropertyInfo.STRING_CLASS; arg2.name = "UserPhoto"; break; default: break; } } @Override public void setProperty(int arg0, Object arg1) { // TODO Auto-generated method stub if (arg1 == null) return; switch (arg0) { case 0: this.UserNo = arg1.toString(); break; case 1: this.UserName = arg1.toString(); break; case 2: this.UserSex = arg1.toString(); break; case 3: this.UserAge = Integer.parseInt(arg1.toString()); break; case 4: this.BirthDay = arg1.toString(); break; case 5: this.Temper = arg1.toString(); break; case 6: this.UserPhoto = arg1.toString(); default: break; } } }
和.net WebServce端是对应的。OK,最后我们看一下保存(ModifyUserInfoEntty)的代码。
private SoapObject ModifyUserInfoEntty(UserInfoEntity userInfoEntity) { SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); PropertyInfo pi = new PropertyInfo(); pi.setName("userInfoEntity"); pi.setValue(userInfoEntity); pi.setType(userInfoEntity.getClass()); request.addProperty(pi); SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope( SoapEnvelope.VER11); soapEnvelope.dotNet = true; HttpTransportSE httpTS = new HttpTransportSE(URL); soapEnvelope.bodyOut = httpTS; soapEnvelope.setOutputSoapObject(request);// 设置请求参数 soapEnvelope.addMapping(NAMESPACE, "UserInfoEntity", userInfoEntity .getClass()); new MarshalBase64().register(soapEnvelope); try { httpTS.call(SOAP_ACTION, soapEnvelope); } catch (IOException e) { // TODO Auto-generated catch block this.ShowMessage(e.getMessage()); // e.printStackTrace(); } catch (XmlPullParserException e) { // TODO Auto-generated catch block e.printStackTrace(); } SoapObject result = null; try { result = (SoapObject) soapEnvelope.getResponse(); } catch (SoapFault e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; }
这里需要注意的是new MarshalBase64().register(soapEnvelope);这是要告诉soap 信使message中包含有Base64转过的byte[]。OK,最后,我们鼓起勇气点击save。
走起,见证奇迹的时刻
yeah,成功了,图片是否成功我们需要借助C#版的程序看一下,成功了。
最后,哥们这博客可真是货真价实,中兴U880S测试机。
评价一下你不会吃亏,评价一下你不会上当,你评的越多,我写的越多。他大舅他二舅都是他舅,高桌子低板凳都是木头,进来的都是干这一行的,给个评价吧。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。