![](/img/trans.png)
[英]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.