我一直在拍电影应用程序(用于学习上udacity机器人BTW项目工作)。我遇到了一些问题,但按照线程这类Unable修改ArrayAdapter中的ListView:UnsupportedOperationException异常
不过,虽然我的应用程序不会崩溃,图像不加载,我无法找出原因。这里是我的code:
布局XML文件movies_item.xml
<?XML版本=1.0编码=UTF-8&GT?;< ImageView的的xmlns:机器人=http://schemas.android.com/apk/res/android 机器人:layout_width =WRAP_CONTENT 机器人:layout_height =WRAP_CONTENT 机器人:ID =@ + ID / movies_item_thumbnail >< / ImageView的>
fragment_main.xml
<的FrameLayout的xmlns:机器人=http://schemas.android.com/apk/res/android 的xmlns:工具=http://schemas.android.com/tools的android:layout_width =match_parent 机器人:layout_height =match_parent机器人:paddingLeft =@扪/ activity_horizontal_margin 机器人:paddingRight =@扪/ activity_horizontal_margin 机器人:paddingTop =@扪/ activity_vertical_margin 机器人:paddingBottom会=@扪/ activity_vertical_margin 工具:上下文=com.example.cindy.popularmovies.MoviesFragment> < GridView控件 机器人:ID =@ + ID / movies_gridview 机器人:layout_width =match_parent 机器人:layout_height =match_parent 机器人:为numColumns =auto_fit 机器人:比重=中心 />< /&的FrameLayout GT;
MovieArrayAdapter.java
公共类MovieArrayAdapter扩展ArrayAdapter<电影及GT; { 私人最终上下文的背景下; 私人最终名单<电影及GT;电影; 公共MovieArrayAdapter(上下文的背景下,列表与LT;电影>电影){ 超(背景下,0,电影); this.context =背景; this.movies =电影; } / * *内getView()方法,你能吹一个基于XML的布局和 *然后设置的基于Java对象该行对个人意见的内容。 * * / @覆盖 公共查看getView(INT位置,查看convertView,父母的ViewGroup){ 查看rowView = convertView; 如果(rowView == NULL){ //充气基于XML布局 LayoutInflater吹气=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); rowView = inflater.inflate(R.layout.movies_item,父母,假); //获取的ImageView ImageView的movieThumbnail =(ImageView的)rowView.findViewById(R.id.movies_item_thumbnail); //加载图片到ImageView的 Picasso.with(上下文).load(movies.get(位置).getThumbnail())到(movieThumbnail)。 Log.v(填充,movies.get(位置).getThumbnail()); } 返回rowView; } @覆盖 公众诠释的getCount(){ 返回super.getCount(); } @覆盖 公众诠释为getPosition(电影项目){ 返回super.getPosition(项目); } }MovieFragment.java公共类MoviesFragment扩展片段{ 私人MovieArrayAdapter mMoviesAdapter; 公共MoviesFragment(){ } @覆盖 公共无效调用onStart(){ super.onStart(); 新FetchMoviesTask()执行(); } @覆盖 公共查看onCreateView(LayoutInflater充气器,容器的ViewGroup, 捆绑savedInstanceState){ 查看rootView = inflater.inflate(R.layout.fragment_main,集装箱,FALSE); mMoviesAdapter =新MovieArrayAdapter(getActivity(),新的ArrayList<电影及GT;()); GridView控件moviesGridView =(GridView控件)rootView.findViewById(R.id.movies_gridview); moviesGridView.setAdapter(mMoviesAdapter); 返回rootView; } 公共类FetchMoviesTask扩展的AsyncTask<弦乐,太虚,电影[]> { 最后弦乐LOG_TAG = this.getClass()getSimpleName()。 @覆盖 保护电影[] doInBackground(字符串... PARAMS){ //检索大众电影JSON字符串 串moviesJsonString = getMoviesJsonString(); //解析JSON字符串来获得重要数据 尝试{ 返回getPopularMoviesInfo(moviesJsonString); }赶上(JSONException E){ Log.e(LOG_TAG,e.getMessage(),E); } 返回null; } @覆盖 保护无效onPostExecute(动画[]电影){ 如果(电影!= NULL){ mMoviesAdapter.clear(); mMoviesAdapter.addAll(电影); } } / * *此功能是从Web API获取热门电影JSON字符串 * * / 私人字符串getMoviesJsonString(){ HttpURLConnection类的URLConnection = NULL; 的BufferedReader的BufferedReader = NULL; 字符串moviesJsonString = NULL; 尝试{ //设置的URI 最后弦乐MOVIES_BASE_URL =http://api.themoviedb.org/3/discover/movie? 最后弦乐SORT_PARAM =sort_by; 最后弦乐API_PARAM =API_KEY; 乌里moviesUri = Uri.parse(MOVIES_BASE_URL).buildUpon() .appendQueryParameter(SORT_PARAMpopularity.desc) .appendQueryParameter(API_PARAM,的getString(R.string.movies_api)) 。建立(); //打开连接 网址URL =新的URL(moviesUri.toString()); URLConnection的=(HttpURLConnection类)url.openConnection(); urlConnection.setRequestMethod(GET); urlConnection.connect(); //读取输入流中的字符串 为InputStream的InputStream = urlConnection.getInputStream(); 如果(InputStream的== NULL){ 返回null; } 的BufferedReader =新的BufferedReader(新的InputStreamReader(InputStream的)); 串线; StringBuffer的缓冲区=新的StringBuffer(); 而((行= bufferedReader.readLine())!= NULL){ buffer.append(行+\\ n); } 如果(buffer.length()== 0){ //流是空的 返回null; } moviesJsonString = buffer.toString(); }赶上(IOException异常五){ Log.e(LOG_TAG,错误,E); } {最后 如果(URLConnection的!= NULL){ urlConnection.disconnect(); } 如果(的BufferedReader!= NULL){ 尝试{ bufferedReader.close(); }赶上(IOException异常五){ Log.e(LOG_TAG,错误收盘流,E); } } } 返回moviesJsonString; } / * *此功能是解析JSON字符串来检索信息 * * / 民营电影[] getPopularMoviesInfo(字符串jsonString)抛出JSONException { //缩略图的基本URL 最后弦乐THUMBNAIL_BASE_URL =http://image.tmdb.org/t/p/w185; //属性名,我们感兴趣的是JSON字符串 最后弦乐M_RESULTS =成果; 最后弦乐M_THUMBNAIL =backdrop_path; 最后弦乐M_TITLE =ORIGINAL_TITLE; 最后弦乐M_ID =ID; 最后弦乐M_SYPNOSIS =概览; 最后弦乐M_USER_RATING =vote_average; 最后弦乐M_RELEASE_DATE =RELEASE_DATE; //转换JSON字符串以JSON对象 JSONObject的moviesJsonObject =新的JSONObject(jsonString); //获取JSON数组 JSONArray moviesJsonArray = moviesJsonObject.getJSONArray(M_RESULTS); 电影[] =电影新电影[moviesJsonArray.length()]; 的for(int i = 0; I< moviesJsonArray.length();我++){ 的JSONObject电影= moviesJsonArray.getJSONObject(ⅰ); 电影由[i] =新电影(THUMBNAIL_BASE_URL + movie.getString(M_THUMBNAIL) movie.getString(M_TITLE) movie.getString(M_ID) movie.getString(M_SYPNOSIS) movie.getString(M_USER_RATING) movie.getString(M_RELEASE_DATE)); Log.v(电影,movie.getString(M_TITLE)); } 回归电影; } }}
有没有错误,但图像不加载。我一直在寻找在其他线程,但无法找到答案我的问题。非常感谢你。
根据下面的讨论[增订]更改了code:
@覆盖 公共查看getView(INT位置,查看convertView,父母的ViewGroup){ 如果(convertView == NULL){ //充气基于XML布局 LayoutInflater吹气=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.movies_item,父母,假); } //获取的ImageView ImageView的movieThumbnail =(ImageView的)convertView.findViewById(R.id.movies_item_thumbnail); //加载图片到ImageView的 Picasso.with(上下文).load(movies.get(位置).getThumbnail())到(movieThumbnail)。 Log.v(填充,movies.get(位置).getThumbnail()); 返回convertView; }
解决方案
这些行:
//获取的ImageViewImageView的movieThumbnail =(ImageView的)rowView.findViewById(R.id.movies_item_thumbnail); //加载图片到ImageView的 Picasso.with(上下文).load(movies.get(位置).getThumbnail())到(movieThumbnail)。
去外面的如果(rowView == NULL){
您总是会得到只有一个空
convertView
,你必须调用两行,而你正在更新/填充你的 GridView控件
。此刻你应该看到遍地常存第一张图像。请不要忘了上网权限添加到清单
I have been making a Movie App (project work for learning android on udacity btw). I encountered a few problems but resolved them by following threads such as these Unable to modify ArrayAdapter in ListView: UnsupportedOperationException
However, although my app does not crash, the images are not loading and I cannot figure out why. Here is my code:
Layout XMl files movies_item.xml
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id = "@+id/movies_item_thumbnail"
>
</ImageView>
fragment_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.cindy.popularmovies.MoviesFragment">
<GridView
android:id="@+id/movies_gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="auto_fit"
android:gravity="center"
/>
</FrameLayout>
MovieArrayAdapter.java
public class MovieArrayAdapter extends ArrayAdapter<Movie> {
private final Context context;
private final List<Movie> movies;
public MovieArrayAdapter(Context context,List<Movie> movies) {
super(context,0,movies);
this.context = context;
this.movies = movies;
}
/*
* Within the getView() method you would inflate an XML based layout and
* then set the content of the individual views based on the Java object for this row.
* */
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if(rowView == null) {
//Inflate the XML based Layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.movies_item, parent, false);
//Get the ImageView
ImageView movieThumbnail = (ImageView) rowView.findViewById(R.id.movies_item_thumbnail);
//Load Image into the ImageView
Picasso.with(context).load(movies.get(position).getThumbnail()).into(movieThumbnail);
Log.v("Populating", movies.get(position).getThumbnail());
}
return rowView;
}
@Override
public int getCount() {
return super.getCount();
}
@Override
public int getPosition(Movie item) {
return super.getPosition(item);
}
}
MovieFragment.java
public class MoviesFragment extends Fragment {
private MovieArrayAdapter mMoviesAdapter;
public MoviesFragment() {
}
@Override
public void onStart() {
super.onStart();
new FetchMoviesTask().execute();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
mMoviesAdapter = new MovieArrayAdapter(getActivity(),new ArrayList<Movie>());
GridView moviesGridView = (GridView) rootView.findViewById(R.id.movies_gridview);
moviesGridView.setAdapter(mMoviesAdapter);
return rootView;
}
public class FetchMoviesTask extends AsyncTask<String,Void,Movie[]> {
final String LOG_TAG = this.getClass().getSimpleName();
@Override
protected Movie[] doInBackground(String...params) {
//Retrieve the Popular Movies Json String
String moviesJsonString = getMoviesJsonString();
//Parse the Json String to get important data
try {
return getPopularMoviesInfo(moviesJsonString);
} catch(JSONException e) {
Log.e(LOG_TAG,e.getMessage(),e);
}
return null;
}
@Override
protected void onPostExecute(Movie[] movies) {
if(movies != null) {
mMoviesAdapter.clear();
mMoviesAdapter.addAll(movies);
}
}
/*
* This Function is to retrieve the Popular movies Json String from a WEB API
* */
private String getMoviesJsonString() {
HttpURLConnection urlConnection = null;
BufferedReader bufferedReader = null;
String moviesJsonString = null;
try {
//Set up the URI
final String MOVIES_BASE_URL = "http://api.themoviedb.org/3/discover/movie?";
final String SORT_PARAM = "sort_by";
final String API_PARAM ="api_key";
Uri moviesUri = Uri.parse(MOVIES_BASE_URL).buildUpon()
.appendQueryParameter(SORT_PARAM, "popularity.desc")
.appendQueryParameter(API_PARAM,getString(R.string.movies_api))
.build();
//Open the connection
URL url = new URL(moviesUri.toString());
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
//Read the input stream into a string
InputStream inputStream = urlConnection.getInputStream();
if(inputStream == null) {
return null;
}
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuffer buffer = new StringBuffer();
while((line = bufferedReader.readLine()) != null) {
buffer.append(line + "\n");
}
if(buffer.length() == 0){
//Stream was empty
return null;
}
moviesJsonString = buffer.toString();
}catch(IOException e) {
Log.e(LOG_TAG,"Error",e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if(bufferedReader != null) {
try {
bufferedReader.close();
} catch(IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
return moviesJsonString;
}
/*
* This function is to parse the JSON String to retrieve info
* */
private Movie[] getPopularMoviesInfo(String jsonString) throws JSONException{
//Base URL of thumbnail
final String THUMBNAIL_BASE_URL = " http://image.tmdb.org/t/p/w185";
//The attribute names we are interested in the JSON String
final String M_RESULTS = "results";
final String M_THUMBNAIL = "backdrop_path";
final String M_TITLE = "original_title";
final String M_ID = "id";
final String M_SYPNOSIS = "overview";
final String M_USER_RATING = "vote_average";
final String M_RELEASE_DATE = "release_date";
//Convert Json String to Json Object
JSONObject moviesJsonObject = new JSONObject(jsonString);
//Get the Json Array
JSONArray moviesJsonArray = moviesJsonObject.getJSONArray(M_RESULTS);
Movie[] movies = new Movie[moviesJsonArray.length()];
for(int i=0;i<moviesJsonArray.length();i++) {
JSONObject movie = moviesJsonArray.getJSONObject(i);
movies[i] = new Movie(THUMBNAIL_BASE_URL + movie.getString(M_THUMBNAIL),
movie.getString(M_TITLE),
movie.getString(M_ID),
movie.getString(M_SYPNOSIS),
movie.getString(M_USER_RATING),
movie.getString(M_RELEASE_DATE));
Log.v("Movie",movie.getString(M_TITLE));
}
return movies;
}
}
}
There is no error, but the images are not loading. I have been looking in other threads, but cannot find the answer to my problem. Thank you very much.
[UPDATED] Changed the code according to discussion below:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
//Inflate the XML based Layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.movies_item, parent, false);
}
//Get the ImageView
ImageView movieThumbnail = (ImageView) convertView.findViewById(R.id.movies_item_thumbnail);
//Load Image into the ImageView
Picasso.with(context).load(movies.get(position).getThumbnail()).into(movieThumbnail);
Log.v("Populating", movies.get(position).getThumbnail());
return convertView;
}
解决方案
those line:
//Get the ImageView
ImageView movieThumbnail = (ImageView) rowView.findViewById(R.id.movies_item_thumbnail);
//Load Image into the ImageView
Picasso.with(context).load(movies.get(position).getThumbnail()).into(movieThumbnail);
go outside the if(rowView == null) {
You will always get only one null
convertView
, and you have to call that two lines while you are updating/populating your GridView
. At the moment you should see alway the first image over and over. Please don't forget to add the Internet permission to the manifest