我是一名初学者,正在尝试使用tmdb API和Kotlin构建电影数据库应用。到目前为止,我一直在按照教程来获取基本想法,但由于我的应用程序不同,我需要自己实现逻辑。
在我的适配器onBindViewHolder()
方法中,我将base_URL字符串与我的poster_path连接并将其传递给Picasso,以使用来自JSON数据的图像填充我的RecyclerView。就是这样:
override fun onBindViewHolder(holder: PosterHolder, position: Int) {
Picasso
.get()
.load("" + R.string.base_URL + "" + movieData.moviePoster)
.into(holder.imageView)
holder.view.movie_poster?.scaleType = ImageView.ScaleType.FIT_CENTER
}
如您所见,海报路径是从数据类(movieData.moviePoster
)调用的。我能够这样做,因为这是我的适配器的构造函数:
class PosterAdapter(val movieData: Movies) : RecyclerView.Adapter<PosterHolder>(){...}
但现在在我的MainActivity onCreate()
方法中,将适配器附加到RecyclerView的调用需要相同的构造函数。
class MainActivity() : AppCompatActivity(), LoaderManager.LoaderCallbacks<List<Movies>> {
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view);
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.layoutManager = GridLayoutManager(this, 3);
recyclerView.adapter = PosterAdapter() <- this is it
runLoaders()
}
...
}
我尝试在MainActivity的构造函数中调用相同的Movies
对象,但它抛出了一个错误,因为它期望MainActivity的一个空构造函数。
如何创建一个对象以传递到MainActivity中的适配器参数?我尝试在全局创建一个,但它强迫我将其初始化为null
。
Movies.kt(根据要求)
data class Movies(val movieTitle: String,
val moviePoster: String,
val overview: String,
val ratings: Int,
val releaseDate: String)
PosterAdapter.kt
class PosterAdapter(val movieData: Movies) : RecyclerView.Adapter<PosterHolder>(){
val movieList = mutableListOf<Movies>()
override fun getItemCount(): Int { return movieList.size }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PosterHolder{
val layoutInflater = LayoutInflater.from(parent?.context)
val listItem = layoutInflater.inflate(R.layout.list_item, parent, false)
return PosterHolder(listItem)
}
override fun onBindViewHolder(holder: PosterHolder, position: Int) {
Picasso
.get()
.load("" + R.string.base_URL + "" + movieData.moviePoster)
.into(holder.imageView)
holder.view.movie_poster?.scaleType = ImageView.ScaleType.FIT_CENTER
}
}
class PosterHolder(val view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
var imageView: ImageView? = null
fun PosterHolder(view: View){ this.imageView = view.findViewById<View>(R.id.movie_poster) as ImageView }
override fun onClick(p0: View?) {}
}
QueryUtils.kt
object QueryUtils {
private val logTag = QueryUtils::class.java.simpleName
fun fetchMovieData(requestURL: String): List<Movies>? {
val url = createURL(requestURL)
var jsonResponse : String? = null
try{
jsonResponse = getResponseFromHttpURL(url)
}catch (e: IOException){
Log.e(logTag, "Problem making the HTTP request", e)
}
return extractFeatureFromJSON(jsonResponse)
}
private fun createURL(requestURL: String): URL? {
var url : URL? = null
try{
url = URL(requestURL)
}catch (e: MalformedURLException){
Log.e(logTag, "Problem building the URL", e)
}
return url
}
@Throws(IOException::class)
private fun getResponseFromHttpURL(url: URL?): String? {
//first, open the connection using the url object that was created in createURL method.
//the "as" keyword casts "urlConnection" as HttpURLConnection.
val urlConnection = url?.openConnection() as HttpURLConnection?
try {
if(urlConnection?.responseCode == HttpURLConnection.HTTP_OK){
//The if statement runs if the connection is successful.
//We're retrieving all the data from the input stream after the connection.
val inputStream = urlConnection.inputStream
val scanner = Scanner(inputStream)
scanner.useDelimiter("\\A")
if(scanner.hasNext()){
return scanner.next()
}
}else{
//Throw a log message in case of a faulty response code.
Log.e(logTag, "Error response code: " + urlConnection?.responseCode)
}
}finally {
//end the connection to reclaim the resources to prevent memory leaks
urlConnection?.disconnect()
}
return null
}
private fun extractFeatureFromJSON(jsonResponse: String?): List<Movies>? {
if(jsonResponse == null || jsonResponse.isEmpty()){
return null
}
val movies = mutableListOf<Movies>()
try{
val baseJSONresponse = JSONObject(jsonResponse)
val titleJSON = baseJSONresponse.getString("original_title")
val posterJSON = baseJSONresponse.getString("poster_path")
val overviewJSON = baseJSONresponse.getString("overview")
val ratingsJSON = baseJSONresponse.getInt("vote_average")
val releaseDateJSON = baseJSONresponse.getString("release_date")
movies.add(Movies(titleJSON, posterJSON, overviewJSON, ratingsJSON, releaseDateJSON))
}catch (e: JSONException){
Log.e(logTag, "Problem parsing JSON results", e)
}
return movies
}
}
答案 0 :(得分:1)
我尝试在我的构造函数中调用相同的Movies对象 MainActivity但它因为期待空而引发错误 MainActivity的构造函数。
活动与您想要做的事情无关。你声明你的适配器是这样的:
class PosterAdapter(val movieData: Movies) : RecyclerView.Adapter<PosterHolder>(){
这意味着当您创建实例时,它需要您在构造函数中传递Movies对象。可以从Web(在您的情况下是电影API),某些磁盘文件,数据库中获取此Movies对象,或者您甚至可以手动创建它:
val dummyMovie = Movies("Dummy title", "Dummy movie poster", "Overview", 5, "Release date")
recyclerView.adapter = PosterAdapter(dummyMovie)
如何创建列表对象以传递到Kotlin中的Adapter参数
更改适配器以使用电影列表:
// the adapter will need a Context so we are going to pass one when we create the adapter
class PosterAdapter(private val context: Context) : RecyclerView.Adapter<PosterHolder>() {
private val inflater: LayoutInflater by lazy { LayoutInflater.from(context) }
private var movies = listOf<Movies>()// there's no need to expose this list
override fun getItemCount(): Int = movies.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PosterHolder = PosterHolder(inflater.inflate(R.layout.list_item, parent, false))
override fun onBindViewHolder(holder: PosterHolder, position: Int) {
//make sure this results in a proper string
Picasso.get()
.load("${context.getString(R.string.base_URL)}${movies[position].moviePoster}")
.into(holder.imageView)
holder.imageView.scaleType = ImageView.ScaleType.FIT_CENTER
}
// because fetching data from an API takes time, we will use this method to update the adapter with data when we actually get it
fun update(movies: List<Movies>) {
this.movies = movies
notifyDataSetChanged()
}
}
class PosterHolder(view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
val imageView: ImageView = view.findViewById(R.id.movie_poster)
override fun onClick(p0: View?) {}
}
然后在您的MainActivity.onCreate()中,您将拥有:
recyclerView.adapter = PosterAdapter(this)
// fetch data from API and call update() on the adapter
要获取数据,我建议您使用Retrofit,有很多关于如何使用该库的指南。