20212313-吴剑标-移动平台开发与实践大作业

20212313-吴剑标-移动平台开发与实践大作业

一、实验目的

1.掌握Android平台的基本开发技能,包括界面设计、数据处理和用户交互。

2.理解并实践用户注册、登录流程,以及用户信息的存储和会话管理。

3.学习SQLite数据库在Android应用中的运用,实现数据的增删查改操作。

4.熟悉使用Android Studio开发环境,包括模拟器的使用和调试技巧。

5.增强解决实际问题的能力,根据本学期所学内容完成一个大作业

二、实验环境

1.操作系统:Windows 10 (家庭版)

2.开发工具:Android Studio,包括必要的SDK和API。

3.编程语言:Java

4.测试设备:模拟器

三、实验内容与设计思路

这次的大作业我打算做的是一款电影购票的App,主要是在csdn上看到各种各样的电影购票系统,所以就看了他们写的,然后主要的就是对代码进行学习与理解,最后进行修改与完善。

主要能够实现的功能与流程为:

1.用户首先需要注册用户名填写密码。

2.注册成功之后,用户可以用之前注册的用户名和密码进行登录。

3.登录成功之后进入到首页,其中包括电影、零食、我的三个部分。

4.电影页面展示电影列表,通过点击列表项中的加号图标,将电影票加入购物车。

5.零食页面展示零食列表,通过点击列表项中的加号图表,将零食加入购物车。

6.我的页面展示当前登录用户名称,购物车入口。

7.点击电影票或零食购物车,进入详情页,展示已选择的电影或零食列表,点击列表项中的删除,可移除该项。(本来想着自己写出来,但是最后没写出来。。。。。。。)

四、实验过程与分析

(一)框架设计

下图是我根据设计思路,然后总结大致结构,用wps画出了电影购票系统的简单结构:

(二)功能模块设计

1.系统功能设计

①登录注册功能:用户信息存储在SQLite中,登录后当前登录用户信息存储在Sharedpreferences中。

②购物车功能:购物车信息存储在SQLite中,存储购物车信息时,包含用户ID,使得每个用户的购物车内容独立分开。

③使用RecyclerView控件展示商品信息。
2.系统界面设计

采用了一些富有电影元素的颜色作为主色调,和电影购票的主题相符合。注册和登录的页面参考了csdn上的许多样例,为了简洁美观,所以登录注册页面都用到了自定义按钮样式和自定义输入框样式。

(三)核心代码

1.Loginactivity

在onCreate方法中,首先调用setContentView来加载登录界面的布局文件activity_login。然后,通过initTitle、initView和initListener三个私有方法分别初始化界面的标题、视图组件和事件监听器。

initTitle方法设置界面标题为"登录",并隐藏返回按钮,这提供一个更简洁的登录界面。initView方法通过findViewById获取界面上的按钮和文本输入框的引用,为后续的事件绑定做准备。initListener方法为登录按钮和注册按钮分别设置了点击事件监听器。当用户点击登录按钮时,会获取用户输入的用户名和密码,然后调用UserService的login方法尝试登录。如果登录成功,将使用CurrentUserUtils类的方法保存当前用户信息,并跳转到主界面MainActivity。如果登录失败,则会显示错误信息。通过点击注册按钮的事件监听器,用户可以跳转到注册界面,这为用户提供了创建新账户的途径。

kotlin 复制代码
public class LoginActivity extends AppCompatActivity {
    private Button btnLogin, btnRegister;
    private EditText etUsername, etPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        // 初始化标题
        initTitle();
        // 初始化视图
        initView();
        // 初始化监听器
        initListener();
    }
    private void initTitle() {
        TextView tvTitle = findViewById(R.id.tv_title);
        tvTitle.setText("登录");
        TextView tvBack = findViewById(R.id.tv_back);
        tvBack.setVisibility(View.GONE);
    }

    private void initView() {
        btnLogin = findViewById(R.id.btn_login);
        btnRegister = findViewById(R.id.btn_register);
        etUsername = findViewById(R.id.et_username);
        etPassword = findViewById(R.id.et_password);
    }

    private void initListener() {
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String username = etUsername.getText().toString();
                String password = etPassword.getText().toString();
                BusinessResult<User> login = UserService.login(username, password);
                if (login.isSuccess()) {
                    CurrentUserUtils.setCurrentUser(login.getData());
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                    finish();
                }else {
                    // 登录失败
                     Toast.makeText(LoginActivity.this, login.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }
        });
        btnRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
                startActivity(intent);
            }
        });
    }
}

2.RegisterActivity

在onCreate方法中,首先通过setContentView加载注册界面的布局,然后依次初始化标题、视图组件和事件监听器。initTitle方法设置了界面标题为"注册",并为返回按钮添加了点击事件,允许用户在需要时返回上一个活动。initView方法通过findViewById获取注册界面上的按钮和文本输入框的引用,为绑定事件监听器做准备。initListener方法为注册按钮设置了点击事件监听器,当用户点击注册按钮时,会从输入框中获取用户名、密码和确认密码,然后调用UserService的register方法进行注册。注册成功后,会通过Toast显示成功消息,并关闭当前注册界面;如果注册失败,则显示失败原因。

