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

1.实验目的

本次实验旨在对本学期所学的内容主要包括Android四大组件,各种常用的布局控件,以及数据持久化存储和多媒体音频使用等基础知识进行进行回顾并进行初步的实现,对Android开发的基本框架和流程有一个初步的了解,为今后进行Android开发打下坚实的基础。因此没有导入任何外部代码和框架而使用原生的功能,以便保持思路清晰,不被复杂的晦涩的陌生代码所混淆

2.实验内容

1.使用Intent实现Atcivity的显式跳转、隐式跳转、Activity间传送数据,跳转到浏览器、拨打电话界面等功能
2.实现BroadcastReceiver基本功能:发送标准广播,注册静态BroadcastReceiver接收广播
3.数据持久化存储之文件存储的基本功能实现
4.使用VideoView实现视频播放,并提供暂停、重新播放等功能
5.使用MediaPlayer实现给应用装饰背景音乐
6.基本布局控件ImageView、ProgressBar等配合实现简单的幻灯片播放

3.实验环境

开发环境:Android Studio Koala | 2024.1.1
运行环境:IQOO Neo9 Pro (Android14)

4.实验过程与分析

4.1 使用Intent实现Atcivity的显式跳转、隐式跳转、Activity间传送数据,跳转到浏览器、拨打电话界面等功能
4.1.1 使用Intent从MainActivity显式跳转到IntentTest

intentTest.setOnClickListener {
            val intent = Intent(this, IntentTest::class.java)
            startActivity(intent)
        }

4.1.2 在IntentTest中调用浏览器和电话薄

bing.setOnClickListener {
            val intent = Intent(Intent.ACTION_VIEW)
            intent.data = Uri.parse("https://cn.bing.com")
            startActivity(intent)
        }

        phone.setOnClickListener {
            val intent = Intent(Intent.ACTION_DIAL)
            startActivity(intent)
        }

4.1.3 跳转到IntentTestNext并在Intent中传送数据

goToNextActivity.setOnClickListener {
            val intent = Intent(this, IntentTestNext::class.java)
            intent.putExtra("extraData", sendData.text)
            startActivityForResult(intent, 1)
        }

4.1.4 IntentTestNext接收数据并显示到界面中,退出时返回数据到IntentTest

receiveData.text = intent.getCharSequenceExtra("extraData")
        goToPreviousActivity.setOnClickListener {
            val intent = Intent()
            intent.putExtra("returnData", returnData.text)
            setResult(RESULT_OK, intent)
            finish()
        }

4.1.5 IntentTest中接收返回数据并显示到界面中

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            1 -> if (resultCode == RESULT_OK) {
                val receiveData0 = findViewById<TextView>(R.id.receiveData0)
                receiveData0.text = data?.getCharSequenceExtra("returnData")
            }
        }
    }

4.1.6 结果展示

4.2 实现BroadcastReceiver基本功能:发送标准广播,注册静态BroadcastReceiver接收广播
4.2.1 在清单文件中静态注册BroadcastReceiver

<receiver
            android:name=".ReceiverTest"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.gong20212411.mylastapplication.MY_BROADCAST" />
            </intent-filter>
        </receiver>

4.2.2 收到广播后简单使用Toast

class ReceiverTest : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "收到广播", Toast.LENGTH_SHORT).show()
    }
}

4.2.3 在MainActivity中发送相应的广播

sendMessage.setOnClickListener {
            val intent = Intent("com.gong20212411.mylastapplication.MY_BROADCAST")
            intent.setPackage(packageName)
            sendBroadcast(intent)
        }

4.2.4 结果展示

4.3 数据持久化存储之文件存储的基本功能实现
4.3.1 将文件中的内容加载到界面中

