飞道的博客

【Android学习之路】之从零开始做一个小项目(一)

402人阅读  评论(0)

最近在学Android(初学者吖),写下这个【Android学习之路】系列记录一下自己学习的过程,欢迎阅读~


目前进度

① 总体页面框架基本成型,初始界面和登录界面经过一定的美化
② 注册和登录功能已经实现,密码采用MD5算法进行加密存储
③ 能成功连接SQLite数据库并进行数据的CRUD操作
④ 手机验证码登录功能进行至一半(采用的是MobTech平台)

准备阶段

开发工具以及方向构思

我用的开发工具是Android Studio,是谷歌基于IntelliJ IDEA开发的IDE,因为习惯于用IDEA写Java,所以我选择使用用Android Studio来进行安卓开发,而不是Eclipse(而且谷歌已经停止对Eclipse Android开发工具的一切支持)。

附上我用的版本的百度网盘链接:
Android Studio:链接:https://pan.baidu.com/s/1y2uXHEUl0ungSwA2eaAO7A 提取码:twmm
SDK: 链接:https://pan.baidu.com/s/1OdKp84vJnbMcm8ky-L28AQ 提取码:h5zi

模拟器我用的是夜神,使用效果还可以,同样附上链接:

链接:https://pan.baidu.com/s/1JOI0bWH1aOvP1gpc4-79pQ
提取码:odn9

— — — — — — — — — — — — — — — — — —
构思自己要做的项目时,方向是和学校相关的,因为这样也比较贴近我的生活,更加熟悉一些,哈哈。然后本取名鬼才给该项目和APP均取名为:SchoolSystem,哈哈,不过现在我发现这个名字在手机里显示不全,后半截直接省略号了😂

要实现的功能计划

功能方面我的计划是:
① 分为教师和学生两种登录方式(密码采用MD5加密),登录后所能使用的功能是不同的(拿【学习】页面来说老师能出题和修改学生的分数等,学生只能查看成绩结果和分析以及做题等)
② 老师注册和登录时有一定的限制(我提前准备好可以注册的手机号,老师注册的时候比学生多出手机短信验证这一限制),然后在登录后学生需进行身份认证,认证成功后可享受全部功能,否则只有【计划】这一页面可供使用
③ 【学习】页面有学生的成绩绘制成的图表分析,以及自己的所有成绩查询(和全班的成绩),然后在该页面会实现一个可以做题的功能(教师在该页面可出题,然后学生在该页面做题)
④ 【计划】这一页面可供大家写下自己的计划(可设置为自己可见和全部人可见)
⑤ 如果能力达到的条件下,完善【论坛】页面,连接云数据库,大家可在其中发表一些内容


第一阶段

UI展示

APP启动后会进入初始的选择登录身份的界面,如下图(是我手机上的截屏):

APP的图标我采用了AS里提供的炒鸡好用的Image Asset功能进行制作,好处是基本能适应各种机型,包括图标是圆形,设计界面如下图:

选择登录身份的初始界面InitActivity的布局采用了LinearLayout垂直方向线性布局,页面中有ImageView组件显示我设计的欢迎那一张图片和底部的图片,然后是“请选择您的身份”和“Copyright”的TextView组件,下面部分我采用了RelativeLayout相对布局,并在其中嵌套了一个相对布局用于教师选择和学生选择的位置控制,使其具有更好地适应能力,该activity_init.xml文件源代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@mipmap/bg1"
    android:padding="3dp"
    tools:context=".InitActivity">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@mipmap/welcome"
        android:adjustViewBounds="true">
    </ImageView>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="8dp"
        android:padding="8dp"
        android:background="@drawable/translucent2"
        android:lineSpacingExtra="4sp"
        android:text="请选择您的身份"
        android:textAlignment="center"
        android:textSize="20sp"
        android:textStyle="bold" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <RelativeLayout
            android:id="@+id/ChooseTeacher"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/translucent2"
            android:layout_toLeftOf="@+id/canzhao"
            android:layout_marginRight="45dp"
            android:layout_marginTop="50dp">
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/teacher_ico"
                android:layout_margin="10dp"
                android:src="@mipmap/teacher_ico"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:text="我是教师"
                android:layout_centerHorizontal="true"
                android:textColor="#576B95"
                android:layout_marginTop="5dp"
                android:layout_below="@id/teacher_ico"
                android:textStyle="bold"/>
        </RelativeLayout>
        <TextView
            android:id="@+id/canzhao"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true" />
        <RelativeLayout
            android:id="@+id/ChooseStudent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/translucent2"
            android:layout_toRightOf="@+id/canzhao"
            android:layout_marginLeft="45dp"
            android:layout_marginTop="50dp">
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/student_ico"
                android:layout_margin="10dp"
                android:src="@mipmap/student_ico"/>
            <TextView
                android:id="@+id/nameLogined"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:text="我是学生"
                android:layout_centerHorizontal="true"
                android:textColor="#576B95"
                android:layout_marginTop="5dp"
                android:layout_below="@id/student_ico"
                android:textStyle="bold"/>
        </RelativeLayout>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/translucent2"
            android:lineSpacingExtra="4sp"
            android:text="Copyright © 2020 Henry.  All Rights Reserved"
            android:layout_marginTop="300dp"
            android:textAlignment="center"
            android:textSize="12sp"
            android:textStyle="bold" />
        <ImageView
            android:id="@+id/welcomebottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:src="@mipmap/welcomebottom"

            android:adjustViewBounds="true">
        </ImageView>
    </RelativeLayout>

</LinearLayout>

emm,这个代码的颜色有些刺眼哈哈,接下来分别是教师和学生登录页面(因为手机短信验证功能还没调试成功,所以教师页面暂时也是用户名+密码的注册和登录形式):


成功登录后跳转一个新的Activity,其中能通过点击底部的导航栏在4个Fragment中切换
(暂时还未设计出其他三个页面的布局框架,目前初步定下【我的】页面):

在【我的】页面中,点击【关于】可跳转至【关于我】页面,里面简单写了一点我的联系方式,然后可以通过点击图标直接拨打电话或发送短信(需要同意相应的权限):

该【关于我】页面的调用拨号和发短信功能实现具体代码如下(我在这里把我的号码改成123456了嘻嘻):

package com.henry.schoolsystem.ui.me;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;

import com.henry.schoolsystem.R;

public class AboutActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_about);
        ImageButton imageButton = (ImageButton) findViewById(R.id.imageButton_phone); //获取电话图片按钮
        ImageButton imageButton1 = (ImageButton) findViewById(R.id.imageButton_sms); //获取短信图片按钮
        imageButton.setOnClickListener(l); //为电话图片按钮设置单击事件
        imageButton1.setOnClickListener(l);//为短信图片按钮设置单击事件
    }

    //创建监听事件对象
    View.OnClickListener l = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(); //创建Intent对象
            switch (v.getId()) {       //根据ImageButton组件的id进行判断
                case R.id.imageButton_phone:              //如果是电话图片按钮
                    intent.setAction(intent.ACTION_DIAL); //调用拨号面板
                    intent.setData(Uri.parse("tel:123456")); //设置要拨打的号码
                    startActivity(intent); //启动Activity
                    break;
                case R.id.imageButton_sms:             //如果是短信图片按钮
                    intent.setAction(intent.ACTION_SENDTO); //调用发送短信息
                    intent.setData(Uri.parse("smsto:123456")); //设置要发送的号码
                    intent.putExtra("sms_body", "您好!"); //设置要发送的信息内容
                    startActivity(intent); //启动Activity
            }
        }


    };
}

功能展示

首先是注册/登录界面功能
写入数据库需要使用SQLiteOpenHelper类,该类是一个抽象类,需要创建该类的派生类,我这里是DBOpenHelper,源代码如下:

package com.henry.schoolsystem.ui.login;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * Created by Henry
 */
public class DBOpenHelper extends SQLiteOpenHelper {
    public static final String USER_INFO = "userInfo";
    public static final String USER_LOGIN = "userLogin";

