调用MediaScannerConnection 发生内存泄露的解决方法
调用MediaScannerConnection发起扫描时经常会发生内存泄露,例如:
E ActivityThread: Activity FolderListActivity has leaked ServiceConnection android.media.MediaScannerConnection@ec2a697 that was originally bound here
从网上看到一种解决方法,就是把MediaScannerConnection单独放在一个类中,而不是直接在Activity中创建。
参考网址:
http://www.dreamincode.net/forums/topic/289977-service-connection-leak-error/
1.有问题的代码:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.createfile); setupVariables(); checkState(); //Locates the SD Card's path to create a new directory //If the directory does not exist, then it is created path = new File(Environment.getExternalStorageDirectory(), dirName); if(!path.exists()){ path.mkdirs(); } //if you can read and write to storage if (wEnable && rEnable) { // Can Read and Write confirm.setonclickListener(this); // creates the library file save.setonclickListener(this); } } private void setupVariables() { //The Variables are stored here } private void checkState() { //Checks the state of the external storage. Not relevant to the problem } public void onclick(View v) { switch (v.getId()) { case R.id.bConfirm: name = tv.getText().toString(); if (name.equals("")) { error.setVisibility(View.VISIBLE); } else { error.setVisibility(View.INVISIBLE); save.setVisibility(View.VISIBLE); } break; case R.id.bSave: name = tv.getText().toString() + ".txt"; library = new File(path, name); //This is where the problem occurs MediaScannerConnection.scanFile(FileCreation.this, new String[]{library.toString()}, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { // TODO Auto-generated method stub runOnUiThread(new Runnable() { public void run() { Toast.makeText(FileCreation.this, "Media scan completed", Toast.LENGTH_SHORT).show(); } }); } }); finish(); break; } }
2.建议的代码:
You are creating a media scanner and running it and then calling finish(); while the service is still connected!
Create the following class :
import java.io.File; import android.content.Context; import android.media.MediaScannerConnection; import android.media.MediaScannerConnection.MediaScannerConnectionClient; import android.net.Uri; public class SingleMediaScanner implements MediaScannerConnectionClient { public interface ScanListener{ public void onScanFinish(); } private MediaScannerConnection mMs; private File mFile; private ScanListener listener; public SingleMediaScanner(Context context, File f,ScanListener l) { listener = l; mFile = f; mMs = new MediaScannerConnection(context, this); mMs.connect(); } @Override public void onMediaScannerConnected() { mMs.scanFile(mFile.getAbsolutePath(), null); } @Override public void onScanCompleted(String path, Uri uri) { mMs.disconnect(); listener.onScanFinish(); } }
Then in your code do the following:
new SingleMediaScanner(<context>,<File go here>,new ScanListener(){ public void onScanFinish() { finish(); Toast.makeText(FileCreation.this,"Media scan completed",Toast.LENGTH_SHORT).show(); });
3.修改后的代码:
package com.maclinCode; import java.io.File; import android.app.Activity; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.view.View.onclickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.maclinCode.SingleMediaScanner.ScanListener; public class FileCreation extends Activity implements onclickListener { EditText tv; TextView error; Button save, confirm; boolean wEnable, rEnable; String name; File path = null; File fileName = null; File library = null; private String state; private static final String dirName = "GameLibrary"; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.createfile); setupVariables(); checkState(); //Locates the SD Card's path to create a new directory //If the directory does not exist, then it is created path = new File(Environment.getExternalStorageDirectory(), dirName); if(!path.exists()){ path.mkdirs(); } //if you can read and write to storage if (wEnable && rEnable) { // Can Read and Write confirm.setonclickListener(this); // creates the library file save.setonclickListener(this); } } private void setupVariables() { confirm = (Button) findViewById(R.id.bConfirm); save = (Button) findViewById(R.id.bSave); tv = (EditText) findViewById(R.id.FileName); error = (TextView) findViewById(R.id.tvError); state = Environment.getExternalStorageState(); wEnable = rEnable = false; } private void checkState() { if (state.equals(Environment.MEDIA_MOUNTED)) { // Can Read and Write to storage wEnable = rEnable = true; } else{ Toast.makeText(this, "Cannot use External Storage", Toast.LENGTH_SHORT).show(); finish(); return; } } public void onclick(View v) { switch (v.getId()) { case R.id.bConfirm: name = tv.getText().toString(); if (name.equals("")) { error.setVisibility(View.VISIBLE); } else { error.setVisibility(View.INVISIBLE); save.setVisibility(View.VISIBLE); } break; case R.id.bSave: name = tv.getText().toString() + ".txt"; library = new File(path, name); // MediaScannerConnection.scanFile(FileCreation.this, new String[]{library.toString()}, // null, new MediaScannerConnection.OnScanCompletedListener() { // public void onScanCompleted(String path, Uri uri) { // // TODO Auto-generated method stub // runOnUiThread(new Runnable() { // public void run() { // Toast.makeText(FileCreation.this, // "Media scan completed", // Toast.LENGTH_SHORT).show(); // } // }); // } // }); // finish(); new SingleMediaScanner(FileCreation.this, library, new ScanListener(){ public void onScanFinish(){ finish(); Toast.makeText(FileCreation.this, "Media scan completed", Toast.LENGTH_SHORT).show(); } }); break; } } }