Как предоставить данные для RecyclerView.Adapter, требующего список фильмов? - PullRequest
0 голосов
/ 13 мая 2018

Я начинающий разработчик, пытающийся создать приложение базы данных фильмов, используя API tmdb и Kotlin. До сих пор я следовал руководству, чтобы понять основную идею, но поскольку мое приложение отличается от других, мне нужно самому реализовать логику.

В методе onBindViewHolder() моего адаптера я объединяю строку base_URL с моим poster_path и передаю ее в Picasso для заполнения моего RecyclerView изображениями из данных JSON. Вот оно:

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>(){...}

но теперь в методе onCreate() моей MainActivity для вызова адаптера к 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()
    }
...
}

Я попытался вызвать тот же самый объект Movies в конструкторе моей MainActivity, но он выдал ошибку, поскольку ожидал пустой конструктор для 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
    }
}

1 Ответ

0 голосов
/ 14 мая 2018

Я пытался вызвать тот же объект Movies в конструкторе моей MainActivity, но он выдал ошибку, так как ожидал пустой конструктор для MainActivity.

Деятельность не имеет ничего общегос тем, что вы хотите сделать.Вы объявили свой адаптер следующим образом:

class PosterAdapter(val movieData: Movies) : RecyclerView.Adapter<PosterHolder>(){

, что означает, что при создании экземпляра требуется передать объект Movies в конструктор.Этот объект Movies может быть извлечен из Интернета (в вашем случае API фильма), некоторого файла на диске, базы данных или даже вы можете создать его вручную:

val dummyMovie = Movies("Dummy title", "Dummy movie poster", "Overview", 5, "Release date")
recyclerView.adapter = PosterAdapter(dummyMovie)

Как создать объект списка дляпередать параметр адаптера в Kotlin

Измените свой адаптер, чтобы использовать список фильмов:

// 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 , есть много руководств по использованию библиотеки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...