登录模块
- 数据库设计
如图所示创建了如上的数据库由于没有注册功能人为添加了两个用户:
数据库创建语句:
public static final String CREATE_task ="create table user ("
+ "id integer primary key autoincrement, "
+"remenberPassword text,"
+"autoLogin text,"
+ "username text, "
+ "password text"
+ ")";
public static final String CREATE_task2 ="create table Travel ("
+ "id integer primary key autoincrement, "
+ "travelName text, "
+ "content text,"
+ "traveldate date,"
+ "userID integer"
+ ")";
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_task);
db.execSQL(CREATE_task2);
}
与数据库对应创建了两个对应于两张表的数据库操作DBBean:代码如下:
- Travel表的TravelDBean
插入语句:
public long insert(TravelBean travel) {
ContentValues newValues =new ContentValues();
newValues.put("content", travel.getContent());
newValues.put("traveldate",travel.getTraveldate());
newValues.put("travelName",travel.getTravelName());
newValues.put("userID",travel.getUserID());
return db.insert(DB_Table, null, newValues);
}
根据用户名加载全部行程的语句,此处加载按时间排序进行加载:
public TravelBean[] LoadAllData(String Uername) {
Cursor result =db.query( DB_Table, new String[] {"id","travelName","content","traveldate","userID"}, “userID”+” = ”+Uername , null, null, null,"traveldate desc");
return ConvertToTravelBean(result);
}
根据返回的游标,将数据封装进对象语句:
private TravelBean[] ConvertToTravelBean(Cursor result) {
// TODO Auto-generated method stub
int resultCounts=result.getCount();
if(resultCounts==0||!result.moveToFirst()) {
return null;
}
TravelBean[] travel=new TravelBean[resultCounts];
for(int i=0;i<resultCounts;i++) {
travel[i]=new TravelBean();
travel[i].setContent(result.getString(result.getColumnIndex("content")));
travel[i].setTravelName(result.getString(result.getColumnIndex("travelName")));
travel[i].setTraveldate(result.getString(result.getColumnIndex("traveldate")));
travel[i].setUserID(result.getString(result.getColumnIndex("userID")));
travel[i].setID(result.getString(result.getColumnIndex("id")));
System.out.println(travel[i].getTravelName());
result.moveToNext();
}
return travel;
}
根据travel的ID号修改旅行名称、内容、时间语句:
public void updateOneData(String travelName,String content,String traveldate,String id) {
ContentValues updateValues=new ContentValues();
updateValues.put("content", content);
updateValues.put("travelName", travelName);
updateValues.put("traveldate", traveldate);
db.update(DB_Table, updateValues, "id"+" = " +id, null);
}
根据旅行的ID号删除一条旅行记录:
public long deleteOneData(String id) {
return db.delete(DB_Table, "id"+" ="+id, null);
}
Uer对应的UserDBBean
创建数据库,并返回一个SQLIteDatabse对象供给TravelDBean使用:
public SQLiteDatabase open() throws SQLiteException{
dbOpenhelper=new MyDatabaseHelper(context, DB_NAME, null, DB_VERSION);
try {
db=dbOpenhelper.getWritableDatabase();
return db;
}catch(SQLiteException e) {
db=dbOpenhelper.getReadableDatabase();
return db;
}
}
插入用户对象,注册功能为实现,但需要插入两个用户进行测试:
public long insert(UserBean user) {
ContentValues newValues =new ContentValues();
newValues.put("remenberPassword", user.getRemenberPassword());
newValues.put("password",user.getPassword());
newValues.put("username",user.getUsername());
newValues.put("autoLogin",user.getAutoLogin());
return db.insert(DB_Table, null, newValues);
}
根据用户名加载用户:
public UserBean queryByUsername(String username) {
UserBean userBean=null;
Cursor result =db.query( DB_Table, new String[] {"username","password","remenberPassword","autoLogin"}, "username"+" = '"+username+"'", null, null, null,null);
if(result.getCount()!=0) {
result.moveToFirst();
userBean=new UserBean();
userBean.setPassword(result.getString(1));
userBean.setAutoLogin(result.getString(3));
userBean.setRemenberPassword(result.getString(2));
userBean.setUsername(username);
}
return userBean;
}
根据用户名来更新记住密码、自动登陆的状态
public void updateOneData(String username,String remenberPassword,String autoLogin ) {
if(username!=null) {
ContentValues updateValues=new ContentValues();
updateValues.put("autoLogin", autoLogin);
updateValues.put("remenberPassword", remenberPassword);
db.update(DB_Table, updateValues, "username"+" = " +username, null);
}
else {
return;
}
}
两个用来封装数据的实体Bean,代码如下:
UserBean:
public class UserBean {
private String id="";
private String username="";
private String password="";
private String remenberPassword="";
private String autoLogin="";
public String getRemenberPassword() {
return remenberPassword;
}
public void setRemenberPassword(String remenberPassword) {
this.remenberPassword = remenberPassword;
}
public String getAutoLogin() {
return autoLogin;
}
public void setAutoLogin(String autoLogin) {
this.autoLogin = autoLogin;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
TravelBean:
public class TravelBean {
private String ID="";
private String travelName="";
private String content="";
private String traveldate="";
private String userID="";
public String getID() {
return ID;
}
public void setID(String iD) {
ID = iD;
}
public String getTravelName() {
return travelName;
}
public void setTravelName(String travelName) {
this.travelName = travelName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getTraveldate() {
return traveldate;
}
public void setTraveldate(String traveldate) {
this.traveldate = traveldate;
}
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
}
- 登录界面设计
登录界面 源代码
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="登录界面"
android:gravity="center"
android:textSize="30sp"
/>
<View android:layout_width="match_parent" android:layout_height="1dp"
android:background="@color/orange_main"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="32dp"
android:layout_marginRight="32dp"
android:layout_marginTop="120dp">
<ImageView
android:id="@+id/img_account"
android:layout_width="19dp"
android:layout_height="20dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="4dp"
android:layout_marginLeft="4dp"
android:scaleType="fitXY"
android:src="@drawable/icon_login_account"/>
<EditText
android:id="@+id/et_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="center"
android:layout_marginBottom="4dp"
android:layout_marginLeft="12dp"
android:layout_toRightOf="@+id/img_account"
android:background="@null"
android:hint="@string/account"
android:maxLines="1"
android:textColor="@android:color/black"
android:textColorHint="@color/tv_gray_deep"
android:textSize="14dp"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_marginLeft="12dp"
android:layout_toRightOf="@+id/img_account"
android:background="@color/orange_light"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="32dp"
android:layout_marginRight="32dp">
<ImageView
android:id="@+id/img_pw"
android:layout_width="18dp"
android:layout_height="20dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="4dp"
android:layout_marginLeft="4dp"
android:scaleType="fitXY"
android:src="@drawable/icon_login_pw"/>
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="center"
android:layout_marginBottom="4dp"
android:layout_marginLeft="12dp"
android:layout_toRightOf="@+id/img_pw"
android:background="@null"
android:hint="@string/password"
android:inputType="textPassword"
android:maxLines="1"
android:textColor="@android:color/black"
android:textColorHint="@color/tv_gray_deep"
android:textSize="14dp"/>
<ImageView
android:id="@+id/iv_see_password"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/image_password_bg"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:scaleType="fitXY"
/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_marginLeft="12dp"
android:layout_toRightOf="@+id/img_pw"
android:background="@color/orange_light"/>
</RelativeLayout>
<CheckBox
android:id="@+id/checkBox_password"
android:padding="10dp"
android:textSize="14dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="@string/check_password"
android:textColor="@color/top_bar_normal_bg" android:checked="false"/>
<CheckBox
android:id="@+id/checkBox_login"
android:padding="10dp"
android:textSize="14dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="@string/check_login"
android:textColor="@color/top_bar_normal_bg" android:checked="false"/>
登录界面功能
登录界面可隐藏显示密码:
实现代码:首先构建一个选择器,选择器代码如下:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/icon_see_pass" android:state_selected="false"/>
<item android:drawable="@drawable/icon_nosee_pass" android:state_selected="true"/>
</selector>
然后在Login.xml文件中调用该选择器:
<ImageView
android:id="@+id/iv_see_password"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/image_password_bg"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:scaleType="fitXY" />
最后通过设置该选择器控件的点击事件,来达到显示密码,与不显示密码,此时要更换图片的状态,以及设置密码框的 setInputType类型,来使密码可见。具体代码如下:
if (iv_see_password.isSelected()) {
iv_see_password.setSelected(false);
//密码不可见
et_password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
} else {
iv_see_password.setSelected(true);
//密码可见
et_password.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
}
登录界面可记住密码、自动登陆:
由以上两张图片登录成功后注销登陆回来仍然显示当前密码:
由两张图片用户选择自动登陆,登录之后,退出APP,在进去自动登陆。若注销,则自动登陆状态自动取消,方便用户更换账号。
输入密码错悟提示如上图所示:
实现代码思想如下:
我点击登陆后,会向数据库更新用户的记下密码、自动登陆的状态,并且将当前用户的账号用SharedPreferences类更新在xml配置文件(保存上一次登陆的账号)中,用户登陆之前从数据库中根据根xml配置文件中保存的用户账号把用户所有信息加载出来,并封装在User对象中,我根据此User的记下密码、自动登陆的状态,做出相应的处理;首先将账号加载到用户控件,然后若记下密码我就将密码显示到密码控件上,若是自动登陆,那么直接进行Login()登陆方法。具体代码如下:
查找上一次加载的用户,并从数据库中将此用户所有信息获取。
SharedPreferencesUtils helper = new SharedPreferencesUtils(this, "setting");
String lastLoginUserName = helper.getString("name");
System.out.println("lastLoginUserName"+lastLoginUserName);
user= userBean.queryByUsername(lastLoginUserName);
验证该用户记住密码、自动登陆的状态:
//判断是否记住密码
if (remenberPassword()) {
checkBox_password.setChecked(true);//勾选记住密码
setTextNameAndPassword();//把密码和账号输入到输入框中
} else {
setTextName();//把用户账号放到输入账号的输入框中
}
//判断是否自动登录
if (autoLogin()) {
checkBox_login.setChecked(true);
login();//去登录就可以
}
判断记住密码方法代码如下:
private boolean remenberPassword() {
if(user.getRemenberPassword().equals("ture"))
return true;
else
return false;
}
将密码以及账号更新UI界面,代码如下:
public void setTextNameAndPassword() {
UserBean user1=userBean.queryByUsername(user.getUsername());
if(user1!=null) {
et_name.setText("" +user1.getUsername());
et_password.setText("" + user1.getPassword());
}
}
只用账户更新UI界面,代码如下:
public void setTextName() {
UserBean user1=userBean.queryByUsername(user.getUsername());
if(user1!=null) {
et_name.setText("" + user1.getUsername());
}
}
判断用户的自动登陆状态,代码如下:
private boolean autoLogin() {
//获取SharedPreferences对象,使用自定义类的方法来获取对象
if(user!=null) {
if(user.getAutoLogin().equals("true")) {
return true;
}
}
return false;
}
重写记住密码、与自动登陆的状态改变监听函数:做到,如选择自动登陆,那么记住密码应自动被勾选,如果取消记住密码,那么自动登陆也将自动取消。重写OnCheckedChangeListener函数:具体代码如下:
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView == checkBox_password) { //记住密码选框发生改变时
if (!isChecked) { //如果取消“记住密码”,那么同样取消自动登陆
checkBox_login.setChecked(false);
}
} else if (buttonView == checkBox_login) { //自动登陆选框发生改变时
if (isChecked) { //如果选择“自动登录”,那么同样选中“记住密码”
checkBox_password.setChecked(true);
}
}
}
登录成功获取失败的消息提示,代码如下:
public void showToast(final String msg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
}
自动登录部分,先验证账号密码是不是为空,在进行登陆。若为空消息提示登陆失败。
若不为空且校验成功,则将进行页面跳转,并将用户名带过去。此处因为不涉及更新UI但是要访问数据库,就创建了一个子线程处理登录模块。具体代码如下:
private void login() {
//先做一些基本的判断,比如输入的用户命为空,密码为空,若是直接返回提示错误
if (et_name.getText().toString().trim().isEmpty()){
showToast("你输入的账号为空!");
return;
}
if (et_password.getText().toString().trim().isEmpty()){
showToast("你输入的密码为空!");
return;
}
Thread loginRunnable = new Thread() {
@Override
public void run() {
super.run();
mLoginBtn.setClickable(false);//点击登录后,设置登录按钮不可点击状态
//睡眠2秒
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
user= userBean.queryByUsername(et_name.getText().toString().trim());
//判断账号和密码
if (et_name.getText().toString().trim().equals(user.getUsername()) &&
et_password.getText().toString().trim().equals(user.getPassword())) {
showToast("登录成功");
loadCheckBoxState();//记录下当前用户记住密码和自动登录的状态;
SharedPreferencesUtils helper = new SharedPreferencesUtils(LoginActivity.this, "setting");
helper.putValues(new SharedPreferencesUtils.ContentValue("name", et_name.getText().toString().trim()));
//将上一次登陆人的账号存入xml文件
Intent intent=new Intent(LoginActivity.this, LoginAfterActivity.class);
intent.putExtra("username", et_name.getText().toString().trim());
startActivity(intent);
finish();//关闭页面
} else {
System.out.println("username"+user.getUsername());
System.out.println("password"+user.getPassword());
showToast("输入的登录账号或密码不正确");
}
mLoginBtn.setClickable(true); //这里解放登录按钮,设置为可以点击
}
};
loginRunnable.start();
}
行程界面模块
- 行程界面就一个自定义标题组件,与一个ListView组件,具体代码如下:
<?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:orientation="vertical" >
<include
layout="@layout/title_travel"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</include>
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#dd430b"
>
</ListView>
</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:orientation="horizontal" >
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="行程安排"
android:textColor="@color/black_translucent"
android:textSize="30dp"
android:gravity="center"
android:textAlignment="center"/>
</LinearLayout>
- 行程界面功能实现:截图
登录之后,按下”注销“返回登陆界面。
添加完条记录,点击添加出来一跳添加框,填好信息点击”保存“如下图按时间最大往低排序显示,如下图所示:
选中最后一条信息进行删除,之后,如上图显示:下面进行修改操作:将”baixue“的行程内容更改为”chifan“:
从上图看到数据库中数据已经改变。
- 注销功能代码如下:
backLogin.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//更新用户自动登录的状态人为设为false
userBean.updateOneData(username, "ture", "false");
//创建记住密码和自动登录是默认不选,密码为空
startActivity(new Intent(LoginAfterActivity.this, LoginActivity.class));
}
});
2. 增加行程的功能代码主要是增加一行TableRow组件,里面内嵌三个EditText组件和一个保存按钮组件,保存按钮实现,点击保存那么,将数据插入到数据库,将此组件从TableRowLsit链表中删除,从数据库重新加载全部数据更新UI界面:
addTravel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
clear();
TableRow tableRow=new TableRow(LoginAfterActivity.this);
tableRow.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
final MyEditText et1=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
final MyEditText et2=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
final MyEditText et3=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
tableRow.addView(et1);
tableRow.addView(et2);
tableRow.addView(et3);
final TravelBean travel=new TravelBean();
Button save=new Button(LoginAfterActivity.this);
save.setText("保存");
tableRow.addView(save);
tableRowList.add(2,tableRow);
save.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
travel.setUserID(username);
travel.setTravelName(et1.getText().toString());
travel.setContent(et2.getText().toString());
travel.setTraveldate(et3.getText().toString());
System.out.println("我被触发了");
travelDB.insert(travel);
tableRowList.remove(2);
queryAll();
}
});
/*updateButtonList.add(update);*/
queryAll();
}
});
queryAll();
System.out.println("列表长度为:"+tableRowList.size());
}
3. 加载所有数据更新UI界面,若有数据那么将数据加载到界面,并且动态创建删除、修改按钮,并注册监听事件;删除按钮:从数据库中删除该条记录,并回调”加载全部函数“更新界面。修改按钮:根据记录ID号,对该行程记录进行更新。具体代码如下
public void queryAll() {
/*lv.removeAllViews();*/
if(!firstLogin)
clear();//清除ListView原来的组件
firstLogin=false;
final TravelBean[] sf= travelDB.LoadAllData(username);
/*TextView tvNew=new TextView(this);*/
/*tvNew.setText("没有数据");*/
if(sf!=null) {
for( int i=0;i<sf.length;i++) {
System.out.println("共有:"+i);
/*"ID:"+sf[i].getId()+*/
TableRow tr=new TableRow(this);
final MyEditText et1=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
et1.setText(" "+sf[i].getTravelName());
final MyEditText et2=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
et2.setText(sf[i].getContent());
final MyEditText et3=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
et3.setText(sf[i].getTraveldate());
Button update=new Button(this);
update.setText("修改");
final TravelBean sfman=sf[i];
final String id=sf[i].getID();
update.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
travelDB.updateOneData(et1.getText().toString(),et2.getText().toString(),et3.getText().toString(),id);
}
});
/*updateButtonList.add(update);*/
Button delete=new Button(this);
delete.setText("删除");
delete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
travelDB.deleteOneData(sfman.getID());
queryAll();
}
});
tr.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
tr.addView(et1);
tr.addView(et2);
tr.addView(et3);
tr.addView(update);
tr.addView(delete);
tableRowList.add(tr);
}
}
mAdapter.setTableRowList1(tableRowList);
//清空ListView链表
/*mAdapter.setTableRowList(tableRowList);*/
lv.setAdapter(mAdapter);
}
4. 根据屏幕大小调整动态创建的组件的宽度,具体代码如下:
获取当前屏幕宽度:
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
ScreenWidth = dm.widthPixels; // 屏幕宽度(dp)
ScreenHeight = dm.heightPixels;// 屏幕高度(dp)
对创建的组件宽度进行设置:
text1.setWidth((int)(0.25*ScreenWidth));
Text2.setWidth((int)(0.25*ScreenWidth));
Text3.setWidth((int)(0.25*ScreenWidth));
Text4.setWidth((int)(0.25*ScreenWidth));
final MyEditText et1=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
final MyEditText et2=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
final MyEditText et3=new MyEditText(LoginAfterActivity.this,(int)(0.25*ScreenWidth));
清除TableRowList中的除注销登陆、增加行程、和标题栏之外的所有TableRow组件。
public void clear() {
if(tableRowList.size()!=0&&tableRowList!=null) {
for(int i=0;i<tableRowList.size();i++) {
if(tableRowList.get(i).getChildCount()==5) {
tableRowList.remove(i);
i--;
}
}
}
}