您好,登錄后才能下訂單哦!
最近天氣真他娘的熱,炸雞啤酒,我覺得如果不演那么什么我從來都不看的韓劇,絕對沒有人喜歡這種吃法。好了,廢話不多說,天這么熱,我只能晚上騰出時間來寫這個東東,順便引用吉日嘎拉的博客上面的一句話"每天進步一點點"。
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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。