GridView适配器不填充?没有按时填充?没有在onPostExecute()中更新?
问题描述:
我正在构建一个由一个GridView与从一个API提取的图像组成的用户界面,我使用的ImageListAdapter和一个MovieFragment,当我启动应用程序,我只是得到一个空的屏幕。 我试过用preownownloaded的图像列表,它的工作原理。 从API获取数据在AsyncTask上,我认为问题在于时机,gridview.setAdapter()过早调用这一事实。 这是代码:GridView适配器不填充?没有按时填充?没有在onPostExecute()中更新?
public class MainActivity extends AppCompatActivity {
private final String LOG_TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager()
.beginTransaction()
.add(R.id.container, new MovieFragment())
.commit();
}
}}
公共类MovieFragment延伸片段{
private final String LOG_TAG = MovieFragment.class.getSimpleName();
public ImageListAdapter imageAdapter;
String urlPopular = "https://api.themoviedb.org/3/movie/popular?api_key=";
String urlRatings = "https://api.themoviedb.org/3/movie/top_rated?api_key=";
public MovieFragment() {
};
@Override
public void onStart() {
super.onStart();
FetchMovieData movieTask = new FetchMovieData();
movieTask.execute(urlPopular);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.movie_fragment_main, container, false);
GridView gridview = (GridView) rootView.findViewById(R.id.grid_view);
Log.d(LOG_TAG, imageAdapter.getCount() +"");
gridview.setAdapter(imageAdapter);
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
Toast.makeText(getActivity(), "" + position,
Toast.LENGTH_SHORT).show();
}
});
return rootView;
}
public class ImageListAdapter extends ArrayAdapter {
private Context context;
private LayoutInflater inflater;
private String[] imageUrls;
public ImageListAdapter(Context context, String[] imageUrls) {
super(context, R.layout.image_item, imageUrls);
this.context = context;
this.imageUrls = imageUrls;
inflater = LayoutInflater.from(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d(LOG_TAG, imageUrls[position]);
if (null == convertView) {
convertView = inflater.inflate(R.layout.image_item, parent, false);
}
Picasso
.with(context)
.load(imageUrls[position])
.fit() // will explain later
.into((ImageView) convertView);
return convertView;
}
}
public class FetchMovieData extends AsyncTask<String,Void,String[][]> {
private final String LOG_TAG = FetchMovieData.class.getSimpleName();
@Override
protected String[][] doInBackground(String... params) {
String url = params[0];
if (params.length == 0){
return null;
}
// Will contain the raw JSON response as a string.
String movieJSON = null;
try {
movieJSON = getMovieInfo(url);
} catch (final IOException e) {
Log.d(LOG_TAG, "Error closing stream", e);
}
try{
return getMovieDataFromJSON(movieJSON);
}
catch (JSONException e){
Log.d(LOG_TAG, e.getMessage(),e);
e.printStackTrace();
}
//Just in case...
return null;
}
private String getMovieInfo(String myurl) throws IOException{
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try{
URL url = new URL(myurl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
inputStream = urlConnection.getInputStream();
StringBuffer stringBuffer = new StringBuffer();
if (inputStream == null){
return null;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
stringBuffer.append(line + "\n");
}
if (stringBuffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
Log.d(LOG_TAG, stringBuffer.toString());
return stringBuffer.toString();
}
finally {
if(urlConnection != null){
urlConnection.disconnect();
}
}
}
private String[][] getMovieDataFromJSON(String jsonObj) throws JSONException{
JSONObject mainJSON = new JSONObject(jsonObj);
final String POSTERS = "poster_path";
final String ORIGINAL_TITLE = "original_title";
final String SYNOPSIS = "overview";
final String USER_RATING = "vote_average";
final String RELEASE_DATE = "release_date";
final String RESULTS = "results";
// Building a String[][] of movie info while:
// movie[][0] = Poster path
// movie[][1] = Original Title
// movie[][2] = Synopsis
// movie[][3] = User Rating
// movie[][4] = Release Date
JSONArray movieIndexArray = mainJSON.getJSONArray(RESULTS);
String[][] movie = new String[20][5];
for(int i = 0; i < movieIndexArray.length(); i++) {
JSONObject movieObject = movieIndexArray.getJSONObject(i);
movie[i][0] = movieObject.getString(POSTERS);
movie[i][1] = movieObject.getString(ORIGINAL_TITLE);
movie[i][2] = movieObject.getString(SYNOPSIS);
movie[i][3] = movieObject.getString(USER_RATING);
movie[i][4] = movieObject.getString(RELEASE_DATE);
}
return movie;
}
private String[] buildPosterArray(String[][] result){
String[] url = new String[20];
Uri.Builder builtUri = new Uri.Builder();
builtUri.scheme("http");
builtUri.authority("image.tmdb.org");
builtUri.appendPath("t");
builtUri.appendPath("p");
builtUri.appendPath("w185");
for (int i = 0 ; i < result.length ; i++){
builtUri.appendEncodedPath((result[i][0]));
builtUri.build();
url[i] = builtUri.toString();
}
return url;
}
protected void onPostExecute(String[][] result){
if(result != null){
String[] posterArray = buildPosterArray(result);
imageAdapter = new ImageListAdapter(getActivity(), posterArray);
Log.d(LOG_TAG, imageAdapter.getCount() +"");
}
}
}
}
答
我终于解决了它,我用BaseAdapter代替ArrayAdapter的延伸:
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private String[] moviePath;
public ImageAdapter(Context c, String[] path) {
mContext = c;
this.moviePath = path;
}
public int getCount() {
return moviePath.length;
}
//Needed due to methods being abstract
public Object getItem(int position) {return null;}
public long getItemId(int position) {return 0;}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = (ImageView) convertView;
if (imageView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(500, 500));
imageView.setPadding(5, 5, 5, 5);
} else {
imageView = (ImageView) convertView;
}
//imageView.setImageResource(mThumbIds[position]);
Picasso.with(getActivity())
.load(moviePath[position])
.fit()
.into(imageView);
return imageView;
}
}
我还使用了onPostExecut内的setAdapter() e()方法。
谢谢大家的帮助= D