Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何使用reformation/Moshi解析嵌套的JSON对象_Android_Kotlin_Retrofit2_Moshi - Fatal编程技术网

Android 如何使用reformation/Moshi解析嵌套的JSON对象

Android 如何使用reformation/Moshi解析嵌套的JSON对象,android,kotlin,retrofit2,moshi,Android,Kotlin,Retrofit2,Moshi,我使用这个CodeLabs教程来学习如何从GoogleBooksAPI发出HTTP请求 现在,我正在尝试访问GoogleBooksAPI吐出的嵌套JSON对象 即 我只需要描述和缩略图属性 我的API服务接口是 package com.example.customapp.network import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import

我使用这个CodeLabs教程来学习如何从GoogleBooksAPI发出HTTP请求

现在,我正在尝试访问GoogleBooksAPI吐出的嵌套JSON对象 即

我只需要描述和缩略图属性

我的API服务接口是

package com.example.customapp.network
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET

//Code from https://codelabs.developers.google.com/codelabs/kotlin-android-training-internet-data/#3

private const val BASE_URL = "https://www.googleapis.com/books/v1/"

private val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

private val retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .baseUrl(BASE_URL)
    .build()

interface BookApiService {
    //Get annotation specifies the endpoint for this web service method.
    //when getProperties() method is invoked, Retrofit appends the endpoint 'book' to the base URL
    //And creates a Call object. The Call object is used to start the request.
    @GET("volumes?q='harry+potter")
    suspend fun getProperties(): BookProperty
}

object BookApi {
    val retrofitService: BookApiService by lazy {
        retrofit.create(BookApiService::class.java)
    }
}
}
我的BookProperty.kt是

data class BookProperty(@field:Json(name = "items" ) val bookDetail: List<BookDetail>)
data class BookDetail(@field:Json(name = "volumeInfo") val volumeInfo: VolumeInfo)
data class VolumeInfo(@field:Json(name = "description") val description: String, @field:Json(name= "imageLinks") val imageLink: ImageLink)
data class ImageLink(@field:Json(name = "thumbnail") val thumbnail: String)
数据类BookProperty(@field:Json(name=“items”)val bookDetail:List)
数据类BookDetail(@field:Json(name=“volumeInfo”)val volumeInfo:volumeInfo)
数据类VolumeInfo(@field:Json(name=“description”)val description:String,@field:Json(name=“imageLinks”)val-imageLink:imageLink)
数据类ImageLink(@field:Json(name=“thumbnail”)val thumbnail:String)
我正在从ViewModel调用API

val readAllData: LiveData<List<BookItem>>
    private val repository: BookRepository
    private val _response = MutableLiveData<String>()

    val response: LiveData<String>
        get() = _response

    init {
        val bookDao = BookDatabase.getDatabase(application).bookDao()
        repository = BookRepository(bookDao)
        readAllData = repository.readAllData
    }

    fun addBook(book: BookItem) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.addBook(book)
        }
    }

    fun updateBook(book: BookItem) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.updateBook(book)
        }
    }

    fun getBookDetailProperties() {
        viewModelScope.launch {
            try {
                //calling get properties from the BookApi service creates and starts the network call
                //on a background thread
                var listResult = BookApi.retrofitService.getProperties()
                _response.value = "${
                    listResult.bookDetail[0].volumeInfo.description} book properties received"
            } catch (e: Exception) {
                _response.value = "Failure: ${e.message}"
            }
        }
    }
val readAllData:LiveData
私有val存储库:BookRepository
private val_response=MutableLiveData()
val响应:LiveData
get()=\u响应
初始化{
val bookDao=BookDatabase.getDatabase(应用程序).bookDao()
repository=BookRepository(bookDao)
readAllData=repository.readAllData
}
趣味addBook(书籍:BookItem){
viewModelScope.launch(Dispatchers.IO){
repository.addBook(book)
}
}
趣味更新电子书(书籍:BookItem){
viewModelScope.launch(Dispatchers.IO){
repository.updateBook(书籍)
}
}
有趣的getBookDetailProperties(){
viewModelScope.launch{
试一试{
//从BookApi服务调用get属性将创建并启动网络调用
//在背景线程上
var listResult=BookApi.reformationservice.getProperties()
_response.value=”${
listResult.bookDetail[0].volumeInfo.description}已收到书本属性“
}捕获(e:例外){
_response.value=“失败:${e.message}”
}
}
}
每次我在CRUD应用程序上更新一个项目时,即当我点击一个按钮时,我都试图发出一个HTTP请求,但我似乎无法得到任何回复。这是我发起API调用的UpdateFragment


class UpdateFragment : Fragment() {
    //Read up on delegation
    //https://codelabs.developers.google.com/codelabs/kotlin-bootcamp-classes/#7

    //UpdateFragmentArgs is a class that is automatically generated
    //when we created an argument for our Update Fragment in the nav graph
    //UpdateFragmentArgs will contain our current book
    //we can also use bundle
    private val args by navArgs<UpdateFragmentArgs>()