fun load(): String {
        val content = StringBuilder()
        try {
            val reader = BufferedReader(InputStreamReader(openFileInput("record")))
            reader.use {
                reader.forEachLine {
                    content.append(it)
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return content.toString()
    }

4.3.2 将数据保存到文件中功能实现

save.setOnClickListener {
            save(record.text.toString())
            isSave = true
            Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show()
        }
fun save(text: String) {
        try {
            val writer =
                BufferedWriter(OutputStreamWriter(openFileOutput("record", Context.MODE_PRIVATE)))
            writer.use {
                it.write(text)
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

4.3.3 如果未保存退出时弹出对话框提示是否保存

exit.setOnClickListener {
            if (!isSave) {
                AlertDialog.Builder(this).apply {
                    setTitle("提示")
                    setMessage("尚未保存,确定要退出吗?")
                    setPositiveButton("退出") { dialog, which ->
                        finish()
                    }
                    setNegativeButton("取消") { dialog, which ->
                    }
                    show()
                }
            } else {
                finish()
            }
        }

        record.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
            override fun afterTextChanged(s: Editable) {
                isSave = false
            }
        })

4.3.4 用户直接使用back退出时,修改的数据尚未保存,弹出Toast提示

override fun onBackPressed() {
        super.onBackPressed()
        if (!isSave) {
            Toast.makeText(this, "您真是勇士,我还没来得及保存呢", Toast.LENGTH_SHORT).show()
        }
    }

4.3.5 结果展示

4.4 使用VideoView实现视频播放,并提供暂停、重新播放等功能
4.4.1 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <VideoView
        android:id="@+id/moon3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="播放"
        android:textAllCaps="false"
        android:textSize="20sp" />

    <Button
        android:id="@+id/pause"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="暂停"
        android:textAllCaps="false"
        android:textSize="20sp" />

    <Button
        android:id="@+id/resume"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="重新播放"
        android:textAllCaps="false"
        android:textSize="20sp" />

</LinearLayout>

4.4.2 相应的Activity实现播放、暂停、重新播放等功能,Activity销毁时需要释放视频播放器

class Moon3 : AppCompatActivity() {
    private lateinit var moon3: VideoView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_moon3)
        moon3 = findViewById<VideoView>(R.id.moon3)
        val start = findViewById<Button>(R.id.start)
        val pause = findViewById<Button>(R.id.pause)
        val resume = findViewById<Button>(R.id.resume)
        val uri = Uri.parse("android.resource://$packageName/${R.raw.moon3}")
        moon3.setVideoURI(uri)
        start.setOnClickListener {
            if (!moon3.isPlaying) {
                moon3.start()
            }
        }
        pause.setOnClickListener {
            if (moon3.isPlaying) {
                moon3.pause()
            }
        }
        resume.setOnClickListener {
            if (moon3.isPlaying) {
                moon3.resume()
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        moon3.suspend()
    }
}

4.4.3 结果展示

4.5 使用MediaPlayer实现给应用装饰背景音乐
4.5.1 这里使用菜单功能以节省界面空间

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/music0"
        android:title="Turn Out The Night" />
    <item
        android:id="@+id/music1"
        android:title="Steppin'Out" />
    <item
        android:id="@+id/music2"
        android:title="My Head &amp; My Heart" />
    <item
        android:id="@+id/music3"
        android:title="One Summer Day" />
    <item
        android:id="@+id/stop"
        android:title="停止" />
</menu>

4.5.2 assets文件夹中放入相应的音频文件
在这里插入图片描述
4.5.3 MainActivity中显示菜单栏、实现播放暂停功能,Activity销毁时释放MediaPlayer

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.music0 -> play("TurnOutTheNight.mp3")
            R.id.music1 -> play("Steppin'Out.mp3")
            R.id.music2 -> play("MyHead&MyHeart.mp3")
            R.id.music3 -> play("OneSummerDay.mp3")
            R.id.stop -> stop()
        }
        return true
    }

    fun stop() {
        mediaPlayer.reset()
    }

    fun play(path: String) {
        if (mediaPlayer.isPlaying) {
            stop()
        }
        val assetsManager = assets
        val fd = assetsManager.openFd(path)
        mediaPlayer.setDataSource(fd.fileDescriptor, fd.startOffset, fd.length)
        mediaPlayer.prepare()
        mediaPlayer.start()
    }

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer.stop()
        mediaPlayer.release()
    }

4.6 基本布局控件ImageView、ProgressBar等配合实现简单的幻灯片播放
4.6.1 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image"
        android:layout_width="400dp"
        android:layout_height="350dp"
        android:layout_gravity="center"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="20sp" />

    <ProgressBar
        android:id="@+id/bar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="6" />

    <Button
        android:id="@+id/next"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="下一页" />
</LinearLayout>

4.6.2 Activity中对点击下一张实现幻灯片切换以及相应文字切换,同时进度条++

class AndroidForMe : AppCompatActivity() {
    @SuppressLint("WrongViewCast")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.android_for_me)
        val image = findViewById<ImageView>(R.id.image)
        val text = findViewById<TextView>(R.id.text)
        val bar = findViewById<ProgressBar>(R.id.bar)
        val next = findViewById<Button>(R.id.next)
        val imageResources = listOf(
            R.drawable.ic_launcher_0,
            R.drawable.ic_launcher_1,
            R.drawable.ic_launcher_2,
            R.drawable.ic_launcher_3,
            R.drawable.ic_launcher_4,
            R.drawable.ic_launcher_5,
            R.drawable.ic_launcher_6
        )
        val texts = listOf(
            "这个学期我们踏上了与我们形影不离的最亲近的朋友——Android的相识之旅",
            "这是我做的第一个Android应用,简简单单的一个Hello,是轻松愉快的开始",
            "第二个作品:计算器。凝聚了我使用双栈进行表达式求值的执着。执着耗费了我很多精力,但我的计算器功能更强大,这令我感到自豪",
            "第三个作品:service。gong出品,必属精品!",
            "第四个作品:socket通信。依旧凝聚了我多线程,保存聊天记录的执着,代码调试很折磨,但我觉得很值得",
            "执着源于热爱,源于我对认识和开发老朋友Android的激情,可惜事务繁忙,之后我花在Android的时间就很少了,也没能做出其它令我满意的作品。本学期的课程虽然结束了,但是我与Android的相伴相识之旅远没有结束,它是跟我们形影不离的一个小精灵,默默无闻地在生活的方方面面给我们服务,给我们惊喜,给我们欢乐。它是我们,至少是我最好的朋友。我始终对它保持好奇,永远热爱它!",
            "后会有期"
        )
        bar.progress = 0
        image.setImageResource(imageResources[bar.progress])
        text.text = texts[bar.progress]
        next.setOnClickListener {
            bar.progress = (bar.progress + 1) % 7
            image.setImageResource(imageResources[bar.progress])
            text.text = texts[bar.progress]
        }
    }
}

4.6.3 结果展示

五.实验问题及解决

5.1运行时菜单栏没有显示
Activity中缺少主题,在清单文件中添加下面主题即可
在这里插入图片描述
5.2 使用Intent传递的信息无法获取
Intent中数据类型是Editable,而我之前使用的是getStringExtra,数据类型不匹配,改为下面方法即可(CharSequenceExtra是Editable的父类)
在这里插入图片描述
5.3 某些音频文件无法播放
经过分析,是音频格式的问题,全部使用mp3类型的音频文件即可解决问题

五.实验心得体会

通过本次实践,我深刻体会到了Android开发的几个关键技术点。
首先,Intent机制是Android中实现组件间通信的核心。通过显式Intent,我能够精确控制Activity的跳转,确保用户界面的流畅性。隐式Intent则让我能够利用系统或第三方应用的功能,如拨打电话或打开网页,极大地扩展了应用的交互能力。同时,Intent也方便了Activity间的数据传递,使得应用组件之间的协作更加高效。
其次,BroadcastReceiver的使用让我对Android的事件驱动机制有了更深的理解。通过发送标准广播和注册静态BroadcastReceiver,我能够监听和响应系统或应用内部的广播消息,实现应用的模块间解耦和事件的灵活处理。
数据持久化存储是保证应用数据安全和一致性的关键。我通过文件存储的方式,实现了数据的基本持久化功能,这为应用的稳定性和可靠性提供了保障。
在多媒体处理方面,VideoView和MediaPlayer的使用让我学会了如何在应用中嵌入视频播放和背景音乐。通过实现视频的暂停、重新播放等功能,以及为应用添加背景音乐,我提升了应用的用户体验。
最后,基本布局控件如ImageView和ProgressBar的运用,让我掌握了如何构建用户界面和实现简单的动画效果,如幻灯片播放,这不仅锻炼了我的UI设计能力,也让我对Android的视图系统有了更深入的认识。
在本学期的移动平台开发实践课程中,我深入探索了Android开发的广阔天地。这不仅是一次技术学习的旅程,更是一次思想和实践能力提升的过程。通过这门课程,我不仅掌握了Android开发的基础技能,更在实践中体会到了作为一名开发者的思考方式和解决问题的能力。
首先,Android四大组件的学习让我对应用的架构有了清晰的认识。Activity作为用户交互的窗口,Service在后台默默支撑着长时间运行的任务,Broadcast Receiver让我理解了系统事件的监听与响应,而Content Provider则向我展示了数据共享的标准化方法。这些组件的学习和实践,让我对Android应用的运行机制有了深刻的理解。
Kotlin编程语言的学习,为我打开了一扇新的大门。它的简洁、安全和表现力,让我在编写代码时更加得心应手。Kotlin与Java的无缝兼容,也让我能够在现有的项目中灵活运用两种语言,提高了开发效率。
UI开发部分的学习,让我对Android界面设计有了更深入的认识。从基本的布局到控件的使用,每一个细节都影响着用户体验。通过实践,我学会了如何构建美观且实用的用户界面,这对于提升应用的吸引力至关重要。
实验和实践环节是本学期课程的亮点。六次实验不仅让我掌握了理论知识,更在实际操作中锻炼了我的动手能力。前四次实验中,我亲手搭建了一个计算器应用,这个过程让我深刻体会到了从零到一构建一个应用的全过程。而后两次实验,通过调用百度地图和实现语音识别功能,我学习了如何利用外部API进行开发,这大大拓宽了我的技术视野。
回顾整个学期,我感到自己在Android开发领域取得了显著的进步。我学会了如何分析需求、设计架构、编写代码,并且在实践中不断提升自己的技术能力。然而,我也清楚地认识到,这只是开始,Android开发的道路还很漫长。我将继续努力,不断学习新知识,挑战自我,争取在Android开发的道路上走得更远。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值