【问题标题】:Android not responding while trying to read from text or doc fileAndroid 在尝试读取文本或 doc 文件时没有响应
【发布时间】:2022-10-13 05:11:00
【问题描述】:

这与my previous question在我更改 readFile 并使其从 URI 中读取运行在 android 11 及更高版本的设备后,我在尝试读取文件时遇到 ANR 错误

显示错误的 gif

这是我的完整代码

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_CODE_DOC = 1;

    private static final String TAG = "MainActivity";

    private ActivityMainBinding activityMainBinding = null;

    private File file;
    private Uri selectedFileURI;
    BufferedReader bufferedReader;
    InputStream inputStream;
    FileReader fileReader;

    @Override
    protected void onDestroy() {
        super.onDestroy();
        activityMainBinding = null;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());

        setContentView(activityMainBinding.getRoot());


    }

    @Override
    protected void onStart() {
        super.onStart();
        activityMainBinding.textView.setMovementMethod(new ScrollingMovementMethod());
        activityMainBinding.browseButton.setOnClickListener(view -> {


            browseDocuments();
        });

        activityMainBinding.read.setOnClickListener(view -> {
            if (TextUtils.isEmpty(activityMainBinding.editTextPath.getText())) {
                activityMainBinding.editTextPath.setError("The file path cannot be empty");
            } else {
                readFile();

            }
        });

        activityMainBinding.clear.setOnClickListener(view -> activityMainBinding.textView.setText(null));
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_DOC && resultCode == Activity.RESULT_OK) {

            try {

                if (data != null) {

                    selectedFileURI = data.getData();
                    file = new File(selectedFileURI.getPath());
                    activityMainBinding.editTextPath.setText(file.getAbsolutePath());
                    Log.d(TAG, "onActivityResult: " + file.getAbsolutePath());

                } else {
                    Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
                }

                String mimeType = getContentResolver().getType(selectedFileURI);
                Log.i("Type of file", mimeType + "");
            } catch (Exception exception) {

                if (exception.getMessage() != null) {

                    Log.e("test Exception", exception.getMessage());

                } else if (exception.getCause() != null) {
                    Log.e("test Exception", Objects.requireNonNull(exception.getCause()).toString());
                }


            }
        }

    }

    public String getPath(Uri uri) {
        String[] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
        if (cursor == null) return null;
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String s = cursor.getString(column_index);
        cursor.close();
        return s;
    }


    private void readFile() {
        try {

            StringBuilder sb = new StringBuilder();
            String line;

            if (SDK_INT >= Build.VERSION_CODES.R) {

                inputStream = getContentResolver().openInputStream(selectedFileURI);
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

            } else {
                fileReader = new FileReader(file);
                bufferedReader = new BufferedReader(fileReader);
            }
            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line).append("\n");
            }

            activityMainBinding.textView.setText(sb.toString());

            if(inputStream != null) {
                inputStream.close();
            }else if(bufferedReader != null) {
                bufferedReader.close();
            }else if(fileReader != null) {
            fileReader.close();
            }

        } catch (IOException e) {
            Log.e("IOException", e.getMessage());
            Log.e("IOException2", e.getCause() + "");
            Log.e("IOException3", "exception", e);
            Toast.makeText(MainActivity.this, "Cannot read this file", Toast.LENGTH_LONG).show();

        }

    }


    private boolean checkPermission() {
        if (SDK_INT >= Build.VERSION_CODES.R) {
            return Environment.isExternalStorageManager();
        } else {
            int result = ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE);
            int result1 = ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE);
            return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
        }
    }

    private void requestPermission() {
        if (SDK_INT >= Build.VERSION_CODES.R) {
            try {
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                intent.addCategory("android.intent.category.DEFAULT");
                intent.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
                startActivityForResult(intent, 1);
            } catch (Exception e) {
                Intent intent = new Intent();
                intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                startActivityForResult(intent, 1);
            }
        } else {

            ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE,
                    WRITE_EXTERNAL_STORAGE}, 1);
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_CODE_DOC:
                if (grantResults.length > 0) {
                    boolean READ_EXTERNAL_STORAGE = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    boolean WRITE_EXTERNAL_STORAGE = grantResults[1] == PackageManager.PERMISSION_GRANTED;

                    if (READ_EXTERNAL_STORAGE && WRITE_EXTERNAL_STORAGE) {
                        readFile();


                    } else {
                        Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
                    }
                }
                break;
        }
    }

    private void browseDocuments() {

        if (!checkPermission()) {
            requestPermission();
        } else {


            String[] mimeTypes =
                    {"text/plain", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                            "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                            "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                            "textView/plain",
                            "application/pdf"};

            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            setResult(Activity.RESULT_OK);

            intent.setType("*/*");
            intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);


            startActivityForResult(Intent.createChooser(intent, "ChooseFile"), REQUEST_CODE_DOC);
        }
    }

}