    private lateinit var mBookViewModel: BookViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_update, container, false)

        //So the keyboard doesn't push the EditText fields up
        this.activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)

        Glide
            .with(this)
            .load(args.currentBook.image)
            .into(view.bookImageDetail)

        mBookViewModel = ViewModelProvider(this).get(BookViewModel::class.java)


        view.apply {
            updateInputName.setText(args.currentBook.title)
            updateInputAuthor.setText(args.currentBook.author)
            updateBookDesc.text = args.currentBook.desc
            updateRatingBar.rating = args.currentBook.rating.toFloat()
            updateBookCompleted.isChecked = args.currentBook.finished
            updateBookCompleted.text =
                if (updateBookCompleted.isChecked) getString(R.string.book_completed) else getString(
                    R.string.book_not_completed
                )
            updateDateCreated.text = getString(R.string.date_created, args.currentBook.dateCreated)
        }

        view.updateBtn.setOnClickListener {
            updateItem()
        }

        view.updateBookCompleted.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked) {
                view.updateBookCompleted.text = getString(R.string.book_completed)
            } else {
                view.updateBookCompleted.text = getString(R.string.book_not_completed)
            }
        }

        return view
    }

    private fun updateItem() {
        val bookName = updateInputName.text.toString()
        val bookAuthor = updateInputAuthor.text.toString()
        val bookRating = updateRatingBar.rating.toDouble()
        val bookFinished = updateBookCompleted.isChecked

        if (inputCheck(bookName, bookAuthor)) {
            
            //***Initiate API call here ****
            mBookViewModel.getBookDetailProperties()

            //Get description and image from API
            mBookViewModel.response.observe(viewLifecycleOwner, {
                println("Get resp " + it)
            })

            //Create book object
            val updatedBook = BookItem(
                args.currentBook.id,
                bookName,
                bookAuthor,
                args.currentBook.desc,
                args.currentBook.image,
                bookRating,
                args.currentBook.dateCreated,
                bookFinished
            )

            //update current book
            mBookViewModel.updateBook(updatedBook)

            Toast.makeText(requireContext(), "Updated book successfully!", Toast.LENGTH_SHORT)
                .show()

            //navigate back
            findNavController().navigate(R.id.action_updateFragment_to_listFragment)
        }
    }

    private fun inputCheck(bookName: String, authorName: String): Boolean {
        return !(TextUtils.isEmpty(bookName) && TextUtils.isEmpty(authorName))
    }

}

类UpdateFragment:Fragment(){
//阅读授权书
//https://codelabs.developers.google.com/codelabs/kotlin-bootcamp-classes/#7
//UpdateFragmentArgs是一个自动生成的类
//当我们在导航图中为更新片段创建参数时
//UpdateFragmentArgs将包含我们当前的书籍
//我们也可以使用bundle
私有val args by navArgs()
私有lateinit变量mBookViewModel:BookViewModel
覆盖创建视图(
充气器:布局充气器,容器:视图组?,
savedInstanceState:捆绑?
):查看{
//为该碎片膨胀布局
val视图=充气机。充气(R.layout.fragment\u更新,容器,错误)
//因此键盘不会向上推EditText字段
此.activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT\u INPUT\u ADJUST\u PAN)
滑翔
.与(此)
.load(args.currentBook.image)
.into(view.bookImageDetail)
mBookViewModel=ViewModelProvider(this).get(BookViewModel::class.java)
view.apply{
updateInputName.setText(args.currentBook.title)
updateInputAuthor.setText(args.currentBook.author)
updateBookDesc.text=args.currentBook.desc
updateRatingBar.rating=args.currentBook.rating.toFloat()
updateBookCompleted.isChecked=args.currentBook.finished
updateBookCompleted.text=
if(updateBookCompleted.isChecked)getString(R.string.book_completed)else getString(
R.string.book\u未完成
)
updateDateCreated.text=getString(R.string.date_created,args.currentBook.dateCreated)
}
view.updateBtn.setOnClickListener{
updateItem()
}
view.updateBookCompleted.setOnCheckedChangeListener{},isChecked->
如果(已检查){
view.updateBookCompleted.text=getString(R.string.book\u已完成)
}否则{
view.updateBookCompleted.text=getString(R.string.book\u未完成)
}
}
返回视图
}
私人娱乐更新项目(){
val bookName=updateInputName.text.toString()
val bookAuthor=updateInputAuthor.text.toString()
val bookRating=updateRatingBar.rating.toDouble()
val bookFinished=updateBookCompleted.isChecked
if(输入检查(书名、书籍作者)){
//***在此处启动API调用****
mBookViewModel.getBookDetailProperties()
//从API获取描述和图像
mBookViewModel.response.observe(viewLifecycleOwner{
println(“获取响应”+它)
})
//创建图书对象
val updatedBook=BookItem(
args.currentBook.id,
书名,
作者:,
args.currentBook.desc,
args.currentBook.image,
簿记评级,
args.currentBook.dateCreated,
书页
)
//更新当前书籍
mBookViewModel.updateBook(updatedBook)
Toast.makeText(requireContext(),“已成功更新书籍!”,Toast.LENGTH\u SHORT)
.show()
//向后导航
findNavController().导航(R.id.action\u updateFragment\u到\u listFragment)
}
}
private fun inputCheck(书名:String,authorName:String):布尔值{
return!(TextUtils.isEmpty(书名)&&TextUtils.isEmpty(authorName))
}
}
问题是我无法从API调用中获得任何响应-我不确定这是否是因为JSON中的嵌套对象。请帮帮我

