[英]Cannot refer to the non-final local variable display defined in an enclosing scope
[英]Is it possible to use a non-final in an enclosing scope like a runnable (no.)
我创建了一个PreferenceActivity
(不要恨我,我支持API 10及更高版本),并且需要显示我的应用程序对本地存储数据的当前使用情况。 我使用处理所有文件操作的专用类( FileOperations.java
,这是一个很大的类)来完成此操作(由于某种原因,它称为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()
使用非final类型, 也不能使其成为final类型,因为我想更新值并且不要停留在例如。 32MiB(虽然它刚刚被清除)。
我应该动手,只用决赛。 用户将了解他们需要手动刷新页面。 (不好了...)
雇用...嗯。 扩展AsyncTask<Void, Void, Void>
来完成工作。
有人免费给我提供了很棒的代码片段,它可以发挥所有魔力。 不,虽然说真的,除了可能的修复程序之外,我真的很感激。 必须有某种方法可以将new Runnable()
传递给变量,而无需创建类和实现整个Universe? 还是我要实现的目标真的是新事物?
TL; DR:
当我new Runnable()
调用getUsedStorage()
,事情就出错了。 此函数也是Runnable内部的后台任务,但是使用设置它的私有void函数更新UI。 它仅将变量传递给此函数。 然后东西从手柄上飞走。
编辑: 语法。
Edit2: 在这里还要注意的一件非常有趣的事情,我在另一个PreferenceActivity中使用了类似的东西,并且这个作品有用。 (但是按下一个调用另一个private something functionName() {new Thread(new Runnable() {public void run() {...});}
的按钮并不会更新private something functionName() {new Thread(new Runnable() {public void run() {...});}
)
有几种方法可以在Runnable或其他封闭的类中使用非final。
首先是将变量更改为封闭类的成员。 这将允许您使用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]);
}
});
}
}
正如reddit.com/r/androiddev上的godmad16所指出的那样,我的问题与最终版和非最终版无关。 那不是我获得旧价值的原因。 我所有的变量都有一个值,发送到setTotalLocalDataTexts,然后超出范围...什么都没有更新它们的值..因此,将它们定为无害,将其定为非定益也无济于事...
这是getSize()中的一个问题
我以为我在使用if file.isDirectory(){...}时有正确的循环。 它创建了一个目录树,并使用找到的子目录执行自己。 扫描完所有项目后,该值返回到调用它的函数。
当我仍在ui线程上运行所有代码时,这对我来说工作得很好。 一切都很缓慢。 但这行得通。
但是,我忘了我删除了一个非常关键的...}其他{...
我相信我删除了那个,因为它在某个时候引起了堆栈溢出,所以我删除了它,我猜忘了放回去...
在这里,我在想我的第一个SO问题不会是一个讨厌的问题...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.