如何在运行后台线程时修复android中的内存不足错误

时间:2018-03-16 05:44:39

标签: android android-asynctask out-of-memory

我创建了一个列出视频并播放它们的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)

1 个答案:

答案 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活动的隐式引用,这会阻止此活动的记忆被释放,因此导致内存泄漏。