是否可以在封闭范围内使用非final,如runnable(no。)

时间:2014-09-17 18:40:34

标签: java android performance

计划:

我创建了一点PreferenceActivity(不要讨厌我,我支持API 10及更高版本)并且需要通过我的应用显示本地存储数据的当前使用情况。我使用一个处理所有文件操作的专门类(一个非常大的类)来处理所有文件操作(由于某种原因,它被称为FileOperations.java)。在这个类文件中,有一个方法getSize(File file) {...}可以做到这一点。它使用这一小段代码获取文件(或文件夹)的大小:

public long getSize(File file) {
    long size = 0;

    if(file.isDirectory()) {
        for(File child : file.listFiles()) {
            size += getSize(child);
        }
    }
    size = file.length();

    return size;
}

一般的想法是在后台Thread中使用它,所以即使是最轻微的一点也不会阻塞UI。 (我对应用程序的滞后感到非常恼火,并且每天都受到它们的影响)

问题:

这很好用。但是,只要我清除文件夹,应用程序就会将其数据存储在使用此美容中:

private void purgeLocalStorage() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();
            Log.i("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", "Started to run");
            final String         directory = context.getResources().getString(R.string.app_name);
            final String         usedData  = context.getResources().getString(R.string.ActivityPrefsLocalStorage_usedData);
            final File           file      = new File(Environment.getExternalStorageDirectory()+"/"+directory);
            final FileOperations FO        = new FileOperations(context);
            Log.i("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", "deleting folder: "+file);
            if(FO.delete(file)) {
                Log.i("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", file+" deleted");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, R.string.ActivityPrefsLocalStorage_deleteSucces, Toast.LENGTH_SHORT).show();
                        setTotalLocalDataTexts(usedData+" "+context.getResources().getString(R.string.pref_totalData_default), "");
                        getUsedStorage();
                    }
                });
            } else {
                Log.e("ActivityPrefsLocalStorage.purgeLocalStorage.Thread.Runnable.run", "could not delete "+file);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, R.string.ActivityPrefsLocalStorage_deleteError, Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }
    }).start();
}
事情袭击了粉丝......

请注意,问题是我的读取文件夹大小的方法在前一种方法调用时不希望正常工作。

这是一个片段:

private void getUsedStorage() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "Started to run");
            final String         directory = context.getResources().getString(R.string.app_name);
            final String         usedData  = context.getResources().getString(R.string.ActivityPrefsLocalStorage_usedData);
            final File           file      = new File(Environment.getExternalStorageDirectory()+"/"+directory);
            final FileOperations FO        = new FileOperations(context);
            final DataUsage      DU        = new DataUsage(context);
            Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "Checking filesize of folder: "+file);
                  long           fileSize  = FO.getSize(file);
                  String         usedUnits = DU.getUnit(fileSize, true, false, false);
                  String         usedBytes = DU.getUnit(fileSize, true, true, true);
            Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "filesize of "+file+": "+usedUnits);
            setTotalLocalDataTexts(usedData+" "+usedUnits, usedBytes);
        }
    }).start();
}

但是,一个快速简便的解决方法是将它放在UI线程上,如下所示:

...blabla code you already read above.
                  long           fileSize  = FO.getSize(file);
                  String         usedUnits = DU.getUnit(fileSize, true, false, false);
                  String         usedBytes = DU.getUnit(fileSize, true, true, true);
            Log.i("ActivityPrefsLocalStorage.getUsedStorage.Thread.Runnable.run", "filesize of "+file+": "+usedUnits);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setTotalLocalDataTexts(usedData+" "+usedUnits, usedBytes);
                }
            });
        }
    }).start();
}

这就是它开始变得有趣的地方。我不能在new Runnable()内使用非决赛,而我不能让它们成为最终版,因为我希望值更新而不会停留在例如。 32MiB(虽然刚被清除)。

可能的修复:

我应该做好并且只是使用决赛。用户将理解他们需要手动刷新页面。 (哦不...)

雇用......呃。扩展AsyncTask<Void, Void, Void>以完成工作。

<小时/>

我的理想修复:

有人给我一个很棒的免费代码片段,可以完成所有的魔法。不,严肃地说,除了我的可能修复列表之外,我真的很感激。必须有一些方法来传递new Runnable()变量而不创建类并实现整个Universe?或者这就是我想要实现的新事物?

TL; DR:
一旦我从getUsedStorage()内拨打new Runnable(),就会出错。此函数也是Runnable中的后台任务,但使用设置它的私有void函数更新UI。它只将变量传递给此函数。 然后事情从句柄(r)飞出。

编辑:语法。
Edit2:这里还要注意一个非常有趣的事情,我在另一个PreferenceActivity中使用了类似的东西,而且那个有效。 (但按下调用另一个private something functionName() {new Thread(new Runnable() {public void run() {...});}的按钮时,更新

2 个答案:

答案 0 :(得分:0)

有几种方法可以在Runnable或其他封闭类中使用非决赛。

第一种是将变量更改为封闭类的成员。这将允许您使用Runnable中的变量。一个例子如下:

public class Foo {
    private long time;

    public void run() {
        time = System.currentTimeMillis();

        new Thread(new Runnable() {
            @Override
            public void run() {
                time += 1;
                System.out.println("Our current time is: " + time);
            }
        });
    }
}

另一个选项,也就是说很糟糕,就是使用长度为1的最终数组。其中一个例子如下:

public class Foo {
    public void run() {
        final long[] time = { System.currentTimeMillis() };

        new Thread(new Runnable() {
            @Override
            public void run() {
                time[0] += 1;
                System.out.println("Our current time is: " + time[0]);
            }
        });
    }
}

答案 1 :(得分:0)

正如reddit.com/r/androiddev上的gonemad16指出的那样,我的问题与决赛与非决赛没有任何关系。这不是我获得旧价值的原因。我的所有变量都被赋予一个值,发送到setTotalLocalDataTexts然后超出范围......没有更新它们的值..所以它们没有任何伤害是最终的,没有任何好处,他们是非最终的......

这是getSize()

中的一个问题

我认为我使用if file.isDirectory(){...}时有一个正确的循环。它创建了一个目录树,并使用它找到的子节点自行执行。扫描完所有项目后,该值将返回调用它的函数。

当我还在ui线程上运行我的所有代码时,这对我来说很好。一切都很慢。但它奏效了。

但是,我忘了我删除了一个非常关键的...}其他{...

我相信我删除了那个,因为它在某个时候导致了堆栈溢出,所以我删除了它,我想忘了把它放回去......

在这里,我认为我的第一个问题不会是一个愚蠢的问题......