Android切近实战(一)
记得上篇文章我还在为使用哪种开发语言开发android而发愁,最近使用了一下C#开发android,感觉不是那么爽。查资料也不方便,于是我决定使用java开发,毕竟java我也是学过的,eclipse环境也不陌生。开始吧,天很冷,先上图
这张图我是从真机上截取下来的,这是一个登陆界面。用户输入用户名和密码后,验证,验证通过之后,跳转至另一个Activity。那么我目前采取的方式是Android调用.net WebService的方式。
OK,先看一下Service端。
很熟悉很简单的结构。我们简单看一下Service端的代码
namespace GRLC.WebService{ /// <summary> /// Login 的摘要说明 /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.None)] [System.ComponentModel.ToolboxItem(false)] // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 // [System.Web.Script.Services.ScriptService] public class LoginService : System.Web.Services.WebService { [WebMethod] public LoginResponse CheckLogin(string userNo, string pwd) { return LoginBiz.GetInstance().CheckLogin(userNo, pwd); } }}
没什么好说的,完了之后我们再看Biz层
public class LoginBiz { static LoginBiz loginBiz = new LoginBiz(); private LoginBiz() { } public static LoginBiz GetInstance() { return loginBiz; } public LoginResponse CheckLogin(string name, string pwd) { return LoginDAL.GetInstance().CheckLogin(name, pwd); } }
也没啥说的,再看Dal层
public class LoginDAL { static LoginDAL loginDAL = new LoginDAL(); private LoginDAL() { } public static LoginDAL GetInstance() { return loginDAL; } const string moduleName = "LoginModule"; BonusEntities bonusEntities = new BonusEntities(); private string PwdIsNotCorrect { get { return this.GetMessageByName("PwdNotCorrect"); } } private string UserNotExists { get { return this.GetMessageByName("UserNotExists"); } } private string GetMessageByName(string msgName) { return CommonFunction.GetMessageByModuleAndName(moduleName, msgName); } public LoginResponse CheckLogin(string name, string pwd) { User user = bonusEntities.User.SingleOrDefault(u => u.UseNo == name); if (user != null) { string passWord = Cryptor.Decrypt(user.Pwd); if (!passWord.Equals(pwd)) { return new LoginResponse() { IsSuccess = false, FailMsg = PwdIsNotCorrect }; } return new LoginResponse() { IsSuccess = true }; } else { return new LoginResponse() { IsSuccess = false, FailMsg = UserNotExists }; } } }
在这里我们使用了EntityFrameWork作真正的数据访问层。我一次性把所有表都映射进来了,并设置了他们之间的关联关系。
在这里需要说的是这个GetMessageByModuleAndName方法。
public class CommonFunction { private static string BaseDirectory { get { return AppDomain.CurrentDomain.BaseDirectory; } } private static List<ServiceMessage> GetMessageList() { List<ServiceMessage> messageList = new List<ServiceMessage>(); string messageConfigFolder = Path.Combine(BaseDirectory, ConfigHelper.MessageConfigFolder); if (!Directory.Exists(messageConfigFolder)) return null; string[] files = Directory.GetFiles(messageConfigFolder, "*.xml", SearchOption.TopDirectoryOnly); foreach (string file in files) { ServiceMessage message = SerializeHelper.XmlDeSerializeByFile<ServiceMessage>(file); messageList.Add(message); } return messageList; } public static string GetMessageByModuleAndName(string moduleName, string msgName) { string message = string.Empty; ServiceMessage serviceMsg = new ServiceMessage(); List<ServiceMessage> serviceMessageList = CommonFunction.GetMessageList(); List<MessageEntityCollection> messageEntityCollection = serviceMessageList.Select(m => m.messageEntityCollection).ToList(); foreach (var msgEntityCollection in messageEntityCollection) { MessageEntity messageEntity = msgEntityCollection.SingleOrDefault(msgEntity => msgEntity.Module == moduleName && msgEntity.Name == msgName); if (messageEntity != null) { message = messageEntity.Content; break; } } return message; } }
首先这个方法会先从配置文件里面获取到提示信息的配置文件夹,然后遍历xml文件,将所有xml文件中的提示信息通过反序列化放到一个List中,也就是上面的GetMessageList()方法,其实在这里我们可以对代码进行优化,如下
private static List<ServiceMessage> _serviceMessageList; private static List<ServiceMessage> ServiceMessageList { get { if (_serviceMessageList == null) { _serviceMessageList = GetMessageList(); return _serviceMessageList; } else { return _serviceMessageList; } } }
那么每次在获取的时候,会先判断_serviceMessageList有没有,如果有,就不再读取文件了。
我们来看一下这个配置文件
<?xml version="1.0" encoding="utf-8"?><ServiceMessages> <Message Module="LoginModule" Name="PwdNotCorrect" Content="密码不正确!"></Message> <Message Module="LoginModule" Name="UserNotExists" Content="用户名不存在!"></Message></ServiceMessages>
它对应的实体如下
namespace GRLC.Model.Config{ [XmlRoot("ServiceMessages")] public class ServiceMessage { [XmlElement("Message")] public MessageEntityCollection messageEntityCollection { get; set; } } public class MessageEntityCollection : KeyedCollection<string, MessageEntity> { protected override string GetKeyForItem(MessageEntity messageEntity) { return messageEntity.Name; } } [XmlRoot("Message")] public class MessageEntity { [XmlAttribute("Name")] public string Name { get; set; } [XmlAttribute("Module")] public string Module { get; set; } [XmlAttribute("Content")] public string Content { get; set; } }}
所以在拿到这些msg以后,根据他的module和name就可以拿到对应content。好了上面就是.net的service端。完了之后我们部署一下
部署的时候需要注意如下
接下来我们看一下app端的开发
我们总共有两个Activity,一个是main,一个是index,main界面登成功跳转至index界面。
我们先看一下mai界面的代码
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layMain" android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingLeft="10dp" android:paddingRight="10dp" android:orientation="vertical" android:gravity="center_vertical"> <LinearLayout android:orientation="horizontal" android:gravity="center_vertical" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/labUserName" android:text="@string/labUserName" android:layout_width="70dp" android:layout_height="wrap_content" android:textSize="18dp" android:textStyle="bold"></TextView> <EditText android:id="@+id/txtUserName" android:hint="@string/hintInputUserNo" android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true"></EditText> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/labPwd" android:text="@string/labPwd" android:layout_width="70dp" android:layout_height="wrap_content" android:textSize="18dp" android:textStyle="bold"></TextView> <EditText android:id="@+id/txtPwd" android:hint="@string/hintInputUserPwd" android:layout_height="wrap_content" android:layout_width="fill_parent" android:singleLine="true" android:password="true"></EditText> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:gravity="center_horizontal" android:layout_height="wrap_content"> <CheckBox android:id="@+id/chkDisplayPwd" android:layout_width="130dp" android:layout_height="wrap_content" android:text="@string/chkDisplayPwd"> </CheckBox> <Button android:id="@+id/btnLogin" android:text="@string/btnLoginText" android:layout_width="80dp" android:layout_height="wrap_content"></Button> <Button android:id="@+id/btnCancel" android:text="@string/btnCancelText" android:layout_width="80dp" android:layout_height="wrap_content"></Button> </LinearLayout></LinearLayout>
采用的是线性布局。运行起来就是最开始我贴的那张图。OK,我们先看一下OnCreate
final static String NAMESPACE = "http://tempuri.org/"; final static String METHOD_NAME = "CheckLogin"; final static String SOAP_ACTION = "http://tempuri.org/CheckLogin"; final static String URL = "http://10.0.2.2:2000/LoginService.asmx?wsdl"; EditText txtUserno; EditText txtPwd; Button btnLogin; Button btnCancel; CheckBox chkDisplay; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btnLogin = (Button) this.findViewById(R.id.btnLogin); btnCancel=(Button) this.findViewById(R.id.btnCancel); txtUserno = (EditText) this.findViewById(R.id.txtUserName); txtPwd = (EditText) this.findViewById(R.id.txtPwd); chkDisplay = (CheckBox) this.findViewById(R.id.chkDisplayPwd); btnLogin.setOnClickListener(new OnClickListener() { public void onClick(View v) { String userNo = txtUserno.getText().toString().trim(); String pwd = txtPwd.getText().toString().trim(); Login(userNo, pwd); } }); btnCancel.setOnClickListener(new OnClickListener() { public void onClick(View v) { txtUserno.setText(""); txtPwd.setText(""); } }); chkDisplay.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton cmpButton, boolean isChecked) { if (isChecked) { txtPwd .setTransformationMethod(HideReturnsTransformationMethod .getInstance()); } else { txtPwd.setTransformationMethod(PasswordTransformationMethod .getInstance()); } } }); }
在页面的最顶端声明了我们需要调用的webservice的信息,注意10.0.2.2是android的内置IP,这个是android访问你本地电脑时使用的IP。如果使用127.0.0.1的话那是在访问你的手机。在Oncreate方法里,我们给按钮注册了事件响应。登录和取消,我们还看到一个checkBox,他的作用是是否让密码明文显示。如果未勾选,如下左所示,否则如右
OK,看完checkBox我们看登录
public void Login(String userNo, String passWord) { if (!CheckUserInput(userNo, passWord)) { return; } SoapObject response = this.GetServerResponse(userNo, passWord); boolean isSuccess = Boolean.valueOf(response.getProperty("IsSuccess") .toString()); if (!isSuccess) { String failMsg = response.getProperty("FailMsg").toString(); new AlertDialog.Builder(this) .setTitle(R.string.WarningMsgTitle) .setMessage(failMsg) .setIcon(R.drawable.warning) .setPositiveButton("确定",null).show(); } else { Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putString("userNo", userNo); intent.putExtras(bundle); intent.setClass(main.this, index.class); startActivityForResult(intent, 0); finish(); } }
登录的时候会先checkInput。
private boolean CheckUserInput(String userNo, String passWord) { if (userNo.equals("")) { new AlertDialog.Builder(this).setTitle(R.string.WarningMsgTitle) .setMessage(R.string.UserNoIsEmpty) .setIcon(R.drawable.info) .setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialoginterface, int i) { txtUserno.requestFocus(); } }).show(); return false; } if (passWord.equals("")) { new AlertDialog.Builder(this).setTitle(R.string.WarningMsgTitle) .setMessage(R.string.UserPWdIsEmpty) .setIcon(R.drawable.info) .setPositiveButton( "确定", new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialoginterface, int i) { txtPwd.requestFocus(); } }).show(); return false; } return true; }
checkInput非常简单,如果是空的话弹出提示,如下
OK,如果输入的不是空,那么调用WebService,需要传递两个参数
看一下代码
private SoapObject GetServerResponse(String userNo, String passWord) { SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME); PropertyInfo pi = new PropertyInfo(); pi.setName("userNo"); pi.setType(String.class); pi.setValue(userNo); Request.addProperty(pi); pi = new PropertyInfo(); pi.setName("pwd"); pi.setType(String.class); pi.setValue(passWord); Request.addProperty(pi); SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope( SoapEnvelope.VER11); soapEnvelope.dotNet = true; soapEnvelope.setOutputSoapObject(Request); HttpTransportSE httpTS = new HttpTransportSE(URL); try { httpTS.call(SOAP_ACTION, soapEnvelope); } catch (IOException e) { // TODO Auto-generated catch block 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; }
在这里调用WebService并返回SoapObject对象,调用WebService不要忘记引用ksoap
如果没有的话,自己去下载一个。这里调用成功返回以后,如果IsSuccess为true的话,直接跳转至index,并将登陆成功的userNo传给index。如果登陆失败,弹出service端返回的提示信息。但悲剧的是我的真机报错,没有访问到webservice。后来我用手机连接了wlan,Ip地址也改了还是报错
电脑访问无线IP没有问题,如下
但是真机就是连不上,模拟器用10.0.2.2却可以正常访问。
后来查看了一下手机,尝试下面所有的ip都不行。
最后我查了一下电脑ip,使用172.18.73.39,结果调用成功。
调用成功了,哈哈
更多相关文章
- HTML5,js与Android(安卓)native通信
- Android(安卓)onTouchEvent, onClick及onLongClick的调用机制
- 关于使用Android(安卓)NDK编译ffmpeg
- 想抢先体验Android操作系统的魅力吗?那就使用Android(安卓)LiveCD
- 转!Android(安卓)onTouchEvent,onClick和onLongClick的调用机制
- Android学习——uses-sdk标签详解
- 箭头函数的基础使用
- NPM 和webpack 的基础使用
- Python list sort方法的具体使用