在外部 Android 存储中保存文件时出错

Error while saving files in External Android storage

当我打开activity时,我请求目录权限。一旦获得许可,我就写下文件的名称和内容,然后按下保存按钮。保存文件前会有一个确认对话框。我在那里选择是,然后出现以下错误。

2019-07-17 04:29:31.063 17879-17879/com.halimlab.catatanharian E/WindowManager: android.view.WindowLeaked: Activity com.halimlab.catatanharian.InsertAndViewActivity has leaked window DecorView@56fdc15[InsertAndViewActivity] that was originally added here
    at android.view.ViewRootImpl.<init>(ViewRootImpl.java:538)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)
    at android.app.Dialog.show(Dialog.java:329)
    at androidx.appcompat.app.AlertDialog$Builder.show(AlertDialog.java:1007)
    at com.halimlab.catatanharian.InsertAndViewActivity.konfirmasiSave(InsertAndViewActivity.java:191)
    at com.halimlab.catatanharian.InsertAndViewActivity.onBackPressed(InsertAndViewActivity.java:197)
    at com.halimlab.catatanharian.InsertAndViewActivity.buatDanUbah(InsertAndViewActivity.java:177)
    at com.halimlab.catatanharian.InsertAndViewActivity.onClick(InsertAndViewActivity.java:188)
    at androidx.appcompat.app.AlertController$ButtonHandler.handleMessage(AlertController.java:167)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6739)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:495)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:859)

这是我的代码。

public class InsertAndViewActivity extends AppCompatActivity implements View.OnClickListener {

    public static final int REQUEST_CODE_STORAGE = 100;
    int eventID = 0;
    EditText edtFileName, edtContent;
    Button btnSimpan;
    boolean isEditable = false;
    String fileName = "";
    String tempCatatan = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_insert_and_view);

        // button back
        ActionBar menu = getSupportActionBar();
        menu.setDisplayShowHomeEnabled(true);
        menu.setDisplayHomeAsUpEnabled(true);

        // input
        edtFileName = findViewById(R.id.editFilename);
        edtContent = findViewById(R.id.editContent);

        // button
        btnSimpan = findViewById(R.id.btnSimpan);
        btnSimpan.setOnClickListener(this);

        Bundle extras = getIntent().getExtras();
        if (extras != null) {
            fileName = extras.getString("filename");
            edtFileName.setText(fileName);
            getSupportActionBar().setTitle("Ubah Catatan");
        } else {
            getSupportActionBar().setTitle("Tambah Catatan");
        }

        eventID = 1;
        if (Build.VERSION.SDK_INT >= 23) {
            if (periksaIzin()) {
                bacaFile();
            }
        } else {
            bacaFile();
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btnSimpan :
                eventID = 2;
                if (!tempCatatan.equals(edtContent.getText().toString())) {
                    if (Build.VERSION.SDK_INT >= 23) {
                        konfirmasiSave();
                    }
                } else {
                    konfirmasiSave();
                }
                break;
        }
    }

    public boolean periksaIzin() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == getPackageManager().PERMISSION_GRANTED) {
                return true;
            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_STORAGE);
                return false;
            }
        } else {
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case  REQUEST_CODE_STORAGE :
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (eventID == 1) {
                        bacaFile();
                    } else {
                        konfirmasiSave();
                    }
                }

                break;
        }
    }

    void bacaFile() {
        String path = Environment.getExternalStorageDirectory().toString() + "/halimlab.catatan";
        File file = new File(path, edtFileName.getText().toString());
        if (file.exists()) {
            StringBuilder text = new StringBuilder();
            try {
                BufferedReader br = new BufferedReader(new FileReader(file));
                String line = br.readLine();
                while (line != null) {
                    text.append(line);
                    line = br.readLine();
                }
                br.close();
            } catch (Exception e) {
                System.out.println("ERROR" + e.getMessage());
            }
            tempCatatan = text.toString();
            edtContent.setText(text.toString());
        }
    }

    void buatDanUbah() {
        String state = Environment.getExternalStorageState();
        if (!Environment.MEDIA_MOUNTED.equals(state)) {
            return;
        }
        String path = Environment.getExternalStorageDirectory().toString() + "/halimlab.catatan";
        File parent = new File(path);
        if (parent.exists()) {
            File file = new File(path, edtFileName.getText().toString());
            FileOutputStream outputStream = null;
            try {
                file.createNewFile();
                outputStream = new FileOutputStream(file);
                OutputStreamWriter streamWriter = new OutputStreamWriter(outputStream);
                streamWriter.append(edtContent.getText());
                streamWriter.flush();
                streamWriter.close();
                streamWriter.flush();
                streamWriter.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            parent.mkdir();
            File file = new File(path, edtFileName.getText().toString());
            FileOutputStream outputStream = null;
            try {
                file.createNewFile();
                outputStream = new FileOutputStream(file, false);
                outputStream.write(edtContent.getText().toString().getBytes());
                outputStream.flush();
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        onBackPressed();
    }

    void konfirmasiSave () {
        new AlertDialog.Builder(this)
                .setTitle("Simpan Catatan")
                .setMessage("Apakah anda akan menyimpan catatan ini ?")
                .setIcon(android.R.drawable.ic_dialog_alert)
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        buatDanUbah();
                    }
                })
                .setNegativeButton(android.R.string.no, null).show();
    }

    @Override
    public void onBackPressed() {
        if (!tempCatatan.equals(edtContent.getText().toString())) {
            konfirmasiSave();
        }

        super.onBackPressed();
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (item.getItemId() == R.id.home) {
            onBackPressed();
        }
        return super.onOptionsItemSelected(item);
    }
}

我在 AndroidManifest.xml 中拥有必要的权限。

<uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE"/>

您需要像下面这样修改 onBackPressed 函数。

@Override
public void onBackPressed() {
    if (!tempCatatan.equals(edtContent.getText().toString()))
        konfirmasiSave();
    else super.onBackPressed(); // Do that in the else part.
}

因为在 konfirmasiSave 函数中您打开了一个未关闭的对话框或正在对其执行任何操作,因此您正在调用 super.onBackPressed 试图 return 返回到之前的 activity 并因此导致 window 泄漏错误。

并在退出前处理 tempCatatan 变量的值,以便您的 onBackPressed 函数按预期执行。