Android切近实战(一)

简介:

记得上篇文章我还在为使用哪种开发语言开发android而发愁,最近使用了一下C#开发android,感觉不是那么爽。查资料也不方便,于是我决定使用java开发,毕竟java我也是学过的,eclipse环境也不陌生。开始吧,天很冷,先上图

221701997.jpg

这张图我是从真机上截取下来的,这是一个登陆界面。用户输入用户名和密码后,验证,验证通过之后,跳转至另一个Activity。那么我目前采取的方式是Android调用.net WebService的方式。

OK,先看一下Service端。

222008451.jpg
很熟悉很简单的结构。我们简单看一下Service端的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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作真正的数据访问层。我一次性把所有表都映射进来了,并设置了他们之间的关联关系。

150001950.png

在这里需要说的是这个GetMessageByModuleAndName方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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()方法,其实在这里我们可以对代码进行优化,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private  static  List<ServiceMessage> _serviceMessageList;
         private  static  List<ServiceMessage> ServiceMessageList
         {
             get
             {
                 if  (_serviceMessageList ==  null )
                 {
                     _serviceMessageList = GetMessageList();
                     return  _serviceMessageList;
                 }
                 else
                 {
                     return  _serviceMessageList;
                 }
             }
         }

那么每次在获取的时候,会先判断_serviceMessageList有没有,如果有,就不再读取文件了。

我们来看一下这个配置文件

1
2
3
4
5
<? xml  version = "1.0"  encoding = "utf-8" ?>
< ServiceMessages >
   < Message  Module = "LoginModule"  Name = "PwdNotCorrect"  Content = "密码不正确!" ></ Message >
   < Message  Module = "LoginModule"  Name = "UserNotExists"  Content = "用户名不存在!" ></ Message >
</ ServiceMessages >

它对应的实体如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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端。完了之后我们部署一下

230437715.jpg

部署的时候需要注意如下

230534281.jpg

230552505.jpg


接下来我们看一下app端的开发

224421241.jpg

我们总共有两个Activity,一个是main,一个是index,main界面登成功跳转至index界面。

我们先看一下mai界面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<? 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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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,他的作用是是否让密码明文显示。如果未勾选,如下左所示,否则如右

230208396.jpg230309988.jpg

OK,看完checkBox我们看登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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非常简单,如果是空的话弹出提示,如下

231011783.jpg231029559.jpg

OK,如果输入的不是空,那么调用WebService,需要传递两个参数

231438392.jpg

看一下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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

231730297.jpg

如果没有的话,自己去下载一个。这里调用成功返回以后,如果IsSuccess为true的话,直接跳转至index,并将登陆成功的userNo传给index。如果登陆失败,弹出service端返回的提示信息。但悲剧的是我的真机报错,没有访问到webservice。后来我用手机连接了wlan,Ip地址也改了还是报错

000058489.jpg

电脑访问无线IP没有问题,如下

000215771.jpg

但是真机就是连不上,模拟器用10.0.2.2却可以正常访问。

150223923.png

后来查看了一下手机,尝试下面所有的ip都不行。

152147922.png

最后我查了一下电脑ip,使用172.18.73.39,结果调用成功。

152347314.png

调用成功了,哈哈

152515547.png 152849640.png



本文转自 BruceAndLee 51CTO博客,原文链接:http://blog.51cto.com/leelei/1345860,如需转载请自行联系原作者


相关文章
|
3月前
Android4.1.0实战教程---自动阅读小说
Android4.1.0实战教程---自动阅读小说
35 0
|
4月前
|
Android开发
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
77 0
|
4月前
|
JSON Java 定位技术
【Android App】GPS获取定位经纬度和根据经纬度获取详细地址讲解及实战(附源码和演示 超详细)
【Android App】GPS获取定位经纬度和根据经纬度获取详细地址讲解及实战(附源码和演示 超详细)
189 0
|
23天前
|
缓存 移动开发 Java
构建高效Android应用:内存优化实战指南
在移动开发领域,性能优化是提升用户体验的关键因素之一。特别是对于Android应用而言,由于设备和版本的多样性,内存管理成为开发者面临的一大挑战。本文将深入探讨Android内存优化的策略和技术,包括内存泄漏的诊断与解决、合理的数据结构选择、以及有效的资源释放机制。通过实际案例分析,我们旨在为开发者提供一套实用的内存优化工具和方法,以构建更加流畅和高效的Android应用。
|
2月前
|
算法 Java Android开发
安卓逆向 -- 实战某峰窝APP(静态分析)
安卓逆向 -- 实战某峰窝APP(静态分析)
22 0
|
2月前
|
网络协议 算法 Android开发
安卓逆向 -- 实战某峰窝APP(动态分析)
安卓逆向 -- 实战某峰窝APP(动态分析)
24 4
|
4月前
|
Android开发 Kotlin
Android实战演练(kotlin版),词汇记录APP
Android实战演练(kotlin版),词汇记录APP
37 0
|
4月前
|
Web App开发 JSON Android开发
【Android App】实战项目之仿微信的视频通话(附源码和演示 超详细必看)
【Android App】实战项目之仿微信的视频通话(附源码和演示 超详细必看)
78 0
|
4月前
|
Web App开发 Android开发 ice
【Android App】给App集成WebRTC实现视频发送和接受实战(附源码和演示 超详细)
【Android App】给App集成WebRTC实现视频发送和接受实战(附源码和演示 超详细)
80 1
|
4月前
|
算法 Android开发
【Android App】二维码的讲解及生成属于自己的二维码实战(附源码和演示 超详细必看)
【Android App】二维码的讲解及生成属于自己的二维码实战(附源码和演示 超详细必看)
73 0