2013-04-26 25 views
2

這裏是我的onCreate,有時是造成異常的部分:併發修改例外,儘管等待完成

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_tilisting); 
    _context = getApplicationContext(); 
    SDName = Environment.getExternalStorageDirectory(); 
    //listview = (ListView)findViewById(R.id.TIlistview); 
    String TIdir = new File(SDName, "/TitaniumBackup/").toString(); 
    final ArrayList<String> apps = new ArrayList<String>(); 
    final StringBuffer done = new StringBuffer(); 
    Command command = new Command(0,"ls -a "+TIdir+"/*.properties") { 
     @Override 
     public void output(int arg0, String arg1) { 
      synchronized(apps) { 
       apps.add(arg1); 
       if (!done.toString().equals("")) { 
        done.append("done");//oh no 
       } 
      } 
     } 
    }; 
    try { 
     RootTools.getShell(true).add(command).waitForFinish(); 
     String attrLine = ""; 
     int ind; 
     backups = new ArrayList<TIBackup>(); 
     synchronized(apps) { 
      for (String app : apps) { 
       try { 
        TIBackup bkup = new TIBackup(app); 
        FileInputStream fstream = new FileInputStream(app); 
        BufferedReader atts = new BufferedReader(new InputStreamReader(fstream)); 
        while ((attrLine = atts.readLine()) != null) { 
         ind = attrLine.indexOf('='); 
         if (ind !=-1 && !attrLine.substring(0,1).equals("#")) 
         bkup.prop.put(attrLine.substring(0,ind), attrLine.substring(ind+1)); 
        } 
        backups.add(bkup); 
        atts.close(); 
       } catch (FileNotFoundException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
      done.append("done"); 
     } 
     setListAdapter(new StableArrayAdapter(this,backups)); 
    } catch (InterruptedException e) { 
     //TODO:errors 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (TimeoutException e) { 
     e.printStackTrace(); 
    } 

for (String app : apps) {導致異常,儘管waitforfinish()之前它。

這個更新後的代碼應該修復它,從輸出中添加數據並等待主代碼中的同步失敗的任何失敗者,但是如果你在上面// oh no行上設置斷點,它仍然會得到直到它嘗試在UI主代碼運行後添加項目。所以waitforfinish()不在等待?我如何防止這種競爭狀態?

我也嘗試了下面的代碼RootTask,但它似乎停在最後一條readline?

RootTask getProfile = new RootTask() { 
     @Override 
     public void onPostExecute(ArrayList<String> result) { 
      super.onPostExecute(result); 
      for (String r : result) { 
       System.out.println(r); 
      } 
     } 
    }; 
    getProfile.execute("ls /data/data/org.mozilla.firefox/files/mozilla/"); 

onPostExecute從不運行。

+1

請不要使用DataInputStream類讀取文本。這是多餘的和令人困惑的。請將其從您的示例中刪除,因爲此錯誤代碼被複制了很多。 – 2013-04-28 18:08:21

回答

1

這是部分地由在RootTools設計缺陷引起的。我認爲問題的癥結在於,您在shell上執行的操作比爲shell命令設置的缺省超時花費的時間更長。當超時發生時,它只是返回完成的命令,這是設計缺陷所在。

我提供了一個新的jar以及一些關於此的更多信息。我也不贊成waitForFinish(),因爲我同意它是一個糟糕的解決方案。

https://code.google.com/p/roottools/issues/detail?id=35

請讓我知道如果您有任何疑問或問題:)

1

Output()被稱爲waitForFinish()等待。執行命令執行的代碼中出現錯誤。

最有可能的:命令執行(?RootTools)在外殼運行命令,獲取了一堆輸出線,從等待通知調用線程,並它得到了作爲輸出的每一行命令,然後電話output()。我認爲它應該通知命令線程之後output()已經在命令對象上調用了所有的輸出行。

仍然可以在synchronized(<some common object>){}中包裝列表修改代碼並列出迭代代碼。

更新:

所以waitForFinish()沒有等待?我如何防止這種競爭狀態?

它確實在等待,但不是您的代碼。 Synchronized關鍵字只是確保output()Command對象在迭代apps集合時不會同時被調用。它不會安排兩個線程以特定的順序運行。

恕我直言,waitForFinish()是不是一個好的模式,使調用線程等待擊敗一個單獨的執行者的觀點。最好制定爲AsyncTask或接受每個Command對象的事件偵聽器。

只是一個粗略的例子,這個類:

public class RootTask extends AsyncTask<String,Void,List<String>> { 
    private boolean mSuccess; 

    public boolean isSuccess() { 
     return mSuccess; 
    } 

    @Override 
    protected List<String> doInBackground(String... strings) { 
     List<String> lines = new ArrayList<String>(); 

     try { 
      Process p = Runtime.getRuntime().exec("su"); 
      InputStream is = p.getInputStream(); 
      OutputStream os = p.getOutputStream(); 

      os.write((strings[0] + "\n").getBytes()); 

      BufferedReader rd = new BufferedReader(new InputStreamReader(is)); 

      String line; 

      while ((line = rd.readLine()) != null){ 
       lines.add(line); 
      } 

      mSuccess = true; 
      os.write(("exit\n").getBytes()); 
      p.destroy(); 

     } catch (IOException e) { 
      mSuccess = false; 
      e.printStackTrace(); 
     } 

     return lines; 
    } 
} 

可以用作:

RootTask listTask = new RootTask{ 
    @Override 
    public void onPostExecute(List<String> result){ 
     super.onPostExecute(); 
     apps.addAll(result); 
     //-- or process the results strings-- 
    } 
}; 

listTask.execute("ls -a "+TIdir+"/*.properties"); 
+0

好點,我記得在線程中使用同步,並沒有想到這是一個線程問題。即使添加了同步,我也遇到了另一個問題 - 請參閱更新的問題。 – NoBugs 2013-04-29 02:38:55

+0

謝謝,但是當我嘗試替換此代碼時,onResult不會被調用。我試過onPostExecute,它也沒有被調用。它似乎失敗了,它可以在doInBackground中'println(line)',但是在那個循環之後的斷點永遠不會被觸發。 – NoBugs 2013-06-25 06:08:26

+0

@NoBugs它的'onPostExecute()'我更新了代碼。你的問題表明進程的流出是阻塞的,'readLine()'一直在等待。你在運行什麼命令? – 2013-06-25 06:47:26