class UpdateFragment : Fragment() {
    //Read up on delegation
    //https://codelabs.developers.google.com/codelabs/kotlin-bootcamp-classes/#7

    //UpdateFragmentArgs is a class that is automatically generated
    //when we created an argument for our Update Fragment in the nav graph
    //UpdateFragmentArgs will contain our current book
    //we can also use bundle
    private val args by navArgs<UpdateFragmentArgs>()

    private lateinit var mBookViewModel: BookViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_update, container, false)

        //So the keyboard doesn't push the EditText fields up
        this.activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)

        Glide
            .with(this)
            .load(args.currentBook.image)
            .into(view.bookImageDetail)

        mBookViewModel = ViewModelProvider(this).get(BookViewModel::class.java)


        view.apply {
            updateInputName.setText(args.currentBook.title)
            updateInputAuthor.setText(args.currentBook.author)
            updateBookDesc.text = args.currentBook.desc
            updateRatingBar.rating = args.currentBook.rating.toFloat()
            updateBookCompleted.isChecked = args.currentBook.finished
            updateBookCompleted.text =
                if (updateBookCompleted.isChecked) getString(R.string.book_completed) else getString(
                    R.string.book_not_completed
                )
            updateDateCreated.text = getString(R.string.date_created, args.currentBook.dateCreated)
        }

        view.updateBtn.setOnClickListener {
            updateItem()
        }

        view.updateBookCompleted.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked) {
                view.updateBookCompleted.text = getString(R.string.book_completed)
            } else {
                view.updateBookCompleted.text = getString(R.string.book_not_completed)
            }
        }

        return view
    }

    private fun updateItem() {
        val bookName = updateInputName.text.toString()
        val bookAuthor = updateInputAuthor.text.toString()
        val bookRating = updateRatingBar.rating.toDouble()
        val bookFinished = updateBookCompleted.isChecked

        if (inputCheck(bookName, bookAuthor)) {
            
            //***Initiate API call here ****
            mBookViewModel.getBookDetailProperties()

            //Get description and image from API
            mBookViewModel.response.observe(viewLifecycleOwner, {
                println("Get resp " + it)
            })

            //Create book object
            val updatedBook = BookItem(
                args.currentBook.id,
                bookName,
                bookAuthor,
                args.currentBook.desc,
                args.currentBook.image,
                bookRating,
                args.currentBook.dateCreated,
                bookFinished
            )

            //update current book
            mBookViewModel.updateBook(updatedBook)

            Toast.makeText(requireContext(), "Updated book successfully!", Toast.LENGTH_SHORT)
                .show()

            //navigate back
            findNavController().navigate(R.id.action_updateFragment_to_listFragment)
        }
    }

    private fun inputCheck(bookName: String, authorName: String): Boolean {
        return !(TextUtils.isEmpty(bookName) && TextUtils.isEmpty(authorName))
    }

}
            //Get description and image from API
            mBookViewModel.response.observe(viewLifecycleOwner, {
                println("Get resp " + it)
            })

            //Create book object
            val updatedBook = BookItem(
                args.currentBook.id,
                bookName,
                bookAuthor,
                args.currentBook.desc,
                args.currentBook.image,
                bookRating,
                args.currentBook.dateCreated,
                bookFinished
            )

            //update current book
            mBookViewModel.updateBook(updatedBook)

            Toast.makeText(requireContext(), "Updated book successfully!", Toast.LENGTH_SHORT)
                .show()

            //navigate back
            findNavController().navigate(R.id.action_updateFragment_to_listFragment)
            //Get description and image from API
            mBookViewModel.response.observe(viewLifecycleOwner, {
                println("Get resp " + it)
          

            //Create book object
            val updatedBook = BookItem(
                args.currentBook.id,
                bookName,
                bookAuthor,
                args.currentBook.desc,
                args.currentBook.image,
                bookRating,
                args.currentBook.dateCreated,
                bookFinished
            )

            //update current book
            mBookViewModel.updateBook(updatedBook)

            Toast.makeText(requireContext(), "Updated book successfully!", Toast.LENGTH_SHORT)
                .show()

            //navigate back
            findNavController().navigate(R.id.action_updateFragment_to_listFragment)
 })