我正在构建一个采用API(电影数据库)的Android应用程序,并提取JSON数组。提取后,将相应的JSONObject发送到模型。此模型是由setter和getter组成的类,用于提取对象并将其分配给我可以使用的变量。所有这些都是在AsyncTask上完成的。但是,我很难理解doInBackground方法,因为它希望我返回一些东西。我已经完成了getMovieJson方法的所有工作,我知道我必须从doInBackground返回一些内容,因为需要在onPostExecute方法上更新我的自定义适配器。此自定义适配器是一个ArrayAdapter,它创建适当的视图以在gridView中填充。
这是我的模特
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>
答案 0 :(得分:2)
首先更改Asynctask的参数
public class FetchMovieTask extends AsyncTask<Void, String[], String[]> {}
然后更改doInBackground()
的返回类型以获得结果
@Override
protected String[] doInBackground(Void... params) {}
了解参数和返回类型的流程。
更新:
@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);
}
从GetMovie&amp;中返回ArrayList。 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);
}
答案 1 :(得分:0)
首先是你编写代码吗?从我可以看到你的AsyncTask有以下签名 -
public class FetchMovieTask extends AsyncTask<String[], Void, Void> {
但是你从doInBackground
返回String [],理想情况下会给你一个错误。
无论如何,你不必在你的情况下从AsyncTask返回任何东西。只需在onPostExecute
- mMovieAdapter.setMovieData(Arrays.asList(result))
顺便说一下,我可以看到类型结果应该是String []而不是String。