0

Я создаю приложение для Android, которое использует API (базу данных фильмов) и извлекает массив JSON. После извлечения соответствующий JSONObject отправляется в модель. Эта модель представляет собой класс, состоящий из сеттеров и геттеров для извлечения объекта и назначения его переменным, которые я могу использовать. Все это делается на AsyncTask. Тем не менее, мне трудно понять метод doInBackground, поскольку он ожидает, что я что-то верну. Я проделал всю работу над методом getMovieJson, и я знаю, что должен вернуть что-то из doInBackground, потому что требуется обновить собственный пользовательский адаптер по методу onPostExecute. Этот пользовательский адаптер представляет собой ArrayAdapter, который создает соответствующие представления для заполнения в моем gridView.Как реализовать пользовательский ArrayList в AsyncTask?

Это моя модель

package com.xxcanizeusxx.erick.moviesnow; 

/** 
* This class acts as the model base for our 
* array of JSON Objects that need to be populated.\ 
* This class uses getters and setters to achieve its task. 
*/ 

public class Movie { 

    private String title; 
    private String vote_average; 
    private String overview; 
    private String release_date; 
    private String poster_path; 

    public String getTitle(){ 
     return title; 
    } 

    public void setTitle(String title){ 
     this.title = title; 
    } 

    public String getOverview(){ 
     return overview; 
    } 

    public void setOverview(String overview){ 
     this.overview = overview; 
    } 

    public String getRelease_date(){ 
     return release_date; 
    } 

    public void setRelease_date(String release_date){ 
     this.release_date = release_date; 
    } 

    public String getVote_average(){ 
     return vote_average; 
    } 

    public void setVote_average(String vote_average){ 
     this.vote_average = vote_average; 
    } 


    public String getPoster_path(){ 
     return poster_path; 
    } 

    public void setPoster_path(String poster_path){ 
     this.poster_path = poster_path; 
    } 


} 

Это мой фрагмент

package com.xxcanizeusxx.erick.moviesnow; 

import android.net.Uri; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.Menu; 
import android.view.MenuInflater; 
import android.view.MenuItem; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.GridView; 

import org.json.JSONArray; 
import org.json.JSONException; 
import org.json.JSONObject; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.ArrayList; 

/** 
* Created by Erick on 1/4/2017. 
*/ 

public class MovieFragment extends Fragment { 
    //Initialize our array adapter and components. 
    private ArrayList<Movie> mMovieData; 
    private MovieAdapter mMovieAdapter; 

    //Empty constructor 
    public MovieFragment() { 

    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     //Add this line in order for this fragment to handle menu events. 
     setHasOptionsMenu(true); 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     inflater.inflate(R.menu.movie_fragment, menu); 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     int id = item.getItemId(); 
     if (id == R.id.popular_movies) { 
      updateMovie(); 

      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 

    private void updateMovie() { 
     FetchMovieTask fetchMovie = new FetchMovieTask(); 
     fetchMovie.execute(); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     //Initialize our array adapter 
     mMovieData = new ArrayList<>(); 
     mMovieAdapter = new MovieAdapter(getActivity(), R.layout.grid_movie_item, mMovieData); 

     View rootView = inflater.inflate(R.layout.gird_layout, container, false); 

     //Get a reference to the gridView and attach the adapter to it 
     GridView mGridView = (GridView) rootView.findViewById(R.id.gridView); 
     mGridView.setAdapter(mMovieAdapter); 
     return rootView; 
    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     updateMovie(); 
    } 

    public class FetchMovieTask extends AsyncTask<String[], Void, String[]> { 
     private final String LOG = FetchMovieTask.class.getSimpleName(); 



     private String[] getMovieJson(String movieJsonStr) throws JSONException { 
      final String OWM_RESULTS = "results"; 
      String title; 
      String posterPath; 




      JSONObject movieJson = new JSONObject(movieJsonStr); 
      JSONArray movieJsonArray = movieJson.getJSONArray(OWM_RESULTS); 
      Movie movieItem = new Movie(); 
      //Newly created array that will house the data in order to check for views on the onPostExecute method 
      String[] results = new String[movieJsonStr.length()]; 
      for (int i = 0; i < movieJsonArray.length(); i++) { 
       JSONObject movieObject = movieJsonArray.getJSONObject(i); 
       title = movieObject.getString("title"); 
       posterPath = movieObject.getString("poster_path"); 
       movieItem.setTitle(title); 
       movieItem.setPoster_path(posterPath); 
       results[i] = movieObject.getString(posterPath) +" " + movieObject.getString(posterPath); 


      } 

      mMovieData.add(movieItem); 
      return results; 


     } 


     @Override 
     protected String[] doInBackground(String[]... params) { 
      //Establish a connection 
      HttpURLConnection urlConnection = null; 
      BufferedReader bufferedReader = null; 

      //Will contain the raw JSON as a string 
      String movieJsonStr = null; 
      //String as placeholders 
      String descriptionHolder = "popularity.desc"; 

      try { 
       //String to hold the Base url 
       final String TMDB_BASE_URL = "http://api.themoviedb.org/3/discover/movie?"; 
       final String APPID = "api_key"; 
       final String DESC = "sort_by"; 

       //Build the url 
       Uri buildMovieUri = Uri.parse(TMDB_BASE_URL).buildUpon() 
         .appendQueryParameter(DESC, descriptionHolder) 
         .appendQueryParameter(APPID, BuildConfig.TMDP_API_KEY) 
         .build(); 

       URL url = new URL(buildMovieUri.toString()); 
       //Create the request to TMDB and open connection 
       urlConnection = (HttpURLConnection) url.openConnection(); 
       urlConnection.setRequestMethod("GET"); 
       urlConnection.connect(); 

       //Read the input stream into a string 
       InputStream inputStream = urlConnection.getInputStream(); 
       StringBuffer buffer = new StringBuffer(); 
       if (inputStream == null) { 
        //Nothing to do 
        return null; 
       } 
       bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); 
       String line; 
       while ((line = bufferedReader.readLine()) != null) { 
        //Make debugging easier by adding a new line to the bufffer stream 
        buffer.append(line + "\n"); 
        int result = 1; 
       } 

       if (buffer.length() == 0) { 
        //stream was empty. No point in parsing. 
        return null; 
       } 
       movieJsonStr = buffer.toString(); 

      } catch (IOException e) { 
       Log.e(LOG, "Error ", e); 
       //If code didnt get the movie data, no point in parsing 
       return null; 
      } finally { 
       if (urlConnection != null) { 
        urlConnection.disconnect(); 
       } 
       if (bufferedReader != null) { 

        try { 
         bufferedReader.close(); 
        } catch (final IOException e) { 
         Log.e(LOG, "Error closing stream ", e); 
        } 
       } 
      } 
      try { 
       return getMovieJson(movieJsonStr); 
      } catch (JSONException e) { 
       Log.e(LOG, e.getMessage(), e); 
       e.printStackTrace(); 
      } 
       return null; 
     } 


     @Override 
     protected void onPostExecute(String[] result){ 
      if (result != null){ 
       mMovieAdapter.clear(); 
       for (String results : result ){ 
        mMovieAdapter.setMovieData(results); 
       } 
      } 
     } 



    } 

} 

Это мой адаптер

package com.xxcanizeusxx.erick.moviesnow; 

import android.app.Activity; 
import android.content.Context; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.ArrayAdapter; 
import android.widget.ImageView; 
import android.widget.TextView; 

import com.squareup.picasso.Picasso; 

import java.util.ArrayList; 

/** 
* This class is the MovieAdapter that will take data from the model and 
* display it on the View. Additionally, this adapter will load the picasso base_img_url 
* to populate the griView according to Udacity. 
*/ 

public class MovieAdapter extends ArrayAdapter<Movie> { 
    private final String BASE_IMAGE_URL = "http://image.tmdb.org/t/p/w185"; 
    private Context mContext; 
    private int resource; 
    private ArrayList<Movie> mMovieData = new ArrayList<Movie>(); 

    //Constructor matching super 
    public MovieAdapter(Context mContext, int resource, ArrayList<Movie> mMovieData) { 
     super(mContext, resource, mMovieData); 
     this.mContext = mContext; 
     this.resource = resource; 
     this.mMovieData = mMovieData; 

    } 

    //This method sets the movieData and refreshes the gridLayout items. 
    public void setMovieData(ArrayList<Movie> mMovieData){ 
     this.mMovieData = mMovieData; 
     //Notifies if data state has changed 
     notifyDataSetChanged(); 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent){ 
     //Declare the variables to hold the convertView and viewHolder static class 
     View cv = convertView; 
     ViewHolder viewHolder; 

     //If the convertView is null, we don't have a view so, create one. 
     if(cv == null){ 
      //Create the View 
      cv = LayoutInflater.from(getContext()).inflate(resource, parent, false); 
      //Call the static viewHolder class 
      viewHolder = new ViewHolder(); 
      //Initialize the textView and imageView to load inside the view 
      viewHolder.movieTextView = (TextView) cv.findViewById(R.id.movie_title); 
      viewHolder.moviePoster = (ImageView) cv.findViewById(R.id.movie_poster); 
      cv.setTag(viewHolder); 
     }else{ 
      viewHolder = (ViewHolder) cv.getTag(); 
     } 

     Movie movieItem = mMovieData.get(position); 
     //Set the textView holder 
     viewHolder.movieTextView.setText(movieItem.getTitle()); 
     //use picasso to load images to the holder 
     Picasso.with(mContext).load(BASE_IMAGE_URL + movieItem.getPoster_path()).fit().into(viewHolder.moviePoster); 
     return cv; 

    } 

    static class ViewHolder{ 
     TextView movieTextView; 
     ImageView moviePoster; 

    } 
} 

Это мой Основная деятельность

package com.xxcanizeusxx.erick.moviesnow; 

import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.Menu; 
import android.view.MenuItem; 

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     if(savedInstanceState == null){ 
      getSupportFragmentManager().beginTransaction() 
        .add(R.id.container, new MovieFragment()) 
        .commit(); 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu){ 
     //Inflate the menu, this adds items to actionbar if present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item){ 
     int id = item.getItemId(); 
     if (id == R.id.action_settings){ 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 
} 

Моего girdLayout XML

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
      android:id="@+id/grid_layout" 
       android:orientation="vertical" 
       android:layout_width="match_parent" 
       android:layout_height="match_parent"> 
    <GridView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:id="@+id/gridView" 
     android:numColumns="2" 
     android:gravity="center" 
     android:drawSelectorOnTop="true" 
     android:verticalSpacing="5dp" 
     android:horizontalSpacing="5dp"> 
    </GridView> 

</FrameLayout> 

Мой movieItem XML (Для того, чтобы заполнить GridLayout)

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:id="@+id/movie_detail_item" 
       android:orientation="vertical" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content"> 
    <ImageView 
     android:id="@+id/movie_poster" 
     android:layout_width="100dp" 
     android:layout_height="100dp" 
     android:scaleType="fitXY"/> 

    <TextView 
     android:id="@+id/movie_title" 
     android:maxLines="2" 
     android:gravity="center" 
     android:textSize="14sp" 
     android:textAllCaps="true" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"/> 

</LinearLayout> 

ответ

2

Изменения параметров Вашего AsyncTask первого

public class FetchMovieTask extends AsyncTask<Void, String[], String[]> {} 

Затем измените тип возвращаемого из вашей doInBackground() для получения результатов

@Override 
protected String[] doInBackground(Void... params) {} 

Поймите поток параметров и типов возврата.

enter image description here

UPDATE:

@Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
rootView = inflater.inflate(R.layout.gird_layout, container, false); 

     //Initialize our array adapter 
     mMovieData = new ArrayList<>(); 
     updateView(mMovieData); 
     return rootView; 
    } 


void updateView(ArrayList<>() movieData){ 
mMovieAdapter = new MovieAdapter(getActivity(), R.layout.grid_movie_item, movieData); 

     //Get a reference to the gridView and attach the adapter to it 
     GridView mGridView = (GridView) rootView.findViewById(R.id.gridView); 
     mGridView.setAdapter(mMovieAdapter); 
} 

Возвращение ArrayList из вашего GetMovie & DoInBackground

@Override 
protected ArrayList<Movies> doInBackground(Object... params) {} 

и

private ArrayList<Movies> getMovieJson(String movieJsonStr) throws JSONException { 
.... 
mMovieData.add(movieItem); 
return mMovieData; 
} 

называют это updateView обновить довольно setAdapater(..) и postExecute параметров

@Override 
     protected void onPostExecute(ArrayList<Movies> movieData){ 
      updateView(movieData); 
     } 
+0

Хорошее объяснение с использованием стрелок – avinash

+0

Благодарим за сообщение, эта тема по-прежнему запутанна, но вы устранили некоторые из моих сомнений в будущем. Я очень ценю ответы. –

+0

Какую часть вы путаете? Я установил возвращаемый тип ваших методов. Хотя вы можете изменить другие части, чтобы получить фактический результат вашего желаемого типа. –

0

Перво компилирует ваш код? Из того, что я могу видеть ваше AsyncTask имеет следующую подпись -

public class FetchMovieTask extends AsyncTask<String[], Void, Void> { 

Но Вы возвращаетесь String [] из doInBackground, который идеально даст вам ошибку. В любом случае вам не нужно ничего возвращать из AsyncTask в вашем случае.Просто добавьте этот звонок на onPostExecute - mMovieAdapter.setMovieData(Arrays.asList(result))

Btw, результат типа должен быть строкой [], а не строкой, как я вижу.

+0

Thankyou! вот почему я сбился с толку. У меня уже есть метод, называемый get getMovieJson, который добавляет элементы к модели, которую позаботится адаптер. DoInBackground возвращает строку Json raw, которая затем отправляется в getMovieJson. Он запустился и раздул один элемент gridView, прежде чем он разбился. Я не знаю, как реализовать этот адаптер в onPostExecute, я отредактирую свой код, пожалуйста, см. Выше спасибо !. –

+0

Так как мой doInbackground возвращает только исходную строку JSON, тогда параметры все равно будут ? потому что JSON - это массив строк. –

+0

Затем вы должны изменить подпись на - '' – Dibzmania