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,如需转载请自行联系原作者


相关文章
|
7天前
Android4.1.0实战教程---自动阅读小说
Android4.1.0实战教程---自动阅读小说
46 0
|
5天前
|
前端开发 Android开发
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
Android架构组件JetPack之DataBinding玩转MVVM开发实战(四)
|
5天前
|
Android开发
Android高级开发面试题以及笞案整理,实战解析
Android高级开发面试题以及笞案整理,实战解析
|
5天前
|
Android开发
Android Jetpack架构开发组件化应用实战,字节跳动+阿里+华为+腾讯等大厂Android面试题
Android Jetpack架构开发组件化应用实战,字节跳动+阿里+华为+腾讯等大厂Android面试题
|
6天前
|
Android开发
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
|
6天前
|
设计模式 Android开发 Java
实战案例,精选Android面试真题集锦
实战案例,精选Android面试真题集锦
|
7天前
|
缓存 Java Android开发
Android应用性能优化实战
【5月更文挑战第14天】 在竞争激烈的应用市场中,一个流畅、高效的应用能显著提升用户体验并增强用户黏性。本文深入探讨了针对安卓平台进行应用性能优化的策略与实践,从内存管理到多线程处理,再到布局渲染和网络请求的优化,旨在为开发者提供一套全面的优化工具箱。通过分析常见的性能瓶颈并结合最新的Android技术动态,我们不仅讨论理论,还将分享具体的代码示例和改进方法,帮助开发者在实际应用中实现性能提升。
|
7天前
|
编解码 缓存 监控
安卓应用性能优化实战
【5月更文挑战第14天】 在当今移动应用竞争激烈的市场中,一款应用的性能直接影响用户体验和留存率。特别是对于安卓平台,由于设备多样性和应用生态环境的复杂性,性能优化显得尤为重要。本文将深入探讨安卓应用的性能瓶颈,分析影响性能的关键因素,并通过具体的代码实践和工具使用,展示如何有效提升安卓应用的响应速度和流畅度。内容覆盖从UI渲染优化、内存管理到电池使用效率的多个方面,旨在为开发者提供一套实用的性能优化策略。
|
7天前
|
移动开发 API Android开发
Android应用性能优化实战
【4月更文挑战第28天】在移动开发领域,一个流畅的用户体验是至关重要的。对于Android开发者而言,应用的性能优化是一项既挑战性也极其重要的工作。本文将深入探讨Android应用性能优化的多个方面,包括内存管理、UI渲染、多线程处理以及电池效率等,旨在为开发者提供实用的性能提升策略和具体的实施步骤。通过分析常见的性能瓶颈,并结合最新的Android系统特性和工具,我们的目标是帮助读者打造更加高效、响应迅速的Android应用。
|
7天前
|
缓存 监控 Android开发
Android 应用性能优化实战
【4月更文挑战第27天】 在竞争激烈的移动应用市场中,性能优越的应用更能吸引和保留用户。针对Android平台,本文将深入探讨影响应用性能的关键因素,并提供一系列实用的优化策略。我们将从内存管理、UI渲染、多线程处理以及电池使用效率等方面入手,通过具体案例分析如何诊断常见问题,并给出相应的解决方案。文中所提技巧旨在帮助开发者构建更加流畅、高效的Android应用。
24 2