无法在Android

时间:2016-12-17 14:27:55

标签: java android sqlite

我有一个应用程序要将当前的SQLite数据库导出到设备的Internal storage Downloads文件夹。我收到以下错误。

  

java.io.FileNotFoundException:   / storage / emulated / 0 / Download / Pipe_Tally:打开失败:EACCES   (许可被拒绝)

我认为AndroidManifest.xml文件中包含的用于读取和写入存储的正确权限。 这是AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="com.example.bigdaddy.pipelinepipetally">

    <uses-feature android:name="android.hardware.camera2"
                  android:required="true"/>
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="18"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>

    <application
        android:allowBackup="true"
        android:debuggable="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="HardcodedDebugMode">
        <activity
            android:name=".MainActivity"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".TallyActivity2"
            android:windowSoftInputMode="adjustResize">
        </activity>
        <activity
            android:name=".JobAndDbActivity"
            android:windowSoftInputMode="adjustResize">
        </activity>
        <activity
            android:name=".ExistingTallyActivity"
            android:windowSoftInputMode="adjustResize">
        </activity>
        <activity android:name=".ImageToFullscreen"
            android:windowSoftInputMode="adjustResize">
        </activity>

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.bigdaddy.pipelinepipetally.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths">
            </meta-data>
        </provider>

    </application>
</manifest>

以下是我尝试用于为内部设备存储中的/Downloads/文件夹创建文件的方法:

public void backUpDatabase() {
    /* Open your local db as the input stream */
    DBHelper anotherDbHelper = null;
    try {
        try {
            anotherDbHelper = new DBHelper(ExistingTallyActivity.this);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    String path = null;
    if (anotherDbHelper != null) {
        path = String.valueOf(getApplicationContext().getDatabasePath(anotherDbHelper.getDatabaseName()));
        Log.i(TAG, "backUpDatabase: 1" +path);
    }
    File dbFile = null;
    if (path != null) {
        dbFile = new File(path);
        Log.i(TAG, "backUpDatabase: 2" + String.valueOf(dbFile));
    }
    FileInputStream fis = null;
    try {
        if (dbFile != null) {
            fis = new FileInputStream(dbFile);
            Log.i(TAG, "backUpDatabase: 3" + String.valueOf(dbFile));
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    String outFileName = (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()+ "/Pipe_Tally/");
    Log.i(TAG, "backUpDatabase: 4"+ outFileName);

    // Open the empty db as the output stream
    OutputStream outputStream = null;
    //FileOutputStream outputStream = null;
    try {
         outputStream = new FileOutputStream(outFileName);
        Log.i(TAG, "backUpDatabase: 5"+ outFileName);
        Log.i(TAG, "backUpDatabase: 6"+ String.valueOf(outputStream));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    // Transfer bytes from the input-file to the output-file
    byte[] buffer = new byte[1024];
    int length;
    try {
        if (fis != null) {
            while ((length = fis.read(buffer)) > 0) {
                try {
                    if (outputStream != null) {
                        outputStream.write(buffer, 0, length);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    //Close the streams
    try {
        if (outputStream != null) {
            outputStream.flush();
            outputStream.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        if (fis != null) {
            fis.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

以下是我用于在运行时检查正确权限的方法:

private boolean checkSdCardPermissions() {
    /* Checking here if we already have permissions*/
    if (ActivityCompat.checkSelfPermission(ExistingTallyActivity.this,
            Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
            && ActivityCompat.checkSelfPermission(ExistingTallyActivity.this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { /* Added this for Write External Storage permissions */
        /* Checking to see if we are equal to or at a higher version than Marshmallow */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            /* System default popup box here to ask for permissions. */
            ActivityCompat.requestPermissions(ExistingTallyActivity.this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    MY_PERMISSION_READ_EXTERNAL_STORAGE);
            /* Added this today for trying to prompt for writing external storage*/
            ActivityCompat.requestPermissions(ExistingTallyActivity.this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    MY_PERMISSION_WRITE_EXTERNAL_STORAGE);
        }
        return true;
    } else {
        return false;
    }
}

这是onOptionsItemSelected()方法,其中包含switch来处理菜单和选择的内容。 case:R.id.menu_save_and_export: 我正在检查checkSdCardPermissions()方法是否为真,然后调用backUpDatabase()方法。

 @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        switch (menuItem.getItemId()) {
            /*
            When Tally New Pipe is selected from the Menu, it sends the user to the TallyActivity
            page, all encapsulated in a runnable and passed to thread below.
            */
            case R.id.menu_new_pipe:
                class ToTallyActivityManager implements Runnable {
                    @Override
                    public void run() {
                        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        Intent intentToTallyActivity =
                                new Intent(ExistingTallyActivity.this, TallyActivity2.class);
                        startActivity(intentToTallyActivity); /* Heading to TallyActivity.*/
                    } /* run method ends here. */
                } /* Runnable ends here. */
                /* This thread takes care of the call to go to TallyActivity page from here.*/
                mThreadToTallyActivity = new Thread(new ToTallyActivityManager());
                mThreadToTallyActivity.start();
                break;
            /* When selected, sends the user to the MainActivity page. */
            case R.id.menu_to_main:
                Intent intentToMainActivity =
                        new Intent(ExistingTallyActivity.this, MainActivity.class);
                startActivity(intentToMainActivity); // Heading to MainActivity
                break;
            /* When chosen allows the option to save and export the current DB.*/
            case R.id.menu_save_and_export:

                if (checkSdCardPermissions()) {
                    try {
                        backUpDatabase();
                    } catch (/*IOException*/ SQLException e) {
                        e.printStackTrace();
                    }
                }

                break;
            /* When chosen from the menu, this kills the app completely. Has popup embedded.*/
            default:
                AlertHelperDialog.displayExitAlertDialog(ExistingTallyActivity.this);
        } /* switch/case ends here */

        return super.onOptionsItemSelected(menuItem);
    } /* onOptionsItemSelected method ends here. */

我非常感谢您解决此问题的任何帮助或建议。谢谢。

1 个答案:

答案 0 :(得分:0)

您在WRITE_EXTERNAL_STORAGE权限上设置了WRITE_EXTERNAL_STORAGE。如果您在使用SDK&gt;的手机上运行18该应用无法获得android:maxSdkVersion的许可。因此,我建议您删除<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 属性。阅读documentation

  

android:maxSdkVersion:应该为您的应用授予此权限的最高API级别。如果从某个API级别开始不再需要您的应用所需的权限,则设置此属性非常有用。

按如下方式更改,

compute angle for every point -- O(n)
sort point by angles -- O(n*lg(n))
for each pair -- O(n^2*lg(n))
    if (B.x > A.x) && (B.y > A.y)
        compute positions of C and D
        compute angles of C and D
        for C and D
            if there is a pair of points with same angles and same positions
                return true
return false