kotlin 复制代码
public class RegisterActivity extends AppCompatActivity {
    private Button btnRegister;

    private EditText etUsername, etPassword, etPasswordAgain;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        initTitle();
        initView();
        initListener();
    }

    private void initTitle() {
        TextView tvTitle = findViewById(R.id.tv_title);
        tvTitle.setText("注册");
        TextView tvBack = findViewById(R.id.tv_back);
        tvBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }

    private void initView() {
        btnRegister = findViewById(R.id.btn_register);
        etUsername = findViewById(R.id.et_username);
        etPassword = findViewById(R.id.et_password);
        etPasswordAgain = findViewById(R.id.et_password_again);
    }

    private void initListener() {
        btnRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String username = etUsername.getText().toString();
                String password = etPassword.getText().toString();
                String passwordAgain = etPasswordAgain.getText().toString();
                BusinessResult<User> result = UserService.register(username, password, passwordAgain);
                Toast.makeText(RegisterActivity.this, result.getMessage(), Toast.LENGTH_SHORT).show();
                if (result.isSuccess()) {
                    finish();
                }
            }
        });
    }
}

3.MainActivity

onCreate方法首先设置活动的内容视图为activity_main布局。然后,创建一个fragmentList列表,用于存储三个不同的片段:HotFragment、SnackFragment和UserFragment,分别代表热门电影、零食和用户信息的界面部分。

接下来,代码通过findViewById获取到ViewPager2和BottomNavigationView的实例。ViewPager2用于展示不同的片段,而BottomNavigationView提供了底部导航栏,允许用户在不同的片段间切换。通过创建一个FragmentStateAdapter的匿名内部类,ViewPager2的适配器被设置,它负责根据用户在ViewPager2上的位置来实例化和展示相应的片段。

kotlin 复制代码
public class MainActivity extends AppCompatActivity {
    private List<Fragment> fragmentList;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fragmentList = new ArrayList<>();
        fragmentList.add(new HotFragment());
        fragmentList.add(new SnackFragment());
        fragmentList.add(new UserFragment());

        ViewPager2 pager = findViewById(R.id.pager);
        BottomNavigationView bottomNavigation = findViewById(R.id.bottom_navigation);


        pager.setAdapter(new FragmentStateAdapter(this) {
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                return fragmentList.get(position);
            }

            @Override
            public int getItemCount() {
                return fragmentList.size();
            }
        });
        pager.setOffscreenPageLimit(fragmentList.size());
        pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                bottomNavigation.getMenu().getItem(position).setChecked(true);
            }
        });
        bottomNavigation.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                pager.setCurrentItem(item.getOrder(), false);
                return true;
            }
        });
    }
}

4.UserDatabaseHelper

init方法用于初始化数据库帮助类实例,确保在应用程序中全局只存在一个UserDatabaseHelper对象。insert方法允许将用户信息插入到数据库中,使用预编译的SQL语句来防止SQL注入攻击。isExistByUsername方法用于检查数据库中是否已存在具有相同用户名的用户,而getUserByUsername方法则用于根据用户名查询用户信息。

onCreate方法在数据库首次创建时被调用,用于定义用户表的结构,包含自增主键_id、用户名username和密码password字段。onUpgrade方法则用于处理数据库版本升级时的逻辑,虽然在此代码示例中该方法为空,但它在实际应用中用于处理数据迁移或版本兼容问题。整个UserDatabaseHelper类的操作包括数据库的创建、用户数据的增删查以及数据库版本的管理。

kotlin 复制代码
public class UserDatabaseHelper extends SQLiteOpenHelper {
    private static UserDatabaseHelper instance;
    private UserDatabaseHelper(Context context) {
        super(context, "user.db", null, 1);
    }

    public static void init(Context context) {
        if (instance == null) {
            instance = new UserDatabaseHelper(context);
        }
    }
    public static void insert(User user) {
        SQLiteDatabase db = instance.getWritableDatabase();
        String sql = "INSERT INTO user(username,password) VALUES(?,?)";
        String[] args = new String[]{user.getUsername(), user.getPassword()};
        db.execSQL(sql, args);
        db.close();
    }
    public static boolean isExistByUsername(String username) {
        SQLiteDatabase db = instance.getWritableDatabase();
        String sql = "SELECT * FROM user WHERE username=?";
        String[] args = new String[]{username};
        Cursor cursor = db.rawQuery(sql, args);
        boolean result = cursor.getCount() > 0;
        cursor.close();
        db.close();
        return result;
    }
    public static User getUserByUsername(String username) {
        SQLiteDatabase db = instance.getWritableDatabase();
        String sql = "SELECT * FROM user WHERE username=?";
        String[] args = new String[]{username};
        Cursor cursor = db.rawQuery(sql, args);
        User user = null;
        if (cursor.moveToNext()) {
            user = new User();
            user.setId(cursor.getInt(0));
            user.setUsername(cursor.getString(1));
            user.setPassword(cursor.getString(2));
        }
        cursor.close();
        db.close();
        return user;
    }
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("CREATE TABLE user(_id INTEGER PRIMARY KEY AUTOINCREMENT,username VARCHAR(20) ,password VARCHAR(20))");
    }
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

