Android切近實戰(一)

記得上篇文章我還在爲使用哪種開發語言開發android而發愁,最近使用了一下C#開發android,感覺不是那麼爽。查資料也不方便,於是我決定使用java開發,畢竟java我也是學過的,eclipse環境也不陌生。開始吧,天很冷,先上圖

221701997.jpg

這張圖我是從真機上截取下來的,這是一個登陸界面。用戶輸入用戶名和密碼後,驗證,驗證通過之後,跳轉至另一個Activity。那麼我目前採取的方式是Android調用.net WebService的方式。

OK,先看一下Service端。

222008451.jpg
很熟悉很簡單的結構。我們簡單看一下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作真正的數據訪問層。我一次性把所有表都映射進來了,並設置了他們之間的關聯關係。

150001950.png

在這裏需要說的是這個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端。完了之後我們部署一下

230437715.jpg

部署的時候需要注意如下

230534281.jpg

230552505.jpg


接下來我們看一下app端的開發

224421241.jpg

我們總共有兩個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,他的作用是是否讓密碼明文顯示。如果未勾選,如下左所示,否則如右

230208396.jpg230309988.jpg

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非常簡單,如果是空的話彈出提示,如下

231011783.jpg231029559.jpg

OK,如果輸入的不是空,那麼調用WebService,需要傳遞兩個參數

231438392.jpg

看一下代碼

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章