我已经梳理了解决此stackoverflow,我已经尝试了吨的片段,并一直无法找出问题。无法填充从api调用gridview
因此,我正在关注一个android Udacity课程,并且已经达到了一个要求我使用电影数据库的api调用填充电影海报的GridView的点。 我在这里看到很多其他人在做同样的项目的计算器stackoverflow然而主要区别(可能为什么他们的解决方案没有为我工作)我有,我试图做到这一点与所有主要类在单独的文件,而不是在主要活动中拥有一切或类似的东西。
我已经尝试了所有解决方案为他们工作,如将gridview适配器声明和setadapter移动到asynctask中的onPostExecute的末尾,并且一遍又一遍地修改了我的ImageAdapter类,但是我无法得到它上班。
我的应用程序不会调用API,记录接收到的JSON和所有海报链接,以及将链接正确复制到arraylist;但gridview不填充。
这里是我的代码:
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new GalleryFragment())
.commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
ImageAdapter.java
public class ImageAdapter extends BaseAdapter {
private final String LOG_TAG = ImageAdapter.class.getSimpleName();
private List<?> mImageList = new ArrayList<>();
private LayoutInflater inflater;
public ImageAdapter(LayoutInflater i, List<?> images) {
this.mImageList = images;
this.inflater = i;
}
@Override
public Object getItem(int position) {
return mImageList.get(position);
}
@Override
public int getCount() {
return mImageList.size();
}
@Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null){
imageView = new ImageView(inflater.getContext());
} else {
imageView = (ImageView) convertView;
}
Log.v(LOG_TAG,"New one: " + mImageList.get(position).toString());
Picasso
.with(inflater.getContext())
.load(mImageList.get(position).toString())
.into(imageView);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setAdjustViewBounds(true);
return imageView;
}
}
GalleryFragment.java
public class GalleryFragment extends Fragment {
public static GridView gridView;
public static ImageAdapter imageAdapter;
public GalleryFragment() {
// Required empty public constructor
}
@Override
public void onStart() {
super.onStart();
FetchMovies data = new FetchMovies(getActivity());
data.execute();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_gallery, container, false);
gridView = (GridView) rootView.findViewById(R.id.gridview);
return rootView;
}
}
FetchMovies.java
public class FetchMovies extends AsyncTask <Void, Void, String[]> {
private final String LOG_TAG = FetchMovies.class.getSimpleName();
private Context context;
List<Uri> posterURLs = new ArrayList<>();
String[] title, overview, popularity, rating, releaseDate;
public FetchMovies(Context c){
this.context = c;
}
/**
* Prepare image URL for presentation.
*/
private String formatURL(String relativeURL) {
String imageBaseURL = "http://image.tmdb.org/t/p/";
String size = "w185";
relativeURL = relativeURL.substring(1);
Uri uri = Uri.parse(imageBaseURL).buildUpon()
.appendPath(size)
.appendPath(relativeURL).build();
return uri.toString();
}
private String[] getMovieDataFromJson(String movieJsonStr)
throws JSONException {
// These are the names of the JSON objects that need to be extracted.
final String RESULT_LIST = "results";
final String TITLE = "original_title";
final String POSTER_URL = "poster_path";
final String OVERVIEW = "overview";
final String POPULARITY = "popularity";
final String RATING = "vote_average";
final String RELEASE_DATE = "release_date";
JSONObject allMovieData = new JSONObject(movieJsonStr);
JSONArray resultsArray = allMovieData.getJSONArray(RESULT_LIST);
String[] posterPaths = new String[resultsArray.length()];
title = new String[resultsArray.length()];
overview = new String[resultsArray.length()];
popularity = new String[resultsArray.length()];
rating = new String[resultsArray.length()];
releaseDate = new String[resultsArray.length()];
for(int i = 0; i < resultsArray.length(); i++) {
// Get the JSON object representing one movie's details
JSONObject eachMovie = resultsArray.getJSONObject(i);
title[i] = eachMovie.getString(TITLE);
String relativeURL = eachMovie.getString(POSTER_URL);
posterPaths[i] = formatURL(relativeURL);
overview[i] = eachMovie.getString(OVERVIEW);
popularity[i] = eachMovie.getString(POPULARITY);
rating[i] = eachMovie.getString(RATING);
releaseDate[i] = eachMovie.getString(RELEASE_DATE);
Log.v("poster path", posterPaths[i]);
}
return posterPaths;
}
@Override
protected String[] doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
//For building the URL for the weather query from OpenWeatherMap
final String BASE_URL = "http://api.themoviedb.org/3/discover/movie?";
final String SORT_PARAM = "sort_by";
final String API_PARAM = "api_key";
String sort_by = "popularity.desc",
apiKey = "MY API KEY IS PLACED HERE";
// Will contain the raw JSON response as a string.
String movieJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are available at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
Uri queryUri = Uri.parse(BASE_URL).buildUpon()
//.appendQueryParameter(SORT_PARAM,params[0])
.appendQueryParameter(SORT_PARAM, sort_by)
.appendQueryParameter(API_PARAM,apiKey).build();
URL queryUrl = new URL(queryUri.toString());
// Create the request to TheMovieDB, and open the connection
urlConnection = (HttpURLConnection) queryUrl.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
Log.v(LOG_TAG, "Couldn't open input stream.");
// Nothing to do.
return null;
}
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.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
Log.v(LOG_TAG, "Input stream was empty.");
// Stream was empty. No point in parsing.
return null;
}
//if all's well, parse the required data and return it to the system
//(which then calls the onPostExecute() method with this data).
movieJsonStr = buffer.toString();
Log.v(LOG_TAG,movieJsonStr);
return getMovieDataFromJson(movieJsonStr);
//return getWeatherDataFromJson(forecastJsonStr, numDays);
} catch (IOException e) {
Log.e(LOG_TAG, "Error: Couldn't get movie data. ", e);
// If the code didn't successfully get the weather data, there's no point in attempting
// to parse it.
return null;
} catch (JSONException e) {
Log.e(LOG_TAG, "Error in parsing: ", e);
//If there is an error in parsing the JSON data, there's nothing to display.
return null;
}
finally
{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
}
@Override
protected void onPostExecute(String[] strings) {
super.onPostExecute(strings);
for (int i=0; i<strings.length;i++){
Uri uri = Uri.parse(strings[i]);
posterURLs.add(uri);
}
LayoutInflater inflater = LayoutInflater.from(context);
GalleryFragment.imageAdapter = new ImageAdapter(inflater,posterURLs);
GalleryFragment.gridView.setAdapter(GalleryFragment.imageAdapter);
}
}
这里是我的布局文件:
fragment_gallery.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"
tools:context="com.example.zakna.popularmovies.GalleryFragment">
<GridView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/gridview"
android:layout_gravity="start|top"
android:numColumns="auto_fit"
android:clickable="false" />
</FrameLayout>
gallery_grid_item.xml
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/movie_poster">
</ImageView>
activity_main.xml中
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.zakna.popularmovies.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
content_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity" tools:ignore="MergeRootFrame" />
logcat的输出:
W/System: ClassLoader referenced unknown path: /data/app/com.example.zakna.popularmovies-1/lib/arm64
W/System: ClassLoader referenced unknown path: /data/app/com.example.zakna.popularmovies-1/lib/arm64
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
I/DpmTcmClient: RegisterTcmMonitor from: com.android.okhttp.TcmIdleTimerMonitor
D/AppTracker: App Event: start
D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
I/Adreno: QUALCOMM build : 183c040, Iff84fb1103
Build Date : 03/18/16
OpenGL ES Shader Compiler Version: XE031.06.00.02
Local Branch :
Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.BF64.1.2.2_RB4.06.00.01.180.031
Remote Branch : NONE
Reconstruct Branch : NOTHING
I/OpenGLRenderer: Initialized EGL, version 1.4
D/AbstractTracker: Event success
V/FetchMovies: SNIPPED JSON FILE
V/poster path: http://image.tmdb.org/t/p/w185/e1mjopzAS2KNsvpbpahQ1a6SkSn.jpg
V/poster path: http://image.tmdb.org/t/p/w185/lFSSLTlFozwpaGlO31OoUeirBgQ.jpg
V/poster path: http://image.tmdb.org/t/p/w185/vOipe2myi26UDwP978hsYOrnUWC.jpg
V/poster path: http://image.tmdb.org/t/p/w185/cGOPbv9wA5gEejkUN892JrveARt.jpg
V/poster path: http://image.tmdb.org/t/p/w185/kqjL17yufvn9OVLyXYpvtyrFfak.jpg
V/poster path: http://image.tmdb.org/t/p/w185/5N20rQURev5CNDcMjHVUZhpoCNC.jpg
V/poster path: http://image.tmdb.org/t/p/w185/h28t2JNNGrZx0fIuAw8aHQFhIxR.jpg
V/poster path: http://image.tmdb.org/t/p/w185/uANwnNNlX4DfUoA6UurzyoAAxTj.jpg
V/poster path: http://image.tmdb.org/t/p/w185/4qnJ1hsMADxzwnOmnwjZTNp0rKT.jpg
V/poster path: http://image.tmdb.org/t/p/w185/gj282Pniaa78ZJfbaixyLXnXEDI.jpg
V/poster path: http://image.tmdb.org/t/p/w185/jjBgi2r5cRt36xF6iNUEhzscEcb.jpg
V/poster path: http://image.tmdb.org/t/p/w185/vNCeqxbKyDHL9LUza03V2Im16wB.jpg
V/poster path: http://image.tmdb.org/t/p/w185/5JU9ytZJyR3zmClGmVm9q4Geqbd.jpg
V/poster path: http://image.tmdb.org/t/p/w185/ghL4ub6vwbYShlqCFHpoIRwx2sm.jpg
V/poster path: http://image.tmdb.org/t/p/w185/dCgm7efXDmiABSdWDHBDBx2jwmn.jpg
V/poster path: http://image.tmdb.org/t/p/w185/inVq3FRqcYIRl2la8iZikYYxFNR.jpg
V/poster path: http://image.tmdb.org/t/p/w185/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg
V/poster path: http://image.tmdb.org/t/p/w185/sM33SANp9z6rXW8Itn7NnG1GOEs.jpg
V/poster path: http://image.tmdb.org/t/p/w185/aBBQSC8ZECGn6Wh92gKDOakSC8p.jpg
V/poster path: http://image.tmdb.org/t/p/w185/t2mZzQXjpQxmqtJOPpe8Dr2YpMl.jpg
V/ImageAdapter: New one: http://image.tmdb.org/t/p/w185/e1mjopzAS2KNsvpbpahQ1a6SkSn.jpg
W/Settings: Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
W/IInputConnectionWrapper: getExtractedText on inactive InputConnection
W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
W/IInputConnectionWrapper: getSelectedText on inactive InputConnection
W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
D/AppTracker: App Event: stop
D/AbstractTracker: Event success
我的日志还显示我的ImageAdapter类只调用一次。它不应该被称为多次,因为它填充gridview? 在这一点上,我很确信这个问题与布局文件有关,也许我没有在正确的地方调用正确的地方或类似的东西,但我无法弄清楚。帮助将不胜感激,谢谢!
你有权限吗? –
我有清单文件中的Internet权限。 <使用权限android:name =“android.permission.INTERNET”/> 我需要任何其他权限吗? –
也许有存储权限? –