(四)实验成果

以下为我的实验成果的视频录制:

CineFlow --

1.登入页面

2.注册页面

3.电影主页面

4.零食页面

5.我的页面

五、实验问题与解决

问题1:导入项目时,无法运行

解决方法:修改项目路径,将路径修改成自己电脑上的路径。

问题2:修改项目路径后仍然无法运行,查找资料后显示需要"Sync project with Gradle Files"。但是我发现我没有"Sync project with Gradle Files"按钮。

解决方法:根据csdn上的教程一步一步完成的。

问题3:在我编译过程中,Android Studio报错,报了大量的错,错误信息大致意思是找不到类或方法、缺少依赖。

解决方法:在网络上查询了特别久,才发现是导入的库与我使用的版本不一致,不兼容。然后花了特别大的时间又去网站上下载了一个对应版本的库。最后重建项目,使用Build -> Clean Project和Build -> Rebuild Project。

问题4:SQLite数据库查询错误,在尝试从SQLite数据库查询用户信息时,无法正确查询到数据。

解决方法:将代码发给了gpt,和gpt交流了特别久都没有找到问题。原来是我在学习数据库查询时,重新设计查询语句的时候sqk语句用的是中文引号,最后SQL查询语句修改成英文引号就可以。

六、实验结果总结

此次移动平台课程的大作业过程中,我深入体验了从理论到实践的转变,这个过程让我受益匪浅。我深刻认识到理论知识与实际操作之间的差距。在设计电影购票系统的过程中,我本以为已经掌握了足够的理论知识,但实际操作时却发现理论与现实之间存在诸多差异。例如,在实现用户登录和注册功能时,我需要考虑如何安全地存储用户信息,如何有效管理用户的会话状态,这些都是书本和课上上不曾深入讨论的问题。这让我意识到,理论知识是基础,但只有通过实践,才能真正理解并掌握技术的应用。

在开发过程中,我遇到了各种预料之外的技术难题,比如数据库的设计与优化、用户界面的友好性设计等。面对这些问题,我学会了查阅资料、分析问题、尝试不同的解决方案,并最终找到问题的答案。这个过程锻炼了我的问题解决能力,也让我更加自信地面对未知的挑战。在开发过程中,离不开舍友和同学的帮助,我与同学们进行了多次讨论和交流。我们分享了彼此的经验和遇到的难题,这种交流极大地拓宽了我的视野,也帮助我更快地解决了问题。通过这次大作业,我不仅提升了自己的技术能力,也锻炼了自己的思维和解决问题的能力。

这学期的课程已经圆满结束,我有幸参加了王志强老师教授的两门课程,它们不仅内容丰富,而且深刻地影响了我对专业知识的理解和应用。在网络攻防课程中,我仿佛化身为一名黑客,深入探索了网络安全的奥秘,学习了如何识别和防范潜在的网络威胁,这些经历极大地拓宽了我的视野,让我对网络安全有了更加深刻的认识。而在移动平台课程中,我更是亲手实践,从零开始学习如何开发一款手机应用,这个过程不仅锻炼了我的编程能力,也让我体会到了创造的乐趣和成就感,我发现自己也能成为一名开发者,这无疑大大增强了我的自信心。

尽管在本学期中,我因私事在移动平台课程上请了两次假,都是去见我的女朋友,但我始终对课程保持着极高的热情和重视。在此,我特别感谢王志强老师的理解和支持,他的和蔼与善良让我感到温暖,也激励我更加努力学习。老师的教学方法生动有趣,能够深入浅出地讲解复杂的知识点,使我能够在轻松愉快的氛围中掌握知识。未来我将不辜负老师的期望,继续保持学习的积极性!最后再次感谢王志强老师辛勤教导!

相关推荐
武昌库里写JAVA28 分钟前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
武昌库里写JAVA4 小时前
浅谈怎样系统的准备前端面试
数据结构·vue.js·spring boot·算法·课程设计
程序员志哥6 小时前
JVM系列(十三) -常用调优工具介绍
jvm
后台技术汇6 小时前
JavaAgent技术应用和原理:JVM持久化监控
jvm
程序员志哥6 小时前
JVM系列(十二) -常用调优命令汇总
jvm
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭7 小时前
聊聊volatile的实现原理?
java·jvm·redis
_LiuYan_10 小时前
JVM执行引擎JIT深度剖析
java·jvm
王佑辉10 小时前
【jvm】内存泄漏的8种情况
jvm
工业甲酰苯胺10 小时前
JVM简介—1.Java内存区域
java·jvm·python