    public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, null, version);     //重写构造方法并设置factory为null
    }


    @Override
    public void onCreate(SQLiteDatabase db) {
        /**
         * 当该子类被实例化时会创建指定名的数据库,在onCreate中创建用户信息表和登录信息表
         * **/
        db.execSQL("CREATE TABLE IF NOT EXISTS " + USER_INFO + "( "
                + "_id  INTEGER PRIMARY KEY AUTOINCREMENT, "
                + "userName VARCHAR, "
                + "nickName VARCHAR, "
                + "sex VARCHAR, "
                + "qq VARCHAR, "
                + "wechat VARCHAR, "
                + "motto VARCHAR "
                + ")");
        db.execSQL("CREATE TABLE IF NOT EXISTS " + USER_LOGIN + "( "
                + "_id  INTEGER PRIMARY KEY AUTOINCREMENT, "
                + "userName VARCHAR, "
                + "password VARCHAR"
                + ")");
    }
    @Override

    // 重写基类的onUpgrade()方法,以便数据库版本更新
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //提示版本更新并输出旧版本信息与新版本信息
        System.out.println("---版本更新-----" + oldVersion + "--->" + newVersion);
    }
}


注册/登录页面的Activity中的代码如下(以学生页面SLoginActivity为例):

package com.henry.schoolsystem.ui.login;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.henry.schoolsystem.R;
import com.henry.schoolsystem.SMainActivity;
import com.henry.schoolsystem.TMainActivity;
import com.henry.schoolsystem.utils.MD5Utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class SLoginActivity extends AppCompatActivity {

    private DBOpenHelper dbOpenHelper;  //定义DBOpenHelper,用于与数据库连接
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_slogin);

        //创建DBOpenHelper对象,指定名称、版本号并保存在databases目录下
        dbOpenHelper = new DBOpenHelper(SLoginActivity.this, "student.db", null, 1);

        final EditText usernameEditText = (EditText) findViewById(R.id.add_username);           //获取添加用户名的编辑框
        final EditText passwordEditText = (EditText) findViewById(R.id.add_password);  //获取添加密码的编辑框
        final Button btn_Save = (Button) findViewById(R.id.register2);      //获取注册按钮
        final Button btn_Login = (Button) findViewById(R.id.login2);     //获取登录按钮

        //登录
        btn_Login.setOnClickListener(new View.OnClickListener() {  //单击登录按钮查看是否有该用户以及密码是否正确
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
                String key = usernameEditText.getText().toString();  //获取输入的登录名

                //用Cursor游标进行查询
                Cursor cursor = db.query("userLogin", null
                        , "userName = ?", new String[]{key}, null, null, null);

                ArrayList<Map<String, String>> resultList = new ArrayList<Map<String, String>>();   //创建ArrayList对象,用于保存查询出的结果
                while (cursor.moveToNext()) {  // 遍历Cursor结果集
                    Map<String, String> map = new HashMap<>();  // 将结果集中的数据存入HashMap中
                    // 取出查询记录中第2、3列的值
                    if (resultList.size() != 0) break;
                    map.put("userName", cursor.getString(1));
                    map.put("password", cursor.getString(2));//将查询出的数据存入ArrayList中
                    resultList.add(map);
                }
                if (resultList.size() == 0) {  //如果数据库中没有数据
                    Toast.makeText(SLoginActivity.this, "用户名不存在,请重新输入或注册!", Toast.LENGTH_SHORT).show();
                    cursor.close();
                } else {
                    // 否则比较password是否一致
                    String passwordIn = passwordEditText.getText().toString(); //获取输入的密码
                    String passwordNeed = cursor.getString(cursor.getColumnIndex("password"));  //获取需要填写的密码

                    if (passwordNeed.equals(MD5Utils.md5(passwordIn))) {   //只是比较内容,不能用==
                        Toast.makeText(SLoginActivity.this, "登录成功!"+key+",欢迎您~", Toast.LENGTH_LONG).show();
                        cursor.close();

                        Intent intent = new Intent(SLoginActivity.this, SMainActivity.class);  //登录成功跳转至学生端
                        startActivity(intent);
                    } else {
                        Toast.makeText(SLoginActivity.this, "密码错误,请重新输入!", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
        //注册
        btn_Save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String username = usernameEditText.getText().toString();  //获取填写的用户名
                String password = passwordEditText.getText().toString(); //获取填写的密码
                if (username.equals("")||password.equals("")){  //如果填写的用户名或密码为空时
                    Toast.makeText(SLoginActivity.this, "用户名或密码为空,请重新填写", Toast.LENGTH_SHORT).show();
                }else {
                    // 调用insertData()方法,实现插入用户数据
                    insertData(dbOpenHelper.getReadableDatabase(), username, password);
                    // 显示提示信息
                    dbOpenHelper.close();
                    Toast.makeText(SLoginActivity.this, "注册成功!可以登录啦", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
    //创建insertData()方法实现插入数据
    private void insertData(SQLiteDatabase readableDatabase, String username, String password) {
        ContentValues values = new ContentValues();
        values.put("userName", username);       //保存用户名
        values.put("password", MD5Utils.md5(password));  //保存密码
        try {
            readableDatabase.insert("userLogin", null, values);//执行插入操作
        }
        catch (SQLException e) {
            Log.e("SQLiteDatabase", "Error inserting " + values, e);
        }
    }
}

当填入的用户名或密码中有一个为空时,注册失败同时通过Toast弹出消息提示框,注册成功并登录后会弹出一个欢迎的消息提示框,如下图:

对了,上一步中,如果密码输入错误或是用户名不存在会有如下的登录失败提示:

然后该注册的密码在数据库中是经过MD5算法加密后存储的,MD5加密算法的java类如下:

package com.henry.schoolsystem.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 *  创建一个md5()方法
 *  通过 MessageDigest 的 getInstance()方法
 *  获取数据加密对象 digest,然后通过该对象的 digest()方法对密码进行加密
 *  由于注册登录涉及密码,需要对用户的密码进行 MD5 算法加密
 */
public class MD5Utils {
    // md5 加密的算法
    public static String md5(String text){
        MessageDigest digest = null;

        try {
            //获取数据指纹对象
            digest = MessageDigest.getInstance("md5");
            //字节数组
            byte[] result = digest.digest(text.getBytes());
            //16进制转换
            StringBuffer sb = new StringBuffer();
            //获取所有字节进行转换
            for (byte b: result){
                //使用『与算法』,java使用unicode字符,所以每个字符占位两个
                // 需要与两位16进制最大值进行与运算,获取number值
                int number = b & 0xff;
                //number值转换字符串
                String hex = Integer.toHexString(number);
                if (hex.length() == 1){
                    //若转换后的字符长度等于1则进行字符串拼接
                    sb.append("0"+hex);
                }else {
                    sb.append(hex);
                }
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            //发送异常return空字符串
            return "";
        }
    }
}

查看SQLite数据库中的相关记录(我使用的Navicat Premium 15):
相关教程可参考:快速激活Navicat Premium 12

打开后连接我从AS中导出的数据库student.db,查看userLogin表:


— — — — — — — — — — — — — — — — — — — — — — — — — — — —
短信验证功能可以有很多平台使用,我选择的是MobTech(免费的),可由此查看相关文档:SMSSDK for Android
需要在AndroidManifest.xml中添加以下权限:

以及在项目根目录的build.gradle中添加依赖,不过你可能还需要像我一样添加上两个库:

以及在使用SMSSDK模块的build.gradle中,添加MobSDK插件和扩展:

// 添加插件
apply plugin: 'com.mob.sdk'

// 在MobSDK的扩展中注册SMSSDK的相关信息
MobSDK {
    appKey "申请Mob的appkey"
    appSecret "申请Mob的AppSecret"
    SMSSDK {}
}

这些设置在文档中都有:SMSSDK for Android,写的挺详细的,该短信验证功能的具体代码实现和调用在下一阶段会完成~


第一阶段主要是构造好了基本的大的框架和初级的登录功能,数据库的详细的各个关系模式将在最近几天设计出来,目前只有userLoginuserInfo两个表,每个页面的设计也会在第二阶段弄出来,不过刚学不久,在很多地方遇到了障碍,在努力克服中,继续加油叭💪!

下一阶段会在这周更新出来,然后在本文附上链接~
对了,安卓连接SQLite数据库的一些具体介绍我会在近期发表一篇博客~

(ps:因为目前代码中一些地方写的还不够好,在最终项目完成后会将项目源码上传至GitHub😊,目前发表出的代码中如有问题和需改进的地方希望大家积极指出~)


转载:https://blog.csdn.net/qq_43974000/article/details/106090564
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场