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的四大核心组件有了更为清晰和深刻的认识,同时也显著增强了我的实践操作能力。在未来的实际项目开发中,我将能够更加熟练地运用这些组件,以期提升应用程序的整体质量和运行性能。

...全文
295 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
代码转载自:https://pan.quark.cn/s/8ce4326d996e 对于在 CentOS 7 系统中修改网卡配置文件后无法使设置生效的情况,经过实践验证,可以通过使用 nmcli 命令来进行调整。完成修改之后,需要重新启动虚拟机以使更改生效,这样操作流程即告完成。如果设置仍然无法生效,则表明虚拟机在启动过程中所获取的 IP 地址配置并非针对 eth0,此时可以对其它网卡的配置文件进行修改或将其移除。在 CentOS 7 系统中,网络配置的管理机制与早期版本存在差异,主要体现为采用了 Network Manager 服务来负责网络接口的管理。在某些情形下,尽管修改了 `/etc/sysconfig/network-scripts` 目录下的 `ifcfg-eth0` 文件,但网络配置却未能即时生效。此类问题的发生通常源于 CentOS 7 采用了不同于以往的配置读取方法。接下来将具体阐述如何借助 nmcli 命令来处理这一挑战。 以 root 用户身份登录系统并打开终端界面。nmcli 是 Network Manager 提供的命令行界面工具,它支持在命令行环境下执行网络连接的建立、编辑、查询及管理任务。针对修改 eth0 网卡配置的需求,可以遵循以下步骤进行操作: 1. 导航至 `/etc/sysconfig/network-scripts` 目录: ``` cd /etc/sysconfig/network-scripts ``` 2. 检查该目录内是否存在 `ifcfg-eth0.bak` 文件,该备份文件可能是先前调整配置时遗留下来的,若存在可能造成冲突。若发现该文件,可以选择将其删除: ``` [root@localhost netw...
代码转载自:https://pan.quark.cn/s/46fd08fb879c 网管教程 从入门到精通软件篇 ★一。★详尽的xp修复控制台指令及其应用!!! 放入xp(2000)的光盘,安装时选择R,执行修复! Windows XP(涵盖 Windows 2000)的控制台指令是在系统遭遇某些意外状况时的一种极具效用的诊断、检测以及恢复系统功能的工具。笔者确实一直期望能够将这方面的指令进行归纳,此由老范辛苦整理了这份极具价值的秘籍。 Bootcfg bootcfg 命令用于启动配置与故障恢复(对大多数计算机而言,即 boot.ini 文件)。 带有特定参数的 bootcfg 命令仅在运用故障恢复控制台时方可使用。能够在命令行界面下运用带有不同参数的 bootcfg 命令。 用法: bootcfg /default 设定默认引导选项。 bootcfg /add 向引导清单中增添 Windows 安装。 bootcfg /rebuild 重复整个 Windows 安装流程并让用户选择需添加的项目。 注意:运用 bootcfg /rebuild 之前,应先借助 bootcfg /copy 命令备份 boot.ini 文件。 bootcfg /scan 探查用于 Windows 安装的全部磁盘并展示结果。 注意:这些结果被静态存储,并用于当前会话。若在当前会话期间磁盘配置发生变动,为获取更新的探查结果,必须先重启计算机,然后再探查磁盘。 bootcfg /list 列示引导清单中已有的项目。 bootcfg /disableredirect 在启动引导程序中禁用重定向。 bootcfg /redirect [ PortBaudRrate] |[ useBio...

98

社区成员

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

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