20212305 2023-2024-2 《移动平台开发与实践》第3次作业

20212305杨贯宇 2024-06-29 22:30:10

20212305 2023-2024-2 《移动平台开发与实践》第3次作业

1.实验内容

本周学习内容如下:

1.1 关于SQLite数据库:

SQLite是一款轻量级的嵌入式关系数据库系统。其特色在于它的跨平台兼容性和无需复杂配置。为了保持其简洁性,SQLite并不需要单独的服务器流程,用户可以直接与数据库进行交互,省去了通过服务器的中间环节。正因如此,SQLite在嵌入式设备及小型应用中广受欢迎。

1.2 谈谈ContentResolver:

在Android系统中,ContentResolver是一个核心类,它负责管理应用与不同组件(例如活动、服务、广播接收器等)之间的数据交流。ContentResolver为访问和修改应用数据提供了一个标准化的方法,这些数据可能存储在应用的私有空间或由其他应用提供。它经常与ContentProvider配合使用,后者作为数据源的抽象,为数据访问和操作提供了接口。

1.3 泛型在Kotlin中的角色:

在Kotlin编程语言中,泛型是一个关键特性,它允许在定义类、接口、函数或对象时引入类型参数。这样做不仅能提升代码的灵活性和可重用性,还能确保类型安全。总的来说,虽然Kotlin中的泛型功能与Java相似,但其语法更为简练,并通过约束等特性提供了更高的灵活性。

2.实验过程

2.1实验目的:

1.掌握Android四大组件(Activity、Service、BroadcastReceiver、ContentProvider)的基本概念和使用方法。
2.学会如何在实际开发中灵活运用这四大组件构建Android应用程序。
3.提高Android应用开发能力和实践操作能力。

2.2实验环境:

1.Android Studio开发环境
2.Android模拟器或真实Android设备

2.3实验内容:

实验步骤

1 Activity组件实践步骤:

1.1创建一个activity并添加UI元素
选择No Activity

img

创建FirstActivity,SecondActivity

img


img

按照书上的代码写FirstActivity.kt、SecondActivity.kt,两个相应的xml文件和AndroidManifest文件
FirstActivity

package com.example.project3

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.activity.ComponentActivity

class FirstActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_first)

        val button1: Button = findViewById(R.id.button1)
        button1.setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            startActivity(intent)
        }
    }
}

activity_first.xml

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


    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button1" />
</LinearLayout>

SecondActivity

package com.example.project3

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.activity.ComponentActivity

class SecondActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        val button2: Button = findViewById(R.id.button2)

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

activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 2"
        />
</LinearLayout>

以及AndroidManifest文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" >

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Project3"
        tools:targetApi="31" >
        <activity
            android:name=".SecondActivity"
            android:exported="false" />
        <activity
            android:name=".FirstActivity"
            android:label="This is FirstActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

运行效果如视频所示:

1.2实现Activity之间的传值
修改firstActivity中的代码,使用Intent提供的putExtra()方法的重载

package com.example.project3

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.activity.ComponentActivity

class FirstActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_first)

        val button1: Button = findViewById(R.id.button1)
        button1.setOnClickListener {
            val data = "Hello SecondActivity"
            val intent = Intent(this, SecondActivity::class.java)
            intent.putExtra("extra_data", data)
            startActivity(intent)
        }
    }
}

在SecondActivity中将传递的数据取出,并打印出来,代码如下所示:

package com.example.project3

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.activity.ComponentActivity
import androidx.appcompat.app.AppCompatActivity

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        val extraData = intent.getStringExtra("extra_data")
        Log.d("SecondActivity", "extra data is $extraData")
    }
}

跳转效果如下:

可以看出和之前基本相同
但是在logcat中可以看到传值:

img

