引言
本周我们主要进行进行页面设计与代码编写,在前两天的工作中我们主要进行了以下工作:
- 页面的初步设计与逻辑交互设计
- 客户端代码编写
- 后台代码编写
在这里,我对自己主要从事的工作,即APP端登录界面以及内部处理逻辑代码的编写,做一个详细的介绍。
在编写登录代码之前,我和王宁先定义了一些基类:
BaseActivity为Activity定义了一个基类,内部为setContentView设置了getLayoutId抽象函数,从而使得Activity可以快速设置layout。
BaseApplication重写了Application类,因为app启动率先调用Application的onCreate函数,故重写这个函数,在里面做一些全局初始化。
BaseFragment'为Fragment定义基类,原理与BaseActivity相似。
一、登录界面的编写:
根据之前的界面设计,登录界面如下所示。
登录界面由app logo作为大背景,使用手机号和密码进行登录,手机号和密码输入完毕后,点击登录按钮后,即可进行登录操作。
若没有账号,则点击下方的注册按钮,跳转到注册页面进行注册。
Android的界面布局文件是xml文件,android studio环境提供了图形化的布局文件编写,但考虑到该APP可能安装在不同屏幕的手机上,需要保证布局的灵活与精确性,所以主要还是采用手动编写代码的方式进行。
根据我的设计,中间的logo采用ImageView控件来实现,两个输入框采用EditText控件实现,三个按钮采用Button控件来实现,整体的布局控制选择纵向的LinearLayout,通过调整不同组件的layout_weight(即权重)属性,就可以控制组件的相对大小,可以自动适应不同尺寸的屏幕。整个界面的蓝色背景只要调整最上次LinearLayout的背景颜色就可以实现。
这一还有一个小技巧要特别说一下,两个输入框是带有图标的,而Android并没有自带的这种组件,所以我选择使用一个横向的LinearLayout,将一个ImageView和EditText放在一起,同时将该LinearLayout的背景设为绘制的椭圆,通过精细调整组件的尺寸,就可以达到理想的效果。
源代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/login_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/login_bg"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="270dp"
android:gravity="center_horizontal|bottom"
android:orientation="vertical"
android:padding="40dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="120dp"
android:src="@drawable/login_logo" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="56dp"
android:layout_marginRight="56dp"
android:background="@drawable/edittext_blue_bord_bg"
android:orientation="horizontal">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_margin="16dp"
android:src="@drawable/login_userid_icon" />
<EditText
android:id="@+id/loginAccountEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="16dp"
android:background="@null"
android:hint="手机号"
android:textColor="@color/black"
android:textColorHint="@color/text_hint_gray"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="56dp"
android:layout_marginRight="56dp"
android:layout_marginTop="16dp"
android:background="@drawable/edittext_blue_bord_bg"
android:orientation="horizontal">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_margin="16dp"
android:src="@drawable/login_password_icon" />
<EditText
android:id="@+id/loginPasswordEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="16dp"
android:background="@null"
android:hint="密码(6-16位英文和数字)"
android:textColor="@color/black"
android:textColorHint="@color/text_hint_gray"
android:textSize="16sp" />
</LinearLayout>
<Button
android:id="@+id/loginLoginButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="56dp"
android:layout_marginRight="56dp"
android:layout_marginTop="16dp"
android:background="@drawable/login_button_bg"
android:gravity="center"
android:onClick="login"
android:text="登陆"
android:textColor="@color/white"
android:textSize="16sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="56dp"
android:layout_marginRight="56dp"
android:layout_marginTop="16dp"
android:paddingBottom="16dp">
<Button
android:id="@+id/loginForgetButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@color/transparent"
android:gravity="center"
android:text="忘记密码"
android:textColor="@color/login_button_default_blue"
android:textSize="16sp" />
<Button
android:id="@+id/loginRegisterButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@color/transparent"
android:gravity="center"
android:onClick="goToRegister"
android:text="注册"
android:textColor="@color/login_button_default_blue"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
二、内部处理逻辑代码的编写:
在之前的详细设计中,已经完成了登录的详细设计。
伪代码如下所示:
1.检查网络是否可用,不可用跳转到9
2.检查账户输入是否合法,不合法跳转到9
3.检查密码输入是否合法,不合法跳转到9
4.建立链表,将账户和密码存入其中
5.调用网络工具类的相应接口,等待返回结果
6.判断返回结果是否成功,不成功跳转到9
7.验证返回的用户数据是否为空,为空跳转到9
8.登录成功,跳转到主界面
9.登录失败
UML的活动图如下所示:
以此为基础,编写的代码如下所示:
package com.example.sdu.myflag.activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.*;
import android.view.View.OnClickListener;
import com.example.sdu.myflag.R;
import com.example.sdu.myflag.base.BaseActivity;
import com.example.sdu.myflag.base.BaseApplication;
import com.example.sdu.myflag.util.BaseTools;
import com.example.sdu.myflag.util.NetUtil;
import com.example.sdu.myflag.util.NetUtil.*;
import org.json.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import okhttp3.Response;
/**
* Created by Administrator on 2016/8/17.
*/
public class LoginActivity extends BaseActivity {
private EditText accountEditText, passwordEditText;
private Button forgetButton;
private String account, password;
@Override
public int getLayoutId() {
return R.layout.activity_login;
}
@Override
public void afterCreate(Bundle savedInstanceState) {
//获取各组件id
accountEditText = (EditText) findViewById(R.id.loginAccountEditText);
passwordEditText = (EditText) findViewById(R.id.loginPasswordEditText);
forgetButton = (Button) findViewById(R.id.loginForgetButton);
setButtonListener();
}
public void goToRegister(View v) {
startNewActivity(RegisterActivity.class);
}
public void login(View v) {
if (getText()) {
List<Param> params = new LinkedList<Param>();
params.add(new Param("phone", account));
params.add(new Param("password", password));
LoginResult loginResult = new LoginResult();
try {
NetUtil.getResult(NetUtil.loginUrl, params, loginResult);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//为各个按钮设置监听器
private void setButtonListener() {
forgetButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
//获取各EditText中的值,并进行合法性校验,合法返回true
//不合法返回false,并用Toast进行提醒
private boolean getText() {
account = accountEditText.getText().toString();
password = passwordEditText.getText().toString();
if (!BaseTools.isNetworkAvailable(LoginActivity.this)) {
Toast.makeText(this, "当前网络不可用!", Toast.LENGTH_SHORT).show();
return false;
} else if (account.isEmpty()) {
Toast.makeText(this, "手机号不能为空!", Toast.LENGTH_SHORT).show();
return false;
} else if (password.isEmpty()) {
Toast.makeText(this, "密码不能为空!", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private class LoginResult implements CallBackForResult {
@Override
public void onFailure(final IOException e) {
LoginActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onSuccess(Response response) {
if (response.isSuccessful()) {
try {
JSONObject jsonObject = new JSONObject(response.body().string());
String user = jsonObject.getString("user");
if (user.equals("")) {
LoginActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, "用户名或密码错误", Toast.LENGTH_LONG).show();
}
});
} else {
JSONObject userJson = new JSONObject(user);
SharedPreferences preferences = BaseApplication.getInstance().getSharedPreferences("User", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("uid", userJson.getInt("uid") + "").apply();
editor.putString("phone", userJson.getString("phone")).apply();
editor.putString("nickname", userJson.getString("nickname")).apply();
editor.putString("information", userJson.getString("information")).apply();
editor.putString("email", userJson.getString("email")).apply();
editor.putString("password", password).apply();
LoginActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, "登陆成功", Toast.LENGTH_LONG).show();
}
});
startNewActivity(MainActivity.class);
LoginActivity.this.finish();
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
在我编写好登录代码,王宁编写好注册代码后,我们进行了代码互查和互测,我们采用白盒测试技术中的基本路径覆盖设计测试用例。针对不同的输入信息,设计了多组测试数据,然后再真机上对每一组数据进行实际测试,检查后台返回数据是否,直到登录注册界面测试运行无误。
总结
应该说,这两天代码的编写工作进行的比较顺利,这得益于前期做了良好的界面设计和详细设计,大大减少了编码的工作量,保证了工作进度。总体来说前两天的工作进度还是可以的,希望这周剩下的时间我能够完成好剩下的任务。