【问题讨论】:

  • 你为什么使用SDK_INT >= Build.VERSION_CODES.R?为了帮助我们理解问题,您测试的是哪个版本的 Android?
  • file = new File(selectedFileURI.getPath()) 这是无稽之谈,因为 getPath() 不提供文件系统路径。在您的图片中可以看到错误的不可能路径。
  • @pedro-oliveira你为什么使用 SDK_INT >= Build.VERSION_CODES.R?这是因为从 android 11 开始在存储中发生的更改请检查此 answerthis 我在 android 11 及更高版本上测试
  • @blackapps 如果在 android <= 10 上运行这个应用程序,这很有用,第二行将获得绝对路径,无论如何我没有从这个路径读取文件,这只是在 textView 中设置的
  • 即使我使用 rxjava 我也有同样的问题

标签: java android inputstream filereader android-anr-dialog


【解决方案1】:

主要问题是由阻塞主线程引起的。 您正在从记忆中阅读,这通常需要一些时间。您在主线程上执行此操作,该线程用于所有 UI 操作(布局、检测输入等)。当您占用它时,不会发生渲染或输入检测。这就是您看到 ANR 警告的原因。

要解决您的问题,您需要将您的工作放到后台线程中。有几种方法可以做到这一点。 This 是一个很好的起点。还有that one,如果您经常运行任务。

现在,为了给您一个快速解决问题的方法,您可以创建一个类来完成您的工作:

public class ReadFile extends Worker
{
    private File file;
    private BufferedReader bufferedReader;
    private InputStream inputStream;
    private FileReader fileReader;
    public ReadFile(@NonNull Context context, @NonNull WorkerParameters workerParams)
    {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork()
    {
        try
        {
            StringBuilder sb = new StringBuilder();
            String line;

            if (SDK_INT >= Build.VERSION_CODES.R)
            {
                Uri uri = Uri.parse(getInputData().getString("URI"));
                inputStream = getApplicationContext().getContentResolver().openInputStream(uri);
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            }
            else
            {
                fileReader = new FileReader(file);
                bufferedReader = new BufferedReader(fileReader);
            }
            while ((line = bufferedReader.readLine()) != null)
            {
                sb.append(line).append("
");
            }

            if (inputStream != null)
            {
                inputStream.close();
            }
            else if (bufferedReader != null)
            {
                bufferedReader.close();
            }
            else if (fileReader != null)
            {
                fileReader.close();
            }
            Data myData = new Data.Builder()
                    .putString("text", sb.toString())
                    .build();
            return Result.success(myData);
        }
        catch (IOException e)
        {
            Log.e("IOException", e.getMessage());
            Log.e("IOException2", e.getCause() + "");
            Log.e("IOException3", "exception", e);
            return Result.failure();
        }
    }
}

如果您正在使用活动的内部类,只需确保您没有使用 UI 线程中的任何字段,您也在工作人员内部使用这些字段。如果这样做,则需要同步它们。这就是我在示例中使用输入和输出数据的原因。

最后在您的活动电话中:

Data myData = new Data.Builder()
        .putString("URI", selectedFileURI.toString())
        .build();
OneTimeWorkRequest readFile = new OneTimeWorkRequest.Builder(ReadFile.class).setInputData(myData).build();
WorkManager.getInstance(getContext()).enqueue(readFile);
WorkManager.getInstance(getContext()).getWorkInfoByIdLiveData(readFile.getId()).observe(this, info ->
{
    String myResult = info.getOutputData().getString("text");
    activityMainBinding.textView.setText(myResult);
});

【讨论】:

    猜你喜欢
    • 2020-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多