我正在开发 pluralsight 的 android note keeper 应用程序,我遇到了两个问题:第一个是该活动旨在使用 ListView 显示笔记列表,但没有显示。其次,我有一个浮动操作按钮,应该允许我创建一个新的笔记,但是当我点击它时,应用程序崩溃了。我正在使用 genymotion 模拟器来运行应用程序。
我发现我的 nav_graph 中没有 NavHostFragment,但我已经实现了它,但它仍然无法正常工作 这是错误信息。
--------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.nokeeper4, PID: 3981
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.nokeeper4/com.example.nokeeper4.MainActivity}: android.view.InflateException: Binary XML file line #28 in com.example.nokeeper4:layout/activity_main: Binary XML file line #28 in com.example.nokeeper4:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3431)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3595)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7660)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: android.view.InflateException: Binary XML file line #28 in com.example.nokeeper4:layout/activity_main: Binary XML file line #28 in com.example.nokeeper4:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: android.view.InflateException: Binary XML file line #28 in com.example.nokeeper4:layout/activity_main: Error inflating class androidx.fragment.app.FragmentContainerView
Caused by: java.lang.RuntimeException: Exception inflating com.example.nokeeper4:navigation/nav_graph2 line 15
at androidx.navigation.NavInflater.inflate(NavInflater.kt:70)
at androidx.navigation.NavController.setGraph(NavController.kt:1039)
at androidx.navigation.fragment.NavHostFragment.onCreate(NavHostFragment.kt:155)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:3090)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:257)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1899)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1823)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1729)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:323)
at androidx.fragment.app.FragmentContainerView.<init>(FragmentContainerView.kt:158)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:53)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:136)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:248)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:227)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
at com.example.nokeeper4.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:60)
at com.example.nokeeper4.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:54)
at com.example.nokeeper4.MainActivity.onCreate(MainActivity.kt:25)
at android.app.Activity.performCreate(Activity.java:8000)
E/AndroidRuntime: at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3404)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3595)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7660)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.UnsupportedOperationException: Cannot add action 0 to Destination(com.example.nokeeper4:id/NoteListActivity) label=Nokeeper4 class=com.example.nokeeper4.NoteListActivity as it does not support actions, indicating that it is a terminal destination in your navigation graph and will never trigger actions.
at androidx.navigation.NavDestination.putAction(NavDestination.kt:445)
at androidx.navigation.NavInflater.inflateAction(NavInflater.kt:322)
at androidx.navigation.NavInflater.inflate(NavInflater.kt:107)
at androidx.navigation.NavInflater.inflate(NavInflater.kt:114)
at androidx.navigation.NavInflater.inflate(NavInflater.kt:64)
... 39 more
I/Process: Sending signal. PID: 3981 SIG: 9
这是我的项目 nav_graph2.xml 文件。
<activity
android:id="@+id/NoteListActivity"
android:name="com.example.nokeeper4.NoteListActivity"
android:label="@string/notelist_label"
tools:layout="@layout/activity_note_list">
<action
app:destination="@id/MainActivity"/>
</activity>
<activity
android:id="@+id/MainActivity"
android:name="com.example.nokeeper4.MainActivity"
android:label="@string/main_label"
tools:layout="@layout/activity_main">
<action
app:destination="@id/NoteListActivity" />
</activity>>
\</navigation\>\`
DataManager.kt 文件。
object DataManager {
val courses = HashMap\<String, CourseInfo\>()
val notes = ArrayList\<NoteInfo\>()
init{
initializeCourses()
initializeNotes()
}
private fun initializeCourses(){
var course = CourseInfo("android_intents","Android Programming with Intents")
courses.set(course.courseId, course)
course = CourseInfo("android_async", "Android Async Programming and Services")
courses.set(course.courseId, course)
course = CourseInfo("java_lang", "Java Fundamentals: The Java Language")
courses.set(course.courseId, course)
course = CourseInfo("java_core", "Java Fundamentals: The core platform")
courses.set(course.courseId, course)
}
private fun initializeNotes(){
}
}`
activity_note_list.xml 文件。
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NoteListActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="100dp">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="@string/new_note"
android:src="@drawable/baseline_add_white_24"
app:backgroundTint="#9C27B0" />
<include
android:id="@+id/contentNoteList"
layout="@layout/content_note_list" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
NoteListActivity.kt 文件。
package com.example.nokeeper4
import android.content.Intent
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
import com.example.nokeeper4.databinding.ActivityNoteListBinding
class NoteListActivity : AppCompatActivity() {
private lateinit var binding: ActivityNoteListBinding
private lateinit var listNotes: ListView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityNoteListBinding.inflate(layoutInflater)
setContentView(binding.root)
listNotes = findViewById(R.id.listNotes)
binding.fab.setOnClickListener {
val activityIntent = Intent(this, MainActivity::class.java)
startActivity(activityIntent)
}
listNotes.adapter = ArrayAdapter(
this,
android.R.layout.simple_list_item_1,
DataManager.notes)
listNotes.setOnItemClickListener { _, _, position, _ ->
val activityIntent = Intent(this, MainActivity::class.java)
activityIntent.putExtra(NOTE_POSITION, position)
startActivity(activityIntent)
}
}
override fun onResume() {
super.onResume()
(listNotes.adapter as ArrayAdapter<*>).notifyDataSetChanged()
}
}
activity_main.xml 文件。
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.Nokeeper4.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/Theme.Nokeeper4.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_frag"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navGraph="@navigation/nav_graph2"/>
<include
android:id="@+id/contentMain"
layout="@layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MainActivity.kt 文件。
package com.example.nokeeper4
import android.annotation.SuppressLint
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.Spinner
import com.example.nokeeper4.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var notePosition = POSITION_NOT_SET
private lateinit var spinnerCourses: Spinner
private lateinit var textNoteTitle: EditText
private lateinit var textNoteText: EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
spinnerCourses = findViewById(R.id.spinnerCourses)
textNoteTitle = findViewById(R.id.textNoteTitle)
textNoteText = findViewById(R.id.textNoteText)
val adapterCourses = ArrayAdapter<CourseInfo>(this,
android.R.layout.simple_spinner_item,
DataManager.courses.values.toList())
adapterCourses.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinnerCourses.adapter = adapterCourses
notePosition = savedInstanceState?.getInt(NOTE_POSITION, POSITION_NOT_SET) ?:
intent.getIntExtra(NOTE_POSITION,POSITION_NOT_SET)
if (notePosition != POSITION_NOT_SET)
displayNote()
else{
DataManager.notes.add(NoteInfo())
notePosition = DataManager.notes.lastIndex
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(NOTE_POSITION, notePosition)
}
private fun displayNote() {
val note = DataManager.notes[notePosition]
textNoteTitle.setText(note.title)
textNoteText.setText(note.text)
val coursePosition = DataManager.courses.values.indexOf(note.course)
spinnerCourses.setSelection(coursePosition)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId) {
R.id.action_settings -> true
R.id.action_next ->{
moveNext()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun moveNext() {
++notePosition
displayNote()
invalidateOptionsMenu()
}
@SuppressLint("UseCompatLoadingForDrawables")
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
if(notePosition >= DataManager.notes.lastIndex){
val menuItem = menu?.findItem(R.id.action_next)
if(menuItem != null){
menuItem.icon = getDrawable(R.drawable.baseline_block_black_24)
menuItem.isEnabled = false
}
}
return super.onPrepareOptionsMenu(menu)
}
override fun onPause() {
super.onPause()
saveNote()
}
private fun saveNote() {
val note = DataManager.notes[notePosition]
note.title = textNoteTitle.text.toString()
note.text = textNoteText.text.toString()
note.course = spinnerCourses.selectedItem as CourseInfo
}
}