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查询语句修改成英文引号就可以。

六、实验结果总结

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

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

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

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

相关推荐
红云梦6 小时前
互联网三高-高性能之JVM调优
java·jvm·互联网三高架构
图梓灵6 小时前
解析Java根基:Object类核心方法
java·开发语言·jvm
武昌库里写JAVA6 小时前
大模型评估论文粗读“AGIEval: A Human-Centric Benchmark for Evaluating Foundation Models“
vue.js·spring boot·毕业设计·layui·课程设计
kill bert12 小时前
Java八股文背诵 第四天JVM
java·开发语言·jvm
你是理想15 小时前
wait 和notify ,notifyAll,sleep
java·开发语言·jvm
returnShitBoy18 小时前
Go语言中的垃圾回收是如何工作的?
java·jvm·golang
liwulin05061 天前
【JAVA】JVM 堆内存“缓冲空间”的压缩机制及调整方法
java·开发语言·jvm
八股文领域大手子1 天前
从接口400ms到20ms,记录一次JVM、MySQL、Redis的混合双打
jvm·数据库·redis·mysql·jar
佩奇的技术笔记1 天前
Java学习手册:JVM、JRE和JDK的关系
java·开发语言·jvm
qian_qh2 天前
如何判断JVM中类和其他类是不是同一个类
jvm