1.3了解Activity的生命周期
Activity类中定义了7个回调方法,覆盖了Activity生命周期的每一个环节。
onCreate(): 此方法会在Activity首次创建时被系统调用。在此阶段,您应当执行Activity的初始化工作,例如加载用户界面布局、初始化变量、设置监听器等。这是配置Activity界面的关键步骤。
onStart(): 当Activity从不可见状态变为可见状态时,会触发此方法。尽管此时Activity对用户可见,但尚未准备好与用户交互。
onResume(): 此方法在Activity准备完毕,可以开始与用户交互之前被调用。当Activity位于任务栈顶且处于活动状态时,这个方法将被执行。此时,应用可以响应用户输入。
onPause(): 当系统准备启动另一个Activity或恢复一个已存在的Activity时,会调用此方法。在此方法中,建议释放占用CPU的资源,并保存关键数据。但需注意,该方法的执行应迅速,以避免影响新Activity的及时显示和交互。
onStop(): 当Activity完全不可见时,会触发此方法。与onPause()不同的是,如果新启动的Activity是一个对话框风格的界面,那么原Activity会执行onPause(),但onStop()则不会执行,因为原Activity仍部分可见。
onDestroy(): 在Activity被销毁并释放其占用的资源之前,系统会调用此方法。一旦执行完此方法,Activity的状态将变为“已销毁”,且不可再被使用。
onRestart(): 如果Activity从停止状态回到运行状态,即用户重新回到了这个Activity,那么在它再次变为可见之前,系统会调用此方法。这标志着Activity的重新启动过程开始。
以上7个方法中除了onRestart()方法,其他都是两两相对的,从而又可以将Activity分为以下3种生存期。
完整生存期:Activity的完整生存期始于onCreate()方法的调用,终于onDestroy()方法的执行。在这一阶段,Activity经历了从创建到销毁的整个过程。通常,onCreate()方法中会完成Activity的各种初始化设置,如加载布局、初始化变量等,而onDestroy()方法则用于执行清理工作,如释放资源,以确保Activity被销毁时不会遗留任何可能导致内存泄漏的对象。

可见生存期:Activity的可见生存期从onStart()方法开始,到onStop()方法结束。在这个期间,Activity对用户是可见的,即使它可能暂时无法响应用户的操作。这个阶段的开始和结束是管理用户可见资源的关键时刻。开发者通常会在onStart()中加载必要的资源,以确保当Activity变为可见时,用户界面能够正确显示。相反,在onStop()方法中,会释放这些资源,以优化内存使用,特别是当Activity不再可见时。

前台生存期:Activity的前台生存期是指从onResume()方法被调用开始,到onPause()方法执行结束的这一段时间。在这个阶段,Activity处于活动状态,可以响应用户的操作。这是用户与应用程序交互最频繁的状态,因此,确保Activity在这个状态下的性能和响应性至关重要。开发者需要确保在这一阶段处理好用户输入,并及时更新用户界面以反映用户的操作。

2Service组件实践

2.1创建一个Service,用于在后台执行长时间运行的任务
新建一个Empty Views Activity

img

2.2通过Intent启动和停止Service
按照书上的提示修改代码:
创建MyService.kt并修改代码

package com.example.project3

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log

class MyService : Service() {
    override fun onBind(intent: Intent): IBinder {
        TODO("Return the communication channel to the service.")
    }
    override fun onCreate() {
        super.onCreate()
        Log.d("MyService", "onCreate executed")
    }
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d("MyService", "onStartCommand executed")
        return super.onStartCommand(intent, flags, startId)
    }
    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyService", "onDestroy executed")
    }
}

Mainactivity

package com.example.project3

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button

class MainActivity:AppCompatActivity(){
    override fun onCreate(savedInstanceState:Bundle?){
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val startServiceBtn: Button = findViewById(R.id.startServiceBtn)
        startServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            startService(intent)// 启动 Service
        }
        val stopServiceBtn:Button = findViewById(R.id.stopServiceBtn)
        stopServiceBtn.setOnClickListener{
            val intent = Intent(this, MyService::class.java)
            stopService(intent)// 停止Service
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/startServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Service" />
    <Button
        android:id="@+id/stopServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Service" />
</LinearLayout>

效果如视频和截图所示(电脑录屏不知为何用不了,所以只能logcat截屏):


img

可以看到运行成功了

2.3实现Service与Activity之间的通信
还是按照书上的步骤,修改代码
修改后的代码如下:
MyService

package com.example.project3

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log

class MyService : Service() {
    private val mBinder = DownloadBinder()
    class DownloadBinder : Binder() {
        fun startDownload() {
            Log.d("MyService", "startDownload executed")
        }
        fun getProgress(): Int {
            Log.d("MyService", "getProgress executed")
            return 0
        }
    }
    override fun onBind(intent: Intent): IBinder {
        return mBinder
    }
    override fun onCreate() {
        super.onCreate()
        Log.d("MyService", "onCreate executed")
    }
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d("MyService", "onStartCommand executed")
        return super.onStartCommand(intent, flags, startId)
    }
    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyService", "onDestroy executed")
    }
}

MainActivity

package com.example.project3

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.IBinder
import android.widget.Button

class MainActivity:AppCompatActivity(){
    lateinit var downloadBinder: MyService.DownloadBinder
    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            downloadBinder = service as MyService.DownloadBinder
            downloadBinder.startDownload()
            downloadBinder.getProgress()
        }
        override fun onServiceDisconnected(name: ComponentName) {
        }
    }
    override fun onCreate(savedInstanceState:Bundle?){
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val startServiceBtn: Button = findViewById(R.id.startServiceBtn)
        startServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            startService(intent)// 启动 Service
        }
        val stopServiceBtn:Button = findViewById(R.id.stopServiceBtn)
        stopServiceBtn.setOnClickListener{
            val intent = Intent(this, MyService::class.java)
            stopService(intent)// 停止Service
        }
        val bindServiceBtn:Button = findViewById(R.id.bindServiceBtn)
        bindServiceBtn.setOnClickListener {
            val intent = Intent(this, MyService::class.java)
            bindService(intent, connection, Context.BIND_AUTO_CREATE) // 绑定Service
        }
        val unbindServiceBtn:Button = findViewById(R.id.unbindServiceBtn)
        unbindServiceBtn.setOnClickListener {
            unbindService(connection) // 解绑Service
        }

    }
}

xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/startServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start Service" />
    <Button
        android:id="@+id/stopServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop Service" />
    <Button
        android:id="@+id/bindServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind Service" />
    <Button
        android:id="@+id/unbindServiceBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Unbind Service" />
</LinearLayout>

运行效果如视频和截图所示:


img

3BroadcastReceiver组件实践

新建一个项目,命名为:project3
按照书上的提示,创建三个类:
ActivityCollector类用于管理所有的Activity
BaseActivity类作为所有Activity的父类
LoginActivity类来作为登录界面
创建类的方式如图:

img

之后跟着书上的步骤修改代码,如下为最终代码结果:
ActivityCollector.kt

package com.example.project3

import android.app.Activity

object ActivityCollector {
    private val activities = ArrayList<Activity>()
    fun addActivity(activity: Activity) {
        activities.add(activity)
    }
    fun removeActivity(activity: Activity) {
        activities.remove(activity)
    }
    fun finishAll() {
        for (activity in activities) {
            if (!activity.isFinishing) {
                activity.finish()
            }
        }
        activities.clear()
    }
}

BaseActivity.kt

package com.example.project3

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity

open class BaseActivity : AppCompatActivity() {
    private lateinit var private: ForceOfflineReceiver
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityCollector.addActivity(this)
    }
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onResume() {
        super.onResume()
        val intentFilter = IntentFilter()
        intentFilter.addAction("com.example.project3.FORCE_OFFLINE")
        private = ForceOfflineReceiver()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            registerReceiver(private, intentFilter,Context.RECEIVER_EXPORTED)
        }
    }
    override fun onPause() {
        super.onPause()
        unregisterReceiver(private)
    }
    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }
    inner class ForceOfflineReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            AlertDialog.Builder(context).apply {
                setTitle("Warning")
                setMessage("You are forced to be offline. Please try to login again.")
                setCancelable(false)
                setPositiveButton("OK") { _, _ ->
                    ActivityCollector.finishAll() // 销毁所有Activity
                    val i = Intent(context, LoginActivity::class.java)
                    context.startActivity(i) // 重新启动LoginActivity
                }
                show()
            }
        }
    }
}

LoginActivity.kt

package com.example.project3

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast

class LoginActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)
        val login: Button = findViewById(R.id.login)
        val accountEdit: EditText = findViewById(R.id.accountEdit)
        val passwordEdit: EditText = findViewById(R.id.passwordEdit)
        login.setOnClickListener {
            val account = accountEdit.text.toString()
            val password = passwordEdit.text.toString()
            // 如果账号是admin且密码是123456,就认为登录成功
            if (account == "admin" && password == "123456") {
                val intent = Intent(this, MainActivity::class.java)
                startActivity(intent)
                finish()
            } else {
                Toast.makeText(this, "account or password is invalid",
                    Toast.LENGTH_SHORT).show()
            }
        }
    }
}

MainActivity.kt

package com.example.project3

import android.content.Intent
import android.os.Bundle
import android.widget.Button

class MainActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val forceOffline: Button = findViewById(R.id.forceOffline)
        forceOffline.setOnClickListener {
            val intent = Intent("com.example.project3.FORCE_OFFLINE")
            sendBroadcast(intent)
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/forceOffline"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send force offline broadcast" />
</LinearLayout>

activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="Account:" />
        <EditText
            android:id="@+id/accountEdit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical" />
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="Password:" />
        <EditText
            android:id="@+id/passwordEdit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"
            android:inputType="textPassword" />
    </LinearLayout>
    <Button
        android:id="@+id/login"
        android:layout_width="200dp"
        android:layout_height="60dp"
        android:layout_gravity="center_horizontal"
        android:text="Login" />
</LinearLayout>

最终效果如下方:

img

4ContentProvider组件实践

4.1创建一个ContentProvider,用于共享数据给其他应用程序
首先先做一下准备工作,在虚拟机上创建两个联系人

img

之后按照步骤修改各代码
MainActivity.kt

package com.example.project3

import android.annotation.SuppressLint
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.ContactsContract
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

class MainActivity : ComponentActivity() {

    private val contactsList = ArrayList<String>()
    private lateinit var adapter: ArrayAdapter<String>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList)
        val contactsView: ListView = findViewById(R.id.contactsView)
        contactsView.adapter = adapter
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS)
            != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_CONTACTS), 1)
        } else {
            readContacts()
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when(requestCode){
            1->{
                if (grantResults.isNotEmpty()&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    readContacts()
                }else{
                    Toast.makeText(this,"you denied the permisson",Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
    @SuppressLint("Range")
    private fun readContacts() {
        // 查询联系人数据
        contentResolver.query(
            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
            null, null, null, null)?.apply {
            while (moveToNext()) {
                // 获取联系人姓名
                val displayName = getString(getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
                // 获取联系人手机号
                val number = getString(getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
                contactsList.add("$displayName\\n$number")
            }
            adapter.notifyDataSetChanged()
            close()
        }
    }
}

activity_main.xml

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

    <ListView
        android:id="@+id/contactsView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </ListView>

</LinearLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Project3"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

运行效果如下方视频所示

5.学习中遇到的问题及解决

问题1:实验做到一半Androidstudio的虚拟机死机了
问题1解决方案:重启了好几遍都无法正常打开虚拟设备,自己摸索着重新创建了一个新的虚拟设备。

6.学习感悟、思考等

通过亲身实践,我深刻领悟了每个组件的功能特性和运作方式,并掌握了如何在实际开发环境中巧妙运用它们来构建Android应用程序。在实验推进的过程中,我遭遇了一些挑战,但借助查阅相关资料和参考教材,我成功地克服了这些难题,并且对Android开发技术有了更为深刻的理解。
此次实验经历,使我对Android的四大核心组件有了更为清晰和深刻的认识,同时也显著增强了我的实践操作能力。在未来的实际项目开发中,我将能够更加熟练地运用这些组件,以期提升应用程序的整体质量和运行性能。

...全文
136 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

98

社区成员

发帖
与我相关
我的任务
社区描述
网络攻防作业
网络安全 高校
社区管理员
  • blackwall0321
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