20212413 2023-2024-2 《移动平台开发与实践》移动平台开发综合实践

20212413 2023-2024-2 《移动平台开发与实践》移动平台开发综合实践

一、实验目的

本实验旨在开发一款名为“皮卡日记”的Android日记应用,以实践和掌握Android开发中的一系列关键知识点和技能。通过本实验,我深入理解并应用以下技术点:
(1)Activity与Fragment的交互:学习如何在Activity与Fragment之间进行数据传递、页面更新以及相互跳转,以实现流畅的用户体验。
(2)数据存储技术:掌握SharedPreference、文件存储以及文件加密技术,确保用户数据的安全性和持久性。
(3)Android权限管理:了解如何获取和设置Android应用所需的权限,保证应用的安全性和功能性。
(4)UI控件的应用:熟悉并应用Button、EditText、AlertDialog、ImageView、ImageButton、ViewPager2、Toolbar、RecyclerView、NavigationButton等控件,以构建丰富且直观的用户界面。
(5)布局设计:掌握LinearLayout、ConstraintLayout、RelativeLayout等布局方式,以实现灵活且响应式的界面设计。
(6)系统应用调用:学习如何调用Android系统应用,增强应用的功能性和集成度。
(7)自定义View:开发复杂的自定义View,如底部弹窗和圆形头像,以提升应用的个性化和美观度。
(8)Glide框架的使用:学习如何使用Glide框架进行网络图片的加载,优化应用的性能和用户体验。

二、实验环境

1.Android Studio
2.Huawei nova 8

三、实验内容与实验要求

1.实验内容与要求:
(1)应用启动页实现:设计并实现应用的启动页面,为用户提供应用的第一印象。
(2)密码保护机制:实现设置密码功能,确保应用的安全性,并采用加密保护密码。
(3)底部导航栏:构建底部导航栏,分为日记列表、新建日记、个人中心三个模块。
(4)日记管理功能:实现日记的删除、修改、新增等功能,满足日记管理的需求。
(5)密码显示与设置界面跳转:实现密码的显示与隐藏功能,并提供跳转到应用设置界面的选项。
(6)应用图标自定义:自定义应用图标,摆脱默认图标,提升应用的个性化和识别度。
2.app效果展示
app效果包括:app图标、启动页、登录注册页、设置密码页
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、实验过程与实验分析

1.MainActivity中使用BottomNavigationView、ViewPager2、Toolbar的实现:

public class MainActivity extends AppCompatActivity {
    private BottomNavigationView bottomNavigationView;
    private DiariesFragment diariesFragment;
    private MeFragment meFragment;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initToolbar();
        initFragment();
        initNavigationBottom();
    }
    @SuppressLint("ResourceAsColor")
    private void initNavigationBottom() {
        bottomNavigationView = findViewById(R.id.navigation_bottom);
        bottomNavigationView.setItemIconTintList(null);
        bottomNavigationView.setOnItemSelectedListener(itemSelectedListener);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return super.onCreateOptionsMenu(menu);
    }
    private void initFragment() {
        getCurrentFragment();
        if (diariesFragment == null) {
            diariesFragment = new DiariesFragment();
            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), diariesFragment, R.id.content);
        }
        if (meFragment == null) {
            meFragment = new MeFragment();
        }
    }
    private void getCurrentFragment() {
        Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.content);
        if (fragment instanceof DiariesFragment) {
            diariesFragment = (DiariesFragment) fragment;
        } else if (fragment instanceof MeFragment) {
            meFragment = (MeFragment) fragment;
        }
    }
    private void initToolbar() {
        //设置顶部状态栏为透明
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }
    private final NavigationBarView.OnItemSelectedListener itemSelectedListener = item -> {
        int id = item.getItemId();
        if (id == R.id.menu_diary) {
            MeController.setToolbarVisibility(this);
            ActivityUtils.replaceFragmentTOActivity(getSupportFragmentManager(), diariesFragment);
        } else if (id == R.id.menu_me) {
            findViewById(R.id.toolbar).setVisibility(View.GONE);
            ActivityUtils.replaceFragmentTOActivity(getSupportFragmentManager(), meFragment);
        } else if (id == R.id.menu_new) {
            bottomNavigationView.setVisibility(View.GONE);
            MeController.setToolbarVisibility(this);
            ActivityUtils.removeFragmentTOActivity(getSupportFragmentManager(), getSupportFragmentManager().findFragmentById(R.id.content));
            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), new AddDiaryFragment(), R.id.content);
        }
        return true;
    };
}

这段代码是一个Android应用程序的主活动(Activity)类,名为MainActivity,它继承自AppCompatActivity。以下是对代码的分析:
类定义和成员变量:
MainActivity类定义了两个Fragment类型的成员变量:diariesFragment和meFragment,分别代表日记列表和个人中心的页面。
onCreate方法:
在onCreate方法中,首先调用了父类的onCreate方法,并设置了布局文件activity_main。
接着,调用了initToolbar方法来初始化顶部的工具栏(Toolbar)。
调用initFragment方法来初始化Fragment,并检查当前的Fragment,如果没有则创建。
最后调用initNavigationBottom方法来初始化底部导航栏(BottomNavigationView)。
initNavigationBottom方法:
通过findViewById获取底部导航栏的实例。
调用setItemIconTintList(null)来移除图标的颜色过滤,使得图标显示原始颜色。
设置了一个OnItemSelectedListener来处理导航项的点击事件。
onCreateOptionsMenu方法:
这个方法被重写,但目前没有实现任何功能,只是返回了父类的方法结果。
initFragment方法:
调用getCurrentFragment来获取当前显示的Fragment。
如果diariesFragment或meFragment为null,则创建它们。
使用ActivityUtils.addFragmentToActivity方法将日记列表Fragment添加到Activity中。
getCurrentFragment方法:
通过findFragmentById查找当前显示的Fragment,并根据类型将其赋值给相应的成员变量。
initToolbar方法:
设置状态栏为透明。
通过findViewById获取Toolbar的实例,并调用setSupportActionBar将其设置为Activity的ActionBar。
itemSelectedListener:
这是一个内部类,实现了NavigationBarView.OnItemSelectedListener接口。
根据用户点击的导航项ID,执行不同的操作:如果点击的是日记(menu_diary),则显示Toolbar并替换当前Fragment为日记列表Fragment。
如果点击的是个人中心(menu_me),则隐藏Toolbar并替换当前Fragment为个人中心Fragment。
如果点击的是新建日记(menu_new),则隐藏底部导航栏和Toolbar,并添加新建日记的Fragment。
ActivityUtils工具类:
代码中提到了ActivityUtils类,它是一个工具类,提供了一系列静态方法来处理Fragment的添加、替换和移除操作。
整体上,这段代码展示了如何在Android应用中使用Fragment和BottomNavigationView来实现多页面的导航,并通过监听器来响应用户的导航选择。

2.ViewPager2中切换不同fragment,对应导航栏新增日记、个人中心及日记列表:

public class DiariesFragment extends Fragment {
    private DiariesController mController;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mController = new DiariesController(this);
    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_diaries, container, false);
        mController.setDiariesList(root.findViewById(R.id.diaries_list));
        mController.setNavigationSelected();
        return root;
    }
    @Override
    public void onResume() {
        super.onResume();
        mController.loadDiaries();
    }
}

DiariesFragment 类是Android应用程序中的一个片段(Fragment),它负责显示日记列表。以下是对代码的分析:
成员变量:
mController 是 DiariesController 类的实例,这个控制器类负责管理日记列表的逻辑。
onCreate方法:
在 onCreate 方法中,调用了基类的 onCreate 方法,并初始化了 mController。
onCreateView方法:
onCreateView 方法负责为 DiariesFragment 创建视图。它使用 LayoutInflater 来加载 fragment_diaries 布局。
该方法将日记列表的视图与 mController 绑定,通过 setDiariesList 方法设置。
调用 setNavigationSelected 方法,这可能用于更新导航栏的状态。
最终,返回布局的根视图。
onResume方法:
onResume 方法在 DiariesFragment 恢复并准备与用户交互时调用。
在此方法中,mController.loadDiaries 被调用,这可能用于执行加载日记列表数据的操作。
DiariesController类:
DiariesController 是一个未在代码中展示的类,但根据上下文,它应该包含与日记列表相关的业务逻辑。
视图绑定:
通过 findViewById 方法,日记列表的视图被绑定到 mController,以便控制器可以管理列表的显示和交互。
布局文件:
R.layout.fragment_diaries 是定义日记列表界面的XML布局文件。
生命周期方法:
onCreateView 和 onResume 是Fragment生命周期中的关键方法,分别用于创建视图和恢复用户交互。
整体来看,DiariesFragment 类通过 DiariesController 类来处理日记列表的展示和数据加载,遵循了Fragment生命周期的方法,确保在适当的时候进行视图的创建和数据的加载。

3.AddDiaryFragment,对应写日记:

public class AddDiaryFragment extends Fragment implements View.OnClickListener {
    private AddDiaryController mController;
    private EditText edit_title;
    private EditText edit_desc;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mController = new AddDiaryController(this);
    }
    private void initView(View view) {
        Button btn_confirm = view.findViewById(R.id.add_diary_confirm);
        btn_confirm.setOnClickListener(this);
        edit_title = view.findViewById(R.id.edit_add_title);
        edit_desc = view.findViewById(R.id.edit_add_desc);
        View edit_layout = view.findViewById(R.id.edit_layout);
        edit_layout.setOnClickListener(this);
    }
    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        menu.clear();
        inflater.inflate(R.menu.menu_cancel, menu);
    }
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (R.id.menu_cancel == item.getItemId()) {
            mController.closeWriteDiary(requireActivity().getSupportFragmentManager(), this);
            mController.setNavigationVisibility();
            return true;
        }
        return false;
    }
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_add_diary, container, false);
        initView(root);
        return root;
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (R.id.add_diary_confirm == id) {
            mController.addDiaryToRepository(edit_title.getText().toString().trim(), edit_desc.getText().toString().trim());
            mController.setNavigationVisibility();
            mController.closeWriteDiary(requireActivity().getSupportFragmentManager(), this);
        } else {
            mController.changeFocus(edit_desc);
        }
    }
}

代码定义了一个名为 AddDiaryFragment 的 Fragment 类,它用于实现一个添加日记的功能。以下是代码的主要功能和组成部分:
类定义:
AddDiaryFragment 继承自 Fragment 类,并实现了 View.OnClickListener 接口,这意味着它能够处理点击事件。
成员变量:
mController:AddDiaryController 类的实例,用于处理添加日记的业务逻辑。
edit_title 和 edit_desc:分别为标题和描述的 EditText 控件,用户可以在这些文本框中输入日记的标题和内容。
onCreate方法:
在 onCreate 方法中,调用了基类的 onCreate 方法,并初始化了 mController。
initView方法:
负责初始化视图和设置点击监听器。为“确认”按钮和编辑布局设置点击事件,这些点击事件将由 onClick 方法处理。
onCreateOptionsMenu方法:
重写该方法以自定义选项菜单,清除原有菜单项,并添加一个取消菜单项。
onOptionsItemSelected方法:
处理选项菜单中的点击事件。如果用户点击了取消菜单项,将调用 mController 的方法关闭写日记界面,并更新导航栏的可见性。
onCreateView方法:
负责创建 AddDiaryFragment 的视图。使用 LayoutInflater 加载 fragment_add_diary 布局,并调用 initView 方法来初始化视图组件。
onDestroy方法:
重写该方法以执行清理操作,尽管在这段代码中没有执行具体操作,但它调用了基类的 onDestroy 方法。
onClick方法:
处理点击事件。如果用户点击了“确认”按钮,则调用 mController 的方法将用户输入的日记标题和内容添加到数据存储中,并关闭写日记界面,更新导航栏的可见性。如果点击了编辑布局,则调用 mController 的方法改变焦点,通常是为了在文本框中输入时切换焦点。
AddDiaryController类:
代码中提到的 AddDiaryController 是一个未展示的类,但根据上下文,它应该包含添加日记到数据存储、关闭写日记界面、更新导航栏可见性等逻辑。

4.将应用密码加密保存与文件中,每次登陆获取密码并对比:

public class LoginDirectActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText edit_input_text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_direct_login);
        bindView();
    }
    private void bindView() {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        edit_input_text = findViewById(R.id.edit_login2_input_text);
        Button btn_comeIn = findViewById(R.id.btn_login2_comeIn);
        btn_comeIn.setOnClickListener(this);
        TextView tv_setPsw = findViewById(R.id.tv_setPsw);
        tv_setPsw.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (R.id.tv_setPsw == id) {
            Intent setPsw_intent = new Intent(LoginDirectActivity.this, LoginActivity.class);
            startActivity(setPsw_intent);
            LoginDirectActivity.this.finish();
        } else if (R.id.btn_login2_comeIn == id) {
            String psw = edit_input_text.getText().toString().trim();
            if (psw.isEmpty()) {
                Toast.makeText(this, getString(R.string.password_is_not_empty_toast), Toast.LENGTH_SHORT).show();
                return;
            }
            String readInfoByContext = FileUtils.readInfoByContext(this);
            if (psw.equals(readInfoByContext)) {
                Toast.makeText(this, getString(R.string.login_success_toast), Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(this, MainActivity.class);
                startActivity(intent);
            } else {
                Toast.makeText(this, getString(R.string.password_is_not_correct_toast), Toast.LENGTH_SHORT).show();
            }
        }
    }

代码定义了一个名为 LoginDirectActivity 的 Activity 类,它实现了直接登录的功能。以下是代码的主要功能:
Activity布局设置:setContentView 方法用于设置 LoginDirectActivity 的布局为 activity_direct_login。
视图绑定:bindView 方法用于初始化界面元素,包括设置状态栏透明、获取 EditText 输入框、登录按钮和设置密码的 TextView,并为它们设置点击监听器。
点击事件处理:onClick 方法用于处理用户点击事件。当用户点击设置密码的 TextView 时,会启动 LoginActivity 并关闭当前 Activity。当用户点击登录按钮时,会获取输入的密码,检查是否为空,然后与存储在本地的密码进行比对。如果密码正确,则显示登录成功的提示,并跳转到 MainActivity;如果密码错误,则显示密码不正确的提示。
密码读取:使用 FileUtils.readInfoByContext 方法来读取存储在本地的密码信息。
Toast提示:使用 Toast 类来显示密码相关的提示信息。
Intent跳转:使用 Intent 来实现 Activity 之间的跳转。

5.使用SharedPrefrenced存储日记标题及内容:

public final class SharedPreferencesUtils {
    private static final SimpleArrayMap<String, SharedPreferencesUtils> mCaches = new SimpleArrayMap<>();
    private SharedPreferences mSharedPreferences;
    private SharedPreferencesUtils(final String spName, final int mode) {
        mSharedPreferences = YyApplication.get().getSharedPreferences(spName, mode);
    }

    public static SharedPreferencesUtils getInstance(String spName) {
        SharedPreferencesUtils utils = mCaches.get(spName);
        if (utils == null) {
            utils = new SharedPreferencesUtils(spName, Context.MODE_PRIVATE);
        }
        return utils;
    }

    public void put(final String key, final String value) {
        mSharedPreferences.edit().putString(key, value).apply();
    }

    public String get(final String key) {
        return mSharedPreferences.getString(key, "");
    }

    public void remove(final String key) {
        mSharedPreferences.edit().remove(key).apply();
    }
}

代码定义了一个名为 SharedPreferencesUtils 的工具类,它封装了对 SharedPreferences 的操作,使得在Android应用中进行数据存储和读取变得更加方便。以下是代码的主要功能:
单例模式:使用 SimpleArrayMap 作为缓存来存储 SharedPreferencesUtils 实例,确保每个 SharedPreferences 名称(spName)只对应一个 SharedPreferencesUtils 对象。
私有构造函数:SharedPreferencesUtils 的构造函数是私有的,它接受一个 spName(存储文件名)和一个 mode(访问模式),用于初始化 SharedPreferences 对象。
获取实例:getInstance 方法是一个公共静态方法,用于获取 SharedPreferencesUtils 的实例。如果缓存中不存在对应的实例,则创建一个新的实例。
数据存储:put 方法用于将键值对数据存储到 SharedPreferences 中。它接受一个键(key)和一个值(value),并将它们以字符串的形式存储。
数据读取:get 方法用于从 SharedPreferences 中读取数据。它接受一个键(key),并返回与该键关联的字符串值。如果键不存在,则返回空字符串。
数据移除:remove 方法用于从 SharedPreferences 中移除指定键的数据。

6.实验结果预览

皮卡日记

五、实验过程中遇到的问题及解决办法

问题:手机nova 8开启开发者模式,仍然无法与电脑上的android studio相连接,无法在手机上调试皮卡日记app。
解决办法:在android studio中以apk包的形式导出文件,发至微信上,用夸克浏览器安装,就可以在手机上调试。

六、实验结果总结与分析

在开发“皮卡日记”这个Android应用的过程中,我深刻体会到了将理论知识转化为实践技能的重要性。通过亲手编写代码,我不仅加深了对Android开发框架的理解,还学会了如何将抽象的概念具体化,使之成为用户界面和交互的组成部分。在实现Activity与Fragment的数据传递和页面更新时,我学会了如何设计模块化和可重用性高的代码,这对于提升应用的稳定性和可维护性至关重要。
在处理数据存储和加密时,我意识到了保护用户隐私的重要性。通过使用SharedPreference和文件存储,我学会了如何安全地保存用户的日记数据,并通过加密技术确保这些数据的安全性。此外,Android权限管理的学习让我认识到了合理请求用户权限的必要性,这不仅关乎应用的功能实现,更关系到用户的信任和满意度。
在UI设计方面,我通过实践了解到,一个直观、美观的用户界面对于提升用户体验至关重要。使用各种控件和布局,我学会了如何根据用户的操作习惯和视觉偏好来设计界面,使“皮卡日记”不仅功能全面,而且易于使用。自定义View的开发,尤其是底部弹窗和圆形头像,锻炼了我的创新思维和编程技巧,让我认识到了在细节上追求完美的重要性。
使用Glide框架进行图片加载的经历,让我体会到了现代开发工具的高效和便捷。它简化了图片处理的复杂性,让我能够专注于应用的其他功能开发。此外,自定义应用图标的过程,让我认识到了品牌形象在用户心中的重要性,一个独特的图标可以显著提升应用的识别度。
通过这次实验,我学会了如何将一个想法从概念转化为一个完整的产品。这个过程不仅提升了我的编程技能,更锻炼了我的项目管理能力、解决问题的能力和创新能力。我相信这些经验将对我的未来职业生涯产生深远的影响。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值