我想在交错网格布局中显示我从Flickr获得的位图。照片在开始时显示良好。但是,当我进一步向下滚动图像时,它会返回"错误 - 内存不足"。显示位图图像时如何避免内存不足错误?以下是我的日志:
E/dalvikvm-heap: Out of memory on a 322013-byte allocation.
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: "Thread-557" prio=5 tid=13 RUNNABLE
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: | group="main" sCount=0 dsCount=0 obj=0x4251a118 self=0x5f496370
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: | sysTid=25360 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=1598646248
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: | state=R schedstat=( 24035935571 12370314782 38194 ) utm=2070 stm=333 core=1
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: at java.io.ByteArrayOutputStream.toByteArray(ByteArrayOutputStream.java:~122)
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: at com.android.volley.toolbox.BasicNetwork.entityToBytes(BasicNetwork.java:222)
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:105)
01-21 09:56:42.718 25341-25360/com.example.myapp I/dalvikvm: at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)
01-21 09:56:42.718 25341-25360/com.example.myapp W/dalvikvm: threadid=13: thread exiting with uncaught exception (group=0x4174cd58)
01-21 09:56:42.718 25341-25360/com.example.myapp I/Process: Sending signal. PID: 25341 SIG: 9
01-21 09:56:42.838 1057-1399/? I/ActivityManager: Process com.example.myapp (pid 25341) has died.
01-21 09:56:42.878 1057-1068/? W/InputMethodManagerService: Got RemoteException sending setActive(false) notification to pid 25341 uid 10186
01-21 09:56:42.878 1315-1326/? W/Binder: Caught a RuntimeException from the binder stub implementation.
java.lang.NullPointerException
at android.inputmethodservice.IInputMethodWrapper.setSessionEnabled(IInputMethodWrapper.java:280)
at com.android.internal.view.IInputMethod$Stub.onTransact(IInputMethod.java:129)
at android.os.Binder.execTransact(Binder.java:404)
at dalvik.system.NativeStart.run(Native Method)
以下是从Flickr获取图像的程序
@SuppressLint("ValidFragment")
public class FragmentRecent extends Fragment implements FragmentManager.OnBackStackChangedListener{
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private StaggeredGridView mStaggeredView;
private RequestQueue mVolleyQueue;
private ProgressDialog mProgress;
private int currPage=1;
GsonRequest<FlickrResponsePhotos> gsonObjRequest;
private RelativeLayout mListFooter;
private boolean isLoading = false;
private final String TAG_REQUEST = "MY_TAG";
private StaggeredGridView.OnScrollListener scrollListener = new StaggeredGridView.OnScrollListener() {
public void onTop() {
}
public void onScroll() {
loadMoreData();//edit from onBottom
}
public void onBottom() {
// loadMoreData(); TBS commented out for loading new data while scrolling
}
};
private void loadMoreData() {
if ( isLoading )
return;
mListFooter.setVisibility(View.VISIBLE);
isLoading = true;
flickerGetImagesRequest();
}
private void flickerGetImagesRequest() {
{
String url = "https://api.flickr.com/services/rest";
Uri.Builder builder = Uri.parse(url).buildUpon();
builder.appendQueryParameter("api_key", "5e045abd4baba4bbcd866e1864ca9d7b");
//builder.appendQueryParameter("method", "flickr.interestingness.getList"); //TBS
builder.appendQueryParameter("method", "flickr.photos.search");
builder.appendQueryParameter("tags",mMenuChoice);
//builder.appendQueryParameter("sort","relevance");
builder.appendQueryParameter("format", "json");
builder.appendQueryParameter("nojsoncallback", "1");
// builder.appendQueryParameter("per_page", "10");
builder.appendQueryParameter("page", Integer.toString(currPage));
gsonObjRequest = new GsonRequest<FlickrResponsePhotos>(Request.Method.GET, builder.toString(),
FlickrResponsePhotos.class, null, new Response.Listener<FlickrResponsePhotos>() {
@Override
public void onResponse(FlickrResponsePhotos response) {
try {
if(response != null) {
parseFlickrImageResponse(response);
currPage++;
}
} catch (Exception e) {
e.printStackTrace();
showToast("JSON parse error");
}
stopProgress();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// Handle your error types accordingly.For Timeout & No connection error, you can show 'retry' button.
// For AuthFailure, you can re login with user credentials.
// For ClientError, 400 & 401, Errors happening on client side when sending api request.
// In this case you can check how client is forming the api and debug accordingly.
// For ServerError 5xx, you can do retry or handle accordingly.
if( error instanceof NetworkError) {
} else if( error instanceof ClientError) {
} else if( error instanceof ServerError) {
} else if( error instanceof AuthFailureError) {
} else if( error instanceof ParseError) {
} else if( error instanceof NoConnectionError) {
} else if( error instanceof TimeoutError) {
}
//mStaggeredView.onRefreshComplete();
stopProgress();
showToast(error.getMessage());
}
});
gsonObjRequest.setTag(TAG_REQUEST);
mVolleyQueue.add(gsonObjRequest);
}
}
private void parseFlickrImageResponse(FlickrResponsePhotos response) {
FlickrGetImagesResponse photos = response.getPhotos(); //pass array of images to Picture Activity
String[] photoUrl;
photoUrl = new String[photos.getPhotos().size()];
for (int index = 0; index < photos.getPhotos().size(); index++) {
FlickrImage flkrImage = photos.getPhotos().get(index);
photoUrl[index]=flkrImage.getImageUrl();
StaggeredGridViewItem item = null;
item = new GridItem(getActivity(), flkrImage,photoUrl); //pass one image of index
mStaggeredView.addItem(item);
}
}
private void showToast(String msg) {
Toast.makeText(getActivity(), msg, Toast.LENGTH_LONG).show();
}
private void stopProgress() {
isLoading = false;
mListFooter.setVisibility(View.GONE);
mProgress.cancel();
}
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
private String mMenuChoice;
public FragmentRecent(String menuChoice) {
// Required empty public constructor
mMenuChoice=menuChoice;
}
//private GridViewAdapter adapter;
private GridView gridView;
private int columnWidth;
private Integer[] photosList;
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment FragmentOne.
*/
// TODO: Rename and change types and number of parameters
public static FragmentRecent newInstance(int page) {
FragmentRecent fragment = new FragmentRecent("recentValue");
Bundle args = new Bundle();
args.putInt("someInt", page);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(mVolleyQueue==null){
mVolleyQueue= Volley.newRequestQueue(getActivity());
}
mVolleyQueue = StaggeredDemoApplication.getRequestQueue(getActivity());//added this
showProgress();
//added async task
//new PrefetchData().execute();
flickerGetImagesRequest();
}
private void showProgress() {
mProgress = ProgressDialog.show(getActivity(), "", "Loading...");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_flickrstart, container, false);
// gridView = (GridView) rootView.findViewById(R.id.grid_view);
// gridView.setVisibility(View.VISIBLE);
// gridView.setAdapter(new GridViewAdapter(getActivity()));
mListFooter = (RelativeLayout) rootView.findViewById(R.id.footer);
mStaggeredView = (StaggeredGridView) rootView.findViewById(R.id.staggeredview);
// Be sure before calling initialize that you haven't initialised from XML
//mStaggeredView.initialize(2, StaggeredGridView.Mode.FIXED);
mStaggeredView.setOnScrollListener(scrollListener);
Toast.makeText(getActivity(),mMenuChoice,Toast.LENGTH_SHORT).show();
return rootView;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onBackStackChanged() {
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
以下是将图像添加到gridItem
的代码public class GridItem extends StaggeredGridViewItem {
private Context mContext;
private ImageLoader mImageLoader;
private FlickrImage mImage;
private View mView;
private int mHeight;
private String[] mPhotoUrl;
public GridItem(Context context, FlickrImage image, String[] photoUrl) {
mImage = image;
mContext = context;
mImageLoader = StaggeredDemoApplication.getImageLoader();
mPhotoUrl=photoUrl;
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
@Override
public View getView(int position, LayoutInflater inflater, ViewGroup parent) {
// TODO Auto-generated method stub
mView = inflater.inflate(R.layout.grid_item, null);
final ImageView image = (ImageView) mView.findViewById(R.id.image);
mImageLoader.get(mImage.getImageUrl(),
ImageLoader.getImageListener(image, R.drawable.bg_no_image, android.R.drawable.ic_dialog_alert), parent.getWidth(), 0);
image.setOnClickListener(new OnImageClickListener(position));//correct position 11,12,13..
return mView;
}
@Override
public int getViewHeight(LayoutInflater inflater, ViewGroup parent) {
FrameLayout item_containerFrameLayout = (FrameLayout)mView.findViewById(R.id.container);
item_containerFrameLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
mHeight = item_containerFrameLayout.getMeasuredHeight();
return mHeight;
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private class OnImageClickListener implements View.OnClickListener {
int _position;
public OnImageClickListener(int position) {
this._position = position;
}
@Override
public void onClick(View v) {
Intent iSlider = new Intent(mContext, FullScreenImageActivity.class);
iSlider.putExtra("position", _position); //0
iSlider.putExtra("array",mPhotoUrl);//check whether is old or new array
iSlider.putExtra("url",mImage.getImageUrl());
mContext.startActivity(iSlider);
}
}
}
以下是图片加载的代码
public class StaggeredDemoApplication extends Application {
private static Context applicationContext;
private static RequestQueue mRequestQueue;
private static ImageLoader mImageLoader;
private static BitmapLruCache mBitmapCache;
public static boolean INIT_FLAG = true;
public void onCreate() {
super.onCreate();
applicationContext = this.getApplicationContext();
mRequestQueue = Volley.newRequestQueue(applicationContext);
long size = Runtime.getRuntime().maxMemory()/4;
mBitmapCache = new BitmapLruCache(30);//(int)size);
mImageLoader = new ImageLoader(mRequestQueue, mBitmapCache);
}
public static RequestQueue getRequestQueue(Context mContext) {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mContext);
}
return mRequestQueue;
}
public static ImageLoader getImageLoader() {
if (mImageLoader != null) {
return mImageLoader;
} else {
throw new IllegalStateException("ImageLoader not initialized");
}
}
}