我创建了一个列出视频并播放它们的Android应用程序。我使用AsyncTask
加载background
中的视频。加载列表中的视频需要一些时间。
但是当我在列表中加载视频之前关闭此fragment
时,它会显示Out Of Memory Error
。
如何解决这个问题??
PlayerFragment.java
public class PlayerFragment extends Fragment {
private RecyclerView recyclerView;
private ArrayList<VideoModel> dataList;
private ArrayList<VideoModel> videoData;
private GetDataForAdapter dataForAdapter;
private ProgressDialog progressDialog;
private TextView noVideoText;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_player, container, false);
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Loading Videos...");
progressDialog.setCanceledOnTouchOutside(false);
noVideoText = (TextView) view.findViewById(R.id.noVideoText);
dataForAdapter = new GetDataForAdapter(getActivity());
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view_for_video);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
dataList = new ArrayList<>();
new LoadVideoData().execute();
//setRecyclerView();
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
public class LoadVideoData extends AsyncTask<Void, Void, ArrayList<VideoModel>> {
@Override
protected void onPreExecute() {
//super.onPreExecute();
progressDialog.show();
}
@Override
protected ArrayList<VideoModel> doInBackground(Void... voids) {
videoData = dataForAdapter.getVideoData();
return videoData;
}
@Override
protected void onPostExecute(ArrayList<VideoModel> videoModels) {
if (videoModels.isEmpty()){
noVideoText.setVisibility(View.VISIBLE);
}
else {
setRecyclerView(videoModels);
noVideoText.setVisibility(View.INVISIBLE);
}
if (progressDialog.isShowing())
progressDialog.dismiss();
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
/*private ArrayList<VideoModel> getDataList() {
for (int i = 0; i < 20; i++) {
VideoModel model = new VideoModel();
model.setName("Video Downloaded From Facebook");
dataList.add(model);
}
return dataList;
}*/
private void setRecyclerView(ArrayList<VideoModel> videoModels) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
} else {
recyclerViewPart(videoModels);
}
} else {
recyclerViewPart(videoModels);
}
}
public void recyclerViewPart(ArrayList<VideoModel> videoModels) {
VideoFilesAdapters adapters = new VideoFilesAdapters(getActivity(), videoModels);
recyclerView.setAdapter(adapters);
registerForContextMenu(recyclerView);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setRecyclerView(videoData);
} else {
Log.e("Permission Denied", "True");
}
break;
}
}
}
GetDataForAdapter.java
- 用于加载视频的适配器类
public class GetDataForAdapter {
private Context context;
private ContentResolver contentResolver;
private Cursor cursor;
public GetDataForAdapter(Context context) {
this.context = context;
contentResolver = context.getContentResolver();
}
public ArrayList<VideoModel> getVideoData() {
ArrayList<VideoModel> models = new ArrayList<>();
contentResolver = context.getContentResolver();
String[] projection = {MediaStore.Video.Media._ID, MediaStore.Video.Media.SIZE, MediaStore.Video.Media.DATA,
MediaStore.Video.Media.DISPLAY_NAME};
String[] selectionArgs = new String[]{"FbVideoDownload"};
cursor = contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection, null, null, MediaStore.Video.Media.DATE_TAKEN);
if (cursor != null) {
if (cursor.moveToFirst()) {
int id = cursor.getColumnIndex(MediaStore.Video.Media._ID);
int name = cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME);
int data = cursor.getColumnIndex(MediaStore.Video.Media.DATA);
do {
VideoModel model = new VideoModel();
model.setName(cursor.getString(name));
model.setUrl(cursor.getString(data));
model.setId(cursor.getInt(id));
Bitmap bitmap = MediaStore.Video.Thumbnails.getThumbnail(contentResolver, model.getId(), MediaStore.Images.Thumbnails.MINI_KIND,
null);
if (bitmap == null) {
bitmap = ThumbnailUtils.createVideoThumbnail(model.getUrl(), MediaStore.Images.Thumbnails.MINI_KIND);
}
model.setImageBitmap(bitmap);
models.add(model);
Log.e("video file name",
cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)));
} while (cursor.moveToNext());
} else {
Log.e("No media file", "Present in the selected directory");
}
Log.e("Cursor", cursor.toString());
} else {
Log.e("No data in Cursor", cursor.toString() + "");
}
cursor.close();
return models;
}
}
错误:
致命的例外:主要 流程:com.kisanthapa33.kisanthapa.facebookvideodownloader,PID:25448 java.lang.NullPointerException:尝试在空对象引用上调用虚方法'int android.content.Context.checkPermission(java.lang.String,int,int)' 在android.support.v4.content.ContextCompat.checkSelfPermission(ContextCompat.java:430) 在com.kisanthapa33.kisanthapa.facebookvideodownloader.fragments.PlayerFragment.setRecyclerView(PlayerFragment.java:117) 在com.kisanthapa33.kisanthapa.facebookvideodownloader.fragments.PlayerFragment.access $ 400(PlayerFragment.java:28) 在com.kisanthapa33.kisanthapa.facebookvideodownloader.fragments.PlayerFragment $ LoadVideoData.onPostExecute(PlayerFragment.java:92) 在com.kisanthapa33.kisanthapa.facebookvideodownloader.fragments.PlayerFragment $ LoadVideoData.onPostExecute(PlayerFragment.java:66) 在android.os.AsyncTask.finish(AsyncTask.java:651) 在android.os.AsyncTask.access $ 500(AsyncTask.java:180) 在android.os.AsyncTask $ InternalHandler.handleMessage(AsyncTask.java:668) 在android.os.Handler.dispatchMessage(Handler.java:102) 在android.os.Looper.loop(Looper.java:148) 在android.app.ActivityThread.main(ActivityThread.java:7325) at java.lang.reflect.Method.invoke(Native Method) 在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:1230) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
答案 0 :(得分:0)
我认为你正在使用一个非静态内部类,它保存对你的外部类的引用。因此,自内部类运行以来,外部类将保留在内存中。由于内部类保持对外部类的引用,因此它不适用于GC(Garbage Collection)
由android。
因此,这会导致内存泄漏情况。此内存泄漏情况进一步导致Out Of Memory Error
。
解决方案:简短的解决方案是LoadVideoData
静态。
private static LoadVideoData extends AsyncTask<Void, Void, ArrayList<VideoModel>> {
示例情况:
考虑doInBackground()
需要很长时间的情况,并且在达到onPostExecute()
回调之前活动可能已经完成。但是,在这个时间点,AsyncTask
对象尚未完成其操作,因此不是garbage collected
,并且它具有对finish活动的隐式引用,这会阻止此活动的记忆被释放,因此导致内存泄漏。