我正在尝试制作一款Android应用。它有一个recyclerView
填充了JSON object
表单https://newsapi.org/v1/sources到cardviews
的数据。我之前做过这个项目,它运行得很好。但当我重复相同的代码时,我不小心删除了该项目。我无法追踪我的错误。
当我运行应用程序时,我收到以下错误。
03-17 21:55:36.706 22896-22896 / com.example.user.samplebulletin E / RecyclerView:未附加适配器;跳过布局 03-17 21:55:36.774 22896-22896 / com.example.user.samplebulletin W / art:在Android 4.1之前,方法int android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int,boolean)会错误地覆盖android.widget.ListView中的package-private方法
我确实记得我在某些功能中添加了@requiresapi
标签,但我不记得是哪些功能。
运行JSON request
后,我收到JSON object
并完美解析(通过记录检查)。但是我得到了这个错误
03-17 21:58:01.936 22896-22896 / com.example.user.samplebulletin E / AndroidRuntime:FATAL EXCEPTION:main 处理:com.example.user.samplebulletin,PID:22896 java.lang.OutOfMemoryError:无法分配506340012字节分配4409258个空闲字节和185MB直到OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) 在android.graphics.BitmapFactory.nativeDecodeAsset(本机方法) 在android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:620) 在android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:455) 在android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1152) 在android.content.res.ResourcesImpl.loadDrawableForCookie(ResourcesImpl.java:724) 在android.content.res.ResourcesImpl.loadDrawable(ResourcesImpl.java:575) 在android.content.res.Resources.loadDrawable(Resources.java:854) 在android.content.res.TypedArray.getDrawable(TypedArray.java:928) 在android.widget.ImageView。(ImageView.java:167) 在android.widget.ImageView。(ImageView.java:155) 在android.support.v7.widget.AppCompatImageView。(AppCompatImageView.java:60) 在android.support.v7.widget.AppCompatImageView。(AppCompatImageView.java:56) 在android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106) 在android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1021) 在android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1080) 在android.support.v4.view.LayoutInflaterCompatHC $ FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:47) 在android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:769) 在android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727) 在android.view.LayoutInflater.rInflate(LayoutInflater.java:858) 在android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821) 在android.view.LayoutInflater.rInflate(LayoutInflater.java:861) 在android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821) 在android.view.LayoutInflater.inflate(LayoutInflater.java:518) 在android.view.LayoutInflater.inflate(LayoutInflater.java:426) 在com.example.user.samplebulletin.NewsAdapter.onCreateViewHolder(NewsAdapter.java:33) 在com.example.user.samplebulletin.NewsAdapter.onCreateViewHolder(NewsAdapter.java:19) 在android.support.v7.widget.RecyclerView $ Adapter.createViewHolder(RecyclerView.java:6321) 在android.support.v7.widget.RecyclerView $ Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5509) 在android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition(RecyclerView.java:5394) 在android.support.v7.widget.RecyclerView $ Recycler.getViewForPosition(RecyclerView.java:5390) 在android.support.v7.widget.LinearLayoutManager $ LayoutState.next(LinearLayoutManager.java:2149) 在android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1533) 在android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1496) 在android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:593) 在android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3537) 在android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3266) 在android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3798) 在android.view.View.layout(View.java:17535) 在android.view.ViewGroup.layout(ViewGroup.java:5616) 在android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 在android.widget.FrameLayout.onLayout(FrameLayout.java:261) 在android.view.View.layout(View.java:17535) 在android.view.ViewGroup.layout(ViewGroup.java:5616) 在android.support.v7.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:437) 在android.view.View.layout(View.java:17535) 在android.view.ViewGroup.layout(ViewGroup.java:5616) 在android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 在android.widget.FrameLayout.onLayout(FrameLayout.java:261) 在android.view.View.layout(View.java:17535) 03-17 21:58:01.937 22896-22896 / com.example.user.samplebulletin E / AndroidRuntime:at android.view.ViewGroup.layout(ViewGroup.java:5616) 在android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741) 在android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585) 在android.widget.LinearLayout.onLayout(LinearLayout.java:1494) 在android.view.View.layout(View.java:17535) 在android.view.ViewGroup.layout(ViewGroup.java:5616) 在android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 在android.widget.FrameLayout.onLayout(FrameLayout.java:261) 在com.android.internal.policy.DecorView.onLayout(DecorView.java:724) 在android.view.View.layout(View.java:17535) 在android.view.ViewGroup.layout(ViewGroup.java:5616) 在android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2354) 在android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2081) 在android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1258) 在android.view.ViewRootImpl $ TraversalRunnable.run(ViewRootImpl.java:6348) 在android.view.Choreographer $ CallbackRecord.run(Choreographer.java:871) 在android.view.Choreographer.doCallbacks(Choreographer.java:683) 在android.view.Choreographer.doFrame(Choreographer.java:619) 在android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.java:857) 在android.os.Handler.handleCallback(Handler.java:751) 在android.os.Handler.dispatchMessage(Handler.java:95) 在android.os.Looper.loop(Looper.java:154) 在android.app.ActivityThread.main(ActivityThread.java:6123) at java.lang.reflect.Method.invoke(Native Method) 在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:867) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
我没有使用位图,并且从未在第一次遇到此错误。
NewsActivity.java
package com.example.user.samplebulletin;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
public class NewsActivity extends AppCompatActivity {
String jsonUrl = "https://newsapi.org/v1/articles?source=the-next-web&sortBy=latest&apiKey=bdba5de1b490495796a1595f77ed3f37";
RecyclerView rv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_source);
rv = (RecyclerView)findViewById(R.id.news_recyclerview);
rv.setLayoutManager(new LinearLayoutManager(NewsActivity.this));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemThatWasClickedId = item.getItemId();
if (itemThatWasClickedId == R.id.refresh) {
new NewsDownloader(NewsActivity.this, jsonUrl, rv).execute();
return true;
}
return super.onOptionsItemSelected(item);
}
}
NewsAdapter.java
package com.example.user.samplebulletin;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
/**
* Created by User on 16-03-2017.
*/
public class NewsAdapter extends RecyclerView.Adapter<NewsViewHolder> {
String TAG = "Not Bla";
Context c;
ArrayList<NewsItem> newsItems;
public NewsAdapter(Context c, ArrayList<NewsItem> newsItems) {
this.c = c;
this.newsItems = newsItems;
}
@Override
public NewsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, "onCreateViewHolder: ");
View v= LayoutInflater.from(c).inflate(R.layout.card_news, parent, false);
return new NewsViewHolder(v);
}
@Override
public void onBindViewHolder(final NewsViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder: ");
NewsItem item = newsItems.get(position);
holder.progressBar.setVisibility(View.VISIBLE);
holder.title.setText(item.getTitle());
holder.description.setText(item.getDescription());
holder.author.setText(item.getAuthor());
holder.date.setText(item.getPublishedAt());
Picasso.with(c)
.load(item.getUrlToImage())
.error(R.drawable.image_not_found)
.into(holder.image, new Callback() {
@Override
public void onSuccess() {
holder.progressBar.setVisibility(View.GONE);
}
@Override
public void onError() {
}
});
}
@Override
public int getItemCount() {
return newsItems.size();
}
}
NewsParser.java
Context c;
String jsonData;
RecyclerView rv;
String TAG = "NOT bla bla";
NewsAdapter adapter;
ProgressDialog pd;
ArrayList<NewsItem> newsItems= new ArrayList<>();
//String id, name, description, url, category, langCode, contCode, smallLogoUrl, medLogoUrl, largeLogoUrl;
public NewsParser(Context c, String jsonData, RecyclerView rv) {
this.c = c;
this.jsonData = jsonData;
this.rv = rv;
}
@Override
protected Boolean doInBackground(Void... params) {
return parse();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(c);
pd.setTitle("Please wait...");
pd.setMessage("Loading list of news newsItems");
pd.show();
}
@Override
protected void onPostExecute(Boolean isParsed) {
super.onPostExecute(isParsed);
pd.dismiss();
if(isParsed){
//bind
adapter = new NewsAdapter(c, newsItems);
rv.setAdapter(adapter);
//rv.setLayoutManager(new LinearLayoutManager(c));
}else
Toast.makeText(c, "Unable to parse", Toast.LENGTH_LONG).show();
}
private boolean parse(){
try{
JSONObject object = new JSONObject(jsonData);
JSONArray jsonArray = object.getJSONArray("articles");
JSONObject jsonObject;
newsItems.clear();
Log.d(TAG, object.toString());
for(int i=0; i<jsonArray.length(); i++){ //jsonArray.length()
jsonObject = jsonArray.getJSONObject(i);
Log.d(TAG, "parse: ");
String author = jsonObject.getString("author");
String title = jsonObject.getString("title");
String description = jsonObject.getString("description");
String url = jsonObject.getString("url");
String urlToImage = jsonObject.getString("urlToImage");
String publishedAt = jsonObject.getString("publishedAt");
String printThis = "New news :\nauthor"+author+"\ntitle"+title+"\ndescription"+description+"\nurl"+url+"\nurlToImage"+urlToImage+"\npublishedAt"+publishedAt;
Log.d(TAG, printThis);
newsItems.add(new NewsItem(author, title, description, url, urlToImage, publishedAt));
}
return true;
} catch (JSONException e) {
e.printStackTrace();
return false;
}
}
NewsDownloader.java
package com.example.user.samplebulletin;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
/**
* Created by User on 16-03-2017.
*/
public class NewsDownloader extends AsyncTask<Void, Void, String> {
Context c;
String jsonUrl;
RecyclerView rv;
String TAG = "Bla bla";
ProgressDialog pd;
public NewsDownloader(Context c, String jsonUrl, RecyclerView rv) {
this.c = c;
this.jsonUrl = jsonUrl;
this.rv = rv;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(c);
pd.setTitle("Please wait...");
pd.setMessage("Loading list of news sources");
pd.show();
}
@Override
protected String doInBackground(Void... params) {
return download();
}
@Override
protected void onPostExecute(String jsonData) {
super.onPostExecute(jsonData);
pd.dismiss();
if(jsonData.startsWith("Error")){
String error = jsonData;
Toast.makeText(c, error, Toast.LENGTH_SHORT).show();
}else{
//parser
new NewsParser(c, jsonData, rv).execute();
}
}
private String download(){
Object connection = Connector.connect(jsonUrl);
if(connection.toString().startsWith("Error"))
return connection.toString();
try{
HttpURLConnection con = (HttpURLConnection)connection;
if(con.getResponseCode()==con.HTTP_OK){
InputStream is = new BufferedInputStream(con.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer jsonData = new StringBuffer();
while((line = br.readLine())!=null)
jsonData.append(line+"\n");
br.close();
is.close();
Log.d(TAG, jsonData.toString());
return jsonData.toString();
}else {
return "Error" + con.getResponseMessage();
}
} catch (IOException e) {
e.printStackTrace();
return "Error : "+e.getMessage();
}
}
}
NewsViewHolder.java
package com.example.user.samplebulletin;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* Created by User on 16-03-2017.
*/
public class NewsViewHolder extends RecyclerView.ViewHolder{
TextView title, author, date, description;
ImageView image;
ProgressBar progressBar;
public NewsViewHolder(View itemView) {
super(itemView);
title = (TextView)itemView.findViewById(R.id.news_title);
description = (TextView)itemView.findViewById(R.id.news_description);
author = (TextView)itemView.findViewById(R.id.news_author);
date = (TextView)itemView.findViewById(R.id.news_date);
image = (ImageView)itemView.findViewById(R.id.news_image);
progressBar = (ProgressBar)itemView.findViewById(R.id.news_progressbar);
}
}
Connector.java
package com.example.user.samplebulletin;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by User on 16-03-2017.
*/
public class Connector {
public static Object connect(String JSONUrl){
try {
URL url = new URL(JSONUrl);
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(15000);
con.setReadTimeout(15000);
con.setDoInput(true);
return con;
} catch (MalformedURLException e) {
e.printStackTrace();
return "Error"+e.getMessage();
} catch (IOException e) {
e.printStackTrace();
return "Error"+e.getMessage();
}
}
}
NewsItem.java
package com.example.user.samplebulletin;
/**
* Created by User on 16-03-2017.
*/
public class NewsItem {
String author, title, description, url, urlToImage, publishedAt;
public NewsItem(String author, String title, String description, String url, String urlToImage, String publishedAt) {
this.author = author;
this.title = title;
this.description = description;
this.url = url;
this.urlToImage = urlToImage;
this.publishedAt = publishedAt;
}
public String getAuthor() {
return author;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public String getUrl() {
return url;
}
public String getUrlToImage() {
return urlToImage;
}
public String getPublishedAt() {
return publishedAt;
}
}
答案 0 :(得分:0)
03-17 21:58:01.936 22896-22896 / com.example.user.samplebulletin E / AndroidRuntime:FATAL EXCEPTION:main进程:com.example.user.samplebulletin,PID:22896 java.lang.OutOfMemoryError:Failed分配一个506340012字节分配4409258个空闲字节和185MB直到OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method)at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)at
这表明您遇到的问题是内存问题。
我检查了数据来自API,图像很大(1612 x 806)(image),这只是一个。将一些这些放在RecyclerView中肯定会让你的记忆大打折扣。
该选项是在加载图像之前缩小图像的大小。毕加索可以选择resize
试试这个:
Picasso.with(c)
.load(item.getUrlToImage())
.resize(70, 70) //The size of your imageView
.error(R.drawable.image_not_found)
.into(holder.image, new Callback() {
@Override
public void onSuccess() {
holder.progressBar.setVisibility(View.GONE);
}
@Override
public void onError() {
}
});
答案 1 :(得分:0)
初始化Recycler视图后未调用setAdapter()时会显示此错误。 初始化回收器视图后可以调用setAdapter(),如
rv = (RecyclerView)findViewById(R.id.news_recyclerview);
rv.setLayoutManager(new LinearLayoutManager(NewsActivity.this));
ArrayList<NewsItem> mDataset = new ArrayList();
NewsAdapter mAdapter = new NewsAdapter(context,mDataset);
rv.setAdapter(mAdapter);
刷新请求完成后,在mDataset中添加传入的新闻。您必须将对mDataset的引用传递给NewsParser。
@Override
protected void onPostExecute(Boolean isParsed) {
super.onPostExecute(isParsed);
pd.dismiss();
if(isParsed){
mDataset.addAll(newsItems);
mAdapter.notifyDataSetChanged();
}else
Toast.makeText(c, "Unable to parse", Toast.LENGTH_LONG).show();
}