写在最前面的话:有同学直接复制我的代码,可是需要复制的太多,觉得Gradle那些文件和自己的都差不多,就不复制了,结果运行报错,来找我,我能说啥?这些代码都是我挨个写注释,挨个复制到CSDN的,你想运行出来效果,就不要怕费力气,把我让你复制的都复制一下,我是个实用主义的人,不需要复制的我是不会给你的。尽管这篇文章很长,但是我觉得这是学习开发必走的路。我之所以没有上传一个压缩包,是想让你们通过挨个复制,来了解一下Android开发的结构,你如果耐不住性子,那么,不好意思,请找个空气新鲜的地方深呼吸,然后回来强迫自己耐住性子。
记于2018/6/24 23:45
--------------------------------------------------------------------------------------------------------------------------------
忙着敲代码,忙着忙着就忘了吃中午饭了,两点半了才想起来,下不为例!
这一篇我写的是用Android实现登录、注册、数据库操作的相关内容。
先放最终效果图:
如果你不想看我胡扯只要代码,请直接跳到文字下面,先声明一下我的AndroidStudio的版本是:
是时候写正文了!
首先,当我们用AndroidStudio运行写好的Android程序的时候,也就是说,当按下那个绿色的小三角,启动小手机的时候,整个AndroidStudio会发生什么事情?这件事重要到,不搞清楚就学不会Android编程的地步。
没错,就是你看到的这两个图标,折磨你到半死不活的两个玩意。
当你熬到深夜两点,拖着疲惫的身躯敲完最后一行代码,颤颤巍巍的右手握着鼠标,眯瞪着双眼瞄准绿色的小三角,用尽平生最后一丝力气狠狠地单击一下鼠标左键 ,然后整个人葛优瘫在键盘上等待着它的运行,它到底发生了什么事情?这一切的背后,是人性的扭曲还是道德的沦丧?啊呸,重来。这一切的背后,是怎样的逻辑结构和运行原理?
注:本文中的“它”指代“AndroidStudio”
我尽我最大的努力来阐释一下我对此过程的拙见。
首先看一下我这个Android程序的三级目录
我已经标注好顺序了 0 → 1 → 2 → 3 → 4 总共5步
步骤 0 :编译,具体Gradle是个啥,我也不清楚,我只知道Android是用Gradle进行编译的,编译的过程它会
一、检查Gradle自身程序是否可用或版本是否最新
二、启动各种我们桌面上看不见的程序,如果我没猜错的话,Gradle和Java、Python都差不多,大概就是一些java.exe、javac.exe之类的
三、匹配各种依赖项,存在的检查完整性,不存在的去指定网站下载
步骤 1 :解析注册XML,AndroidManifest.xml在Android中的作用和Windows中的注册表类似,每个Activity.java都需要去注册,而且里面有MAIN和LAUNCH设置,MAIN是:主要、入口的意思;LAUNCH是:启动、加载的意思。也就是说,AndroidManifest.xml是个导游,告诉AndroidStudio从哪开始运行,都有什么大致内容。
步骤 2 :运行Activity,所谓Activity 翻译为 :活动、界面 一个Activity就是一个运行界面,AndroidStudio会启动在AndroidManifest.xml中被设置为 MAIN和LAUNCH 的Activity。首页启动之后,就是各个Activity之间的跳转通信了。
步骤 3 :解析布局XML,在每个Activity创建(onCreate)时都会加载自己的xml布局文件,这些xml布局文件定义了对应Activity长什么样子。
步骤 4: 解析完布局XML后,每个Activity的模样就确定了,然后就会返回Activity中执行类似响应点击、滑动之类的操作的代码
GameOver ! ! Talk is cheap,Show me your code.我把代码按照我上面发的目录树的顺序粘贴一下。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.justloginregistertest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".loginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".RegisterActivity"></activity>
<activity android:name=".MainActivity"></activity>
</application>
</manifest>
Code.java
package com.example.justloginregistertest;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import java.util.Random;
/**
* Created by littlecurl 2018/6/24
*/
public class Code {
/**
* 随机数数组
* 去除了易混淆的 数字 0 和 字母 o O
* 数字 1 和 字母 i I l L
* 数字 6 和 字母 b
* 数字 9 和 字母 q
* 字母 c C 和 G
* 字母 t (经常和随机线混在一起看不清)
*/
private static final char[] CHARS = {
'2', '3', '4', '5', '7', '8',
'a', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm',
'n', 'p', 'r', 's', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'D', 'E', 'F', 'H', 'J', 'K', 'M',
'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
private static Code bmpCode;
public static Code getInstance() {
if(bmpCode == null)
bmpCode = new Code();
return bmpCode;
}
//default settings
//验证码默认随机数的个数
private static final int DEFAULT_CODE_LENGTH = 4;
//默认字体大小
private static final int DEFAULT_FONT_SIZE = 25;
//默认线条的条数
private static final int DEFAULT_LINE_NUMBER = 5;
//padding值
private static final int BASE_PADDING_LEFT = 10, RANGE_PADDING_LEFT = 15, BASE_PADDING_TOP = 15, RANGE_PADDING_TOP = 20;
//验证码的默认宽高
private static final int DEFAULT_WIDTH = 100, DEFAULT_HEIGHT = 40;
//settings decided by the layout xml
//canvas width and height
private int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT;
//random word space and pading_top
private int base_padding_left = BASE_PADDING_LEFT, range_padding_left = RANGE_PADDING_LEFT,
base_padding_top = BASE_PADDING_TOP, range_padding_top = RANGE_PADDING_TOP;
//number of chars, lines; font size
private int codeLength = DEFAULT_CODE_LENGTH, line_number = DEFAULT_LINE_NUMBER, font_size = DEFAULT_FONT_SIZE;
//variables
private String code;
private int padding_left, padding_top;
private Random random = new Random();
//验证码图片
public Bitmap createBitmap() {
padding_left = 0;
Bitmap bp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bp);
code = createCode();
c.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTextSize(font_size);
//画验证码
for (int i = 0; i < code.length(); i++) {
randomTextStyle(paint);
randomPadding();
c.drawText(code.charAt(i) + "", padding_left, padding_top, paint);
}
//画线条
for (int i = 0; i < line_number; i++) {
drawLine(c, paint);
}
c.save( Canvas.ALL_SAVE_FLAG );//保存
c.restore();//
return bp;
}
public String getCode() {
return code;
}
//生成验证码
private String createCode() {
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < codeLength; i++) {
buffer.append(CHARS[random.nextInt(CHARS.length)]);
}
return buffer.toString();
}
//画干扰线
private void drawLine(Canvas canvas, Paint paint) {
int color = randomColor();
int startX = random.nextInt(width);
int startY = random.nextInt(height);
int stopX = random.nextInt(width);
int stopY = random.nextInt(height);
paint.setStrokeWidth(1);
paint.setColor(color);
canvas.drawLine(startX, startY, stopX, stopY, paint);
}
//生成随机颜色
private int randomColor() {
return randomColor(1);
}
private int randomColor(int rate) {
int red = random.nextInt(256) / rate;
int green = random.nextInt(256) / rate;
int blue = random.nextInt(256) / rate;
return Color.rgb(red, green, blue);
}
//随机生成文字样式,颜色,粗细,倾斜度
private void randomTextStyle(Paint paint) {
int color = randomColor();
paint.setColor(color);
paint.setFakeBoldText(random.nextBoolean()); //true为粗体,false为非粗体
float skewX = random.nextInt(11) / 10;
skewX = random.nextBoolean() ? skewX : -skewX;
paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
//paint.setUnderlineText(true); //true为下划线,false为非下划线
//paint.setStrikeThruText(true); //true为删除线,false为非删除线
}
//随机生成padding值
private void randomPadding() {
padding_left += base_padding_left + random.nextInt(range_padding_left);
padding_top = base_padding_top + random.nextInt(range_padding_top);
}
}
DBOpenHelper.java
package com.example.justloginregistertest;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
/**
* Created by littlecurl 2018/6/24
*/
public class DBOpenHelper extends SQLiteOpenHelper {
/**
* 声明一个AndroidSDK自带的数据库变量db
*/
private SQLiteDatabase db;
/**
* 写一个这个类的构造函数,参数为上下文context,所谓上下文就是这个类所在包的路径
* 指明上下文,数据库名,工厂默认空值,版本号默认从1开始
* super(context,"db_test",null,1);
* 把数据库设置成可写入状态,除非内存已满,那时候会自动设置为只读模式
* 不过,以现如今的内存容量,估计一辈子也见不到几次内存占满的状态
* db = getReadableDatabase();
*/
public DBOpenHelper(Context context){
super(context,"db_test",null,1);
db = getReadableDatabase();
}
/**
* 重写两个必须要重写的方法,因为class DBOpenHelper extends SQLiteOpenHelper
* 而这两个方法是 abstract 类 SQLiteOpenHelper 中声明的 abstract 方法
* 所以必须在子类 DBOpenHelper 中重写 abstract 方法
* 想想也是,为啥规定这么死必须重写?
* 因为,一个数据库表,首先是要被创建的,然后免不了是要进行增删改操作的
* 所以就有onCreate()、onUpgrade()两个方法
* @param db
*/
@Override
public void onCreate(SQLiteDatabase db){
db.execSQL("CREATE TABLE IF NOT EXISTS user(" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT," +
"name TEXT," +
"password TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
db.execSQL("DROP TABLE IF EXISTS user");
onCreate(db);
}
/**
* 接下来写自定义的增删改查方法
* 这些方法,写在这里归写在这里,以后不一定都用
* add()
* delete()
* update()
* getAllData()
*/
public void add(String name,String password){
db.execSQL("INSERT INTO user (name,password) VALUES(?,?)",new Object[]{name,password});
}
public void delete(String name,String password){
db.execSQL("DELETE FROM user WHERE name = AND password ="+name+password);
}
public void updata(String password){
db.execSQL("UPDATE user SET password = ?",new Object[]{password});
}
/**
* 前三个没啥说的,都是一套的看懂一个其他的都能懂了
* 下面重点说一下查询表user全部内容的方法
* 我们查询出来的内容,需要有个容器存放,以供使用,
* 所以定义了一个ArrayList类的list
* 有了容器,接下来就该从表中查询数据了,
* 这里使用游标Cursor,这就是数据库的功底了,
* 在Android中我就不细说了,因为我数据库功底也不是很厚,
* 但我知道,如果需要用Cursor的话,第一个参数:"表名",中间5个:null,
* 最后是查询出来内容的排序方式:"name DESC"
* 游标定义好了,接下来写一个while循环,让游标从表头游到表尾
* 在游的过程中把游出来的数据存放到list容器中
* @return
*/
public ArrayList<User> getAllData(){
ArrayList<User> list = new ArrayList<User>();
Cursor cursor = db.query("user",null,null,null,null,null,"name DESC");
while(cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex("name"));
String password = cursor.getString(cursor.getColumnIndex("password"));
list.add(new User(name,password));
}
return list;
}
}
loginActivity.java
package com.example.justloginregistertest;
/**
* 纯粹实现登录注册功能,其它功能都被注释掉了
* 起作用的代码(连带着packag、import算上) 共 73 行
* 不多吧?
*/
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
/**
* Created by littlecurl 2018/6/24
*/
public class loginActivity extends AppCompatActivity {
/**
* 声明自己写的 DBOpenHelper 对象
* DBOpenHelper(extends SQLiteOpenHelper) 主要用来
* 创建数据表
* 然后再进行数据表的增、删、改、查操作
*/
private DBOpenHelper mDBOpenHelper;
/**
*创建 Activity 时先来重写 onCreate() 方法
* 保存实例状态
* super.onCreate(savedInstanceState);
* 设置视图内容的配置文件
* setContentView(R.layout.activity_login);
* 上面这行代码真正实现了把视图层 View 也就是 layout 的内容放到 Activity 中进行显示
* 将开源库ButterKnife应用到此上下文,这个开源库的规定用法
* ButterKnife.bind(this);
* 实例化 DBOpenHelper,待会进行登录验证的时候要用来进行数据查询
* mDBOpenHelper = new DBOpenHelper(this);
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
mDBOpenHelper = new DBOpenHelper(this);
}
/**
* onCreae()中大的布局已经摆放好了,接下来就该把layout里的东西
* 声明、实例化对象然后有行为的赋予其行为
* 这样就可以把视图层View也就是layout 与 控制层 Java 结合起来了
* <p>
* 这里使用注解的方式注入View,可以不再写findViewById了
* 我认为这样的方式比以前的方式好理解
* 比如说,以前声明并实例化一个 Button 是这样的代码:
* Button button1 = (Button)findViewById(R.id.button1);
* <p>
* 用注解的方式是这样的代码(两行代码):
* @BindView(R.id.button1)
* Button button1;
* <p>
* 这个Button的例子代码有点短,还不能说明问题,
* 我直接上个长代码吧:
* ImageView mIvLoginactivityBack = (ImageView)findViewById(R.id.iv_loginactivity_back);
* <p>
* 这样的长代码看的很费劲,可以用注解的方式等价代换成短代码的格式(两行代码):
* @BindView(R.id.iv_loginactivity_back)
* ImageView mIvLoginactivityBack;
* <p>
* 直接按着句子读就能理解了
* 绑定视图(资源id号是iv_loginactivity_back)
* 实例化ImageView 为 mIvLoginactivityBack
* <p>
* 成功声明并实例化一个对象,是不是注解的方式更简单易懂明了?
* 是不是?是不是?
* 当然,这么好的方法不是让你说用就用的
* 你需要拥抱一下开源库,阅读这两篇文章:
* https://www.sogou.com/link?url=DOb0bgH2eKh1ibpaMGjuy6YnbQPc3cuKC5mI2Qw8RgpomuBEhdSpHkUUZED5fr2Oc1DxBW0w__gl8OT6rYpPtg..
* https://github.com/JakeWharton/butterknife
* 读完你就会用了
* 怎么样?和我一起拥抱开源吧。
* 接下来敲代码
*/
// @BindView(R.id.iv_loginactivity_back)
// ImageView mIvLoginactivityBack;
@BindView(R.id.tv_loginactivity_register)
TextView mTvLoginactivityRegister;
@BindView(R.id.rl_loginactivity_top)
RelativeLayout mRlLoginactivityTop;
@BindView(R.id.et_loginactivity_username)
EditText mEtLoginactivityUsername;
@BindView(R.id.et_loginactivity_password)
EditText mEtLoginactivityPassword;
@BindView(R.id.ll_loginactivity_two)
LinearLayout mLlLoginactivityTwo;
// @BindView(R.id.tv_loginactivity_forget)
// TextView mTvLoginactivityForget;
// @BindView(R.id.tv_loginactivity_check)
// TextView mTvLoginactivityCheck;
// @BindView(R.id.tv_loginactivity_else)
// TextView mBtLoginactivityElse;
/**
* 都声明并实例化之后
* 需要为实例化的这些对象设置行为
* 在写 activity_login.xml 的时候
* 有些控件 Button、ImageView、TextView 都有一个属性:
* android:onClick="onClick"
* 其实这也是开源库ButterKnife中的东西
* 人家不仅解决了findViewById代码过长的问题,
* 还解决了setOnClickListener(new View.OnClickListener() {}代码过长的问题
* 让你不再写findViewById、setOnClickListener
* 所以人家叫 ButterKnife 黄油刀
* 就是专门管切割长代码的
* Talk is cheap, show me your code.
*/
@OnClick({
// R.id.iv_loginactivity_back,
R.id.tv_loginactivity_register,
//R.id.tv_loginactivity_forget,
//R.id.tv_loginactivity_check,
R.id.bt_loginactivity_login,
//R.id.tv_loginactivity_else
})
public void onClick(View view) {
switch (view.getId()) {
//case R.id.iv_loginactivity_back:
//TODO 返回箭头功能
// finish();//销毁此Activity
// break;
case R.id.tv_loginactivity_register:
//TODO 注册界面跳转
startActivity(new Intent(this, RegisterActivity.class));
finish();
break;
//case R.id.tv_loginactivity_forget: //忘记密码
//TODO 忘记密码操作界面跳转
// startActivity(new Intent(this, FindPasswordActivity.class));
// break;
//case R.id.tv_loginactivity_check: //短信验证码登录
// TODO 短信验证码登录界面跳转
// startActivity(new Intent(this, MessageLoginActivity.class));
// finish();
// break;
/**
* 登录验证:
*
* 从EditText的对象上获取文本编辑框输入的数据,并把左右两边的空格去掉
* String name = mEtLoginactivityUsername.getText().toString().trim();
* String password = mEtLoginactivityPassword.getText().toString().trim();
* 进行匹配验证,先判断一下用户名密码是否为空,
* if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(password))
* 再进而for循环判断是否与数据库中的数据相匹配
* if (name.equals(user.getName()) && password.equals(user.getPassword()))
* 一旦匹配,立即将match = true;break;
* 否则 一直匹配到结束 match = false;
*
* 登录成功之后,进行页面跳转:
*
* Intent intent = new Intent(this, MainActivity.class);
* startActivity(intent);
* finish();//销毁此Activity
*/
case R.id.bt_loginactivity_login:
String name = mEtLoginactivityUsername.getText().toString().trim();
String password = mEtLoginactivityPassword.getText().toString().trim();
if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(password)) {
ArrayList<User> data = mDBOpenHelper.getAllData();
boolean match = false;
for(int i=0;i<data.size();i++) {
User user = data.get(i);
if (name.equals(user.getName()) && password.equals(user.getPassword())){
match = true;
break;
}else{
match = false;
}
}
if (match) {
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();//销毁此Activity
}else {
Toast.makeText(this, "用户名或密码不正确,请重新输入", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "请输入你的用户名或密码", Toast.LENGTH_SHORT).show();
}
break;
//case R.id.tv_loginactivity_else:
//TODO 第三方登录,时间有限,未实现
// break;
}
}
}
MainActivity.java
package com.example.justloginregistertest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
/**
* Created by littlecurl 2018/6/24
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 一定 一定 一定记得加这句,而且是固定位置,在setContentView()之下
* 否则无论写的什么逻辑 都不会在Activity中起作用
*/
ButterKnife.bind(this);
}
@BindView(R.id.bt_main_logout)
Button mBtMainLogout;
@OnClick({
R.id.bt_main_logout
})
public void onClick(View view){
switch (view.getId()) {
case R.id.bt_main_logout:
Intent intent = new Intent(this, loginActivity.class);
startActivity(intent);
finish();
break;
}
}
}
RegisterAcitvity.java
package com.example.justloginregistertest;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
/**
* Created by littlecurl 2018/6/24
*/
public class RegisterActivity extends AppCompatActivity{
private String realCode;
private DBOpenHelper mDBOpenHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
ButterKnife.bind(this);
mDBOpenHelper = new DBOpenHelper(this);
//将验证码用图片的形式显示出来
mIvRegisteractivityShowcode.setImageBitmap(Code.getInstance().createBitmap());
realCode = Code.getInstance().getCode().toLowerCase();
}
@BindView(R.id.rl_registeractivity_top)
RelativeLayout mRlRegisteractivityTop;
@BindView(R.id.iv_registeractivity_back)
ImageView mIvRegisteractivityBack;
@BindView(R.id.ll_registeractivity_body)
LinearLayout mLlRegisteractivityBody;
@BindView(R.id.et_registeractivity_username)
EditText mEtRegisteractivityUsername;
@BindView(R.id.et_registeractivity_password1)
EditText mEtRegisteractivityPassword1;
@BindView(R.id.et_registeractivity_password2)
EditText mEtRegisteractivityPassword2;
@BindView(R.id.et_registeractivity_phoneCodes)
EditText mEtRegisteractivityPhonecodes;
@BindView(R.id.iv_registeractivity_showCode)
ImageView mIvRegisteractivityShowcode;
@BindView(R.id.rl_registeractivity_bottom)
RelativeLayout mRlRegisteractivityBottom;
/**
* 注册页面能点击的就三个地方
* top处返回箭头、刷新验证码图片、注册按钮
*/
@OnClick({
R.id.iv_registeractivity_back,
R.id.iv_registeractivity_showCode,
R.id.bt_registeractivity_register
})
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_registeractivity_back: //返回登录页面
Intent intent1 = new Intent(this, loginActivity.class);
startActivity(intent1);
finish();
break;
case R.id.iv_registeractivity_showCode: //改变随机验证码的生成
mIvRegisteractivityShowcode.setImageBitmap(Code.getInstance().createBitmap());
realCode = Code.getInstance().getCode().toLowerCase();
break;
case R.id.bt_registeractivity_register: //注册按钮
//获取用户输入的用户名、密码、验证码
String username = mEtRegisteractivityUsername.getText().toString().trim();
String password = mEtRegisteractivityPassword2.getText().toString().trim();
String phoneCode = mEtRegisteractivityPhonecodes.getText().toString().toLowerCase();
//注册验证
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password) && !TextUtils.isEmpty(phoneCode) ) {
if (phoneCode.equals(realCode)) {
//将用户名和密码加入到数据库中
mDBOpenHelper.add(username, password);
Intent intent2 = new Intent(this, MainActivity.class);
startActivity(intent2);
finish();
Toast.makeText(this, "验证通过,注册成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "验证码错误,注册失败", Toast.LENGTH_SHORT).show();
}
}else {
Toast.makeText(this, "未完善信息,注册失败", Toast.LENGTH_SHORT).show();
}
break;
}
}
}
User.java
package com.example.justloginregistertest;
/**
* Created by littlecurl 2018/6/24
*/
public class User {
private String name; //用户名
private String password; //密码
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
res → drawable 文件夹下面的内容:三个xml 一个.png图片
前两个xml是自动生成的我就不在这粘贴了,只粘贴图片和图片下面那个xml
ic_left_back.png
←←←←←你用鼠标选中一下, 这一行开头确实有个图片,很尴尬,看不见。
selector_loginactivity_button.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--默认情况下是一个带圆角,蓝色背景,白色边框的矩形-->
<!--第二种方法-->
<item android:state_window_focused="false">
<shape android:shape="rectangle">
<!--圆角-->
<corners android:radius="5dp" />
<!--填充颜色-->
<solid android:color="@color/color_minefragment_top" />
<!--描边-->
<stroke android:width="1dp" android:color="#fff" />
</shape>
</item>
<!--单击时是一个带圆角,绿色背景,白色边框的矩形-->
<item android:state_pressed="true">
<shape android:shape="rectangle">
<!--圆角-->
<corners android:radius="5dp" />
<!--填充颜色-->
<solid android:color="#008B8B" />
<!--描边-->
<stroke android:width="1dp" android:color="#fff" />
</shape>
</item>
</selector>
res → layout 文件夹下面的内容:三个xml
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
这里把整个Activity_login的布局设置成相对布局,
因为相对布局比较灵活,想咋放咋放
看代码,上来就是三个 xmlns,xml这仨字母认识,ns这俩字母是namespace的缩写
正是有了这些namespace的声明,才能在不同的xml中使用相同的id名,
而不会造成使用时的冲突
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#eeeeee"
tools:context=".loginActivity">
<!--
整体是相对布局,
在整体上方放三个东西,这三个东西也是相对布局
合在一起称为一个top
一个返回箭头 ←
两个文字显示 登录 注册
也就是说 login界面的上方长这个样子
← 登录 注册
下面是具体代码
-->
<RelativeLayout
android:id="@+id/rl_loginactivity_top"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@color/color_minefragment_top" >
<ImageView
android:id="@+id/iv_loginactivity_back"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/ic_left_back"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:clickable="true"
android:onClick="onClick"
/>
<TextView
android:id="@+id/tv_loginactivity_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登录"
android:textColor="#fff"
android:textSize="20dp"
android:layout_toRightOf="@+id/iv_loginactivity_back"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
/>
<TextView
android:id="@+id/tv_loginactivity_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="注册"
android:textColor="#fff"
android:textSize="20dp"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="30dp"
android:clickable="true"
android:onClick="onClick"
/>
</RelativeLayout>
<!--
顶部三个东西摆放好之后
就该来摆放登录时候的两个文本输入框了
用户名
密码
这个明显的是LinerLayout
LinerLayout必须指明orientation 方向 要么垂直vertical 要么水平 horizontal
这里显然是垂直vertical
-->
<LinearLayout
android:id="@+id/ll_loginactivity_two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_below="@+id/rl_loginactivity_top"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_loginactivity_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户名:"/>
<EditText
android:id="@+id/et_loginactivity_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="手机号/邮箱/用户名"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_loginactivity_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密 码:"/>
<EditText
android:id="@+id/et_loginactivity_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="登录密码"
android:inputType="textPassword"/>
</LinearLayout>
</LinearLayout>
<!--
填好用户名、密码后,就该点击登录按钮了
注意最后有一句: android:onClick="onClick"
这是应用了一个开源库,详细信息在loginActivity.java 中有注释
-->
<Button
android:id="@+id/bt_loginactivity_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/ll_loginactivity_two"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="@drawable/selector_loginactivity_button"
android:text="登录"
android:textColor="#fff"
android:gravity="center"
android:onClick="onClick"
/>
<!--
为了App的人性化,
想到有以下三种无法密码登录的异常处理情况
一、密码错误,重新输入
二、忘记密码,重新修改密码
三、不想注册,通过短信验证登录
密码输错了,重新输入,这个没啥说的
忘记密码应该以一个可以点击的文字出现在登录按钮的左下方
短信验证登录也以一个可以点击的文字出现在登录按钮的右下方
-->
<TextView
android:id="@+id/tv_loginactivity_forget"
android:text="忘记密码"
android:textColor="#f00"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_marginVertical="50dp"
android:layout_below="@+id/bt_loginactivity_login"
android:layout_alignLeft="@+id/bt_loginactivity_login"
/>
<TextView
android:id="@+id/tv_loginactivity_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="短信验证码登录"
android:textColor="#f00"
android:layout_marginRight="50dp"
android:layout_marginVertical="50dp"
android:layout_below="@+id/bt_loginactivity_login"
android:layout_alignRight="@+id/bt_loginactivity_login"
/>
<!--
当然,QQ、微信、微博、GitHub...在当今如此火热
登录的时候完全可以免注册
直接使用第三方登录
-->
<TextView
android:id="@+id/tv_loginactivity_else"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_loginactivity_forget"
android:layout_centerInParent="true"
android:layout_marginVertical="30dp"
android:text="---------------------------第三方登录---------------------------"
android:textColor="#B3B3B3"
android:gravity="center"
/>
</RelativeLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_main_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/bt_main_logout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="退出登录"
android:textColor="@color/colorAccent"
/>
</android.support.constraint.ConstraintLayout>
activity_register.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.justloginregistertest.RegisterActivity"
android:background="#eeeeee"
>
<RelativeLayout
android:id="@+id/rl_registeractivity_top"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@color/color_minefragment_top"
>
<ImageView
android:id="@+id/iv_registeractivity_back"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/ic_left_back"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:clickable="true"
android:onClick="onClick"
/>
<TextView
android:id="@+id/tv_registeractivity_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="注册"
android:textColor="#fff"
android:textSize="20dp"
android:layout_toRightOf="@+id/iv_registeractivity_back"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
/>
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_registeractivity_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_below="@+id/rl_registeractivity_top"
android:layout_marginTop="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
>
<!-- 第一个文本编辑框 输入用户名 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_registeractivity_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户名:"/>
<EditText
android:id="@+id/et_registeractivity_username"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入用户名"
android:gravity="center_vertical"
android:layout_marginLeft="10dp"
/>
</LinearLayout>
<!-- 第二个文本编辑框 输入密码 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_registeractivity_password1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密 码:"/>
<EditText
android:id="@+id/et_registeractivity_password1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:layout_marginLeft="10dp"
android:inputType="textPassword"
android:hint="请输入密码" />
</LinearLayout>
<!-- 第三个文本编辑框 再次输入密码 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_registeractivity_password2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密 码:"/>
<EditText
android:id="@+id/et_registeractivity_password2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请再次输入密码"
android:gravity="center_vertical"
android:layout_marginLeft="10dp"
android:inputType="textPassword"
/>
</LinearLayout>
<!-- 验证码部分 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:layout_marginTop="10dp"
android:orientation="horizontal" >
<!-- 第四个文本编辑框 输入验证码 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_registeractivity_phoneCodes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="验证码:"/>
<EditText
android:id="@+id/et_registeractivity_phoneCodes"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:hint="请输入4位验证码" />
<ImageView
android:id="@+id/iv_registeractivity_showCode"
android:layout_width="0dp"
android:layout_height="70dp"
android:layout_weight="1.5"
android:clickable="true"
android:onClick="onClick"
android:layout_marginTop="-10dp"
/>
</LinearLayout>
</LinearLayout>
<!-- 注册按钮 -->
<Button
android:id="@+id/bt_registeractivity_register"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="5dp"
android:background="@drawable/selector_loginactivity_button"
android:textColor="#fff"
android:text="注册"
android:onClick="onClick"
android:layout_marginTop="40dp"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="@+id/rl_registeractivity_bottom"
android:layout_marginTop="10dp"
>
<TextView
android:layout_centerInParent="true"
android:text="注册即代表同意《用户协议》"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
values → colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
<color name="color_minefragment_top">#20B2AA</color>
</resources>
因为我这个程序用到了开源库,编译的时候Gradle需要根据下面这个文件去下载jar包,在这里特别的粘贴一下下面这个文件
build.gradle(Module:app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.example.justloginregistertest"
minSdkVersion 18
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}
build.gradle(后缀名不是app的那个文件)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-alpha18'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists