2014-05-12 3 views
3

일부 shell commands을 실행하고 TextView에서 결과를 얻고 싶습니다. 명령에 ping 또는 logcat과 같은 연속 출력이있을 수 있습니다. 또한 TextView은 명령 출력이 실시간으로 추가 될 때 자동으로 스크롤해야합니다. 는이를 위해, 나는 이런 짓을했는지 : 이것은 잘 작동하지만셸 명령을 실행하고 TextView에서 출력을 얻으십시오.

package com.example.rootapp; 

import java.io.DataOutputStream; 
import java.io.InputStream; 

import android.app.Activity; 
import android.os.Bundle; 
import android.text.method.ScrollingMovementMethod; 
import android.widget.TextView; 

public class MainActivity extends Activity { 
    TextView tv; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     String[] cmdArray={"logcat -b radio"}; 
     try { 
      runAsRoot(cmdArray); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    public void runAsRoot(String[] cmds) throws Exception { 
     tv=(TextView)findViewById(R.id.cmdOp); 
     tv.setMovementMethod(new ScrollingMovementMethod()); 
     Process p = Runtime.getRuntime().exec("su"); 
     DataOutputStream os = new DataOutputStream(p.getOutputStream()); 
     InputStream is = p.getInputStream(); 
     for (String tmpCmd : cmds) { 
      os.writeBytes(tmpCmd+"\n"); 
      int readed = 0; 
      byte[] buff = new byte[4096]; 
      boolean cmdRequiresAnOutput = true; 
      if (cmdRequiresAnOutput) { 
       while(is.available() <= 0) { 
        try { Thread.sleep(5000); } catch(Exception ex) {} 
       } 

       while(is.available() > 0) { 
        readed = is.read(buff); 
        if (readed <= 0) break; 
        String seg = new String(buff,0,readed); 
        tv.append(seg); 
       } 
      } 
     }   
    } 
} 

이 지속적으로 TextView를 업데이트하지 않습니다. 당신이 볼 수 있듯이, 나는 루트 사용자로서 라디오 logcat을 실행 중이며, 출력은 지속적으로 생성된다 (이미 터미널 에뮬레이터와 adb 쉘에서 확인 됨). 하지만 제 경우에는 출력이 계속 추가되지 않습니다. 그것은 100 라인이 약간 지나면 멈 춥니 다.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    tools:context=".MainActivity" > 

    <ScrollView 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <TextView 
     android:id="@+id/cmdOp" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:gravity="bottom" 
     android:text="@string/hello_world" /> 
</ScrollView> 

</RelativeLayout> 

출력은 텍스트 뷰 스크롤 유지해야합니다 여기 내 레이아웃입니다. 적어도 이것은 내가 기대하는 것입니다.이 문제를 해결할 수있는 방법은 없습니까?

답변

8

당신은 다음과 같이 텍스트로 명령 및 표시 명령 출력을 실행할 수 있습니다

public class MainActivity extends Activity { 

    TextView tv; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     tv=(TextView)findViewById(R.id.cmdOp); 
     tv.setText("Output :"+"\n"+runAsRoot()); 
    } 

    public String runAsRoot() { 

     try { 
      // Executes the command. 
      Process process = Runtime.getRuntime().exec("ls -l"); 

      // Reads stdout. 
      // NOTE: You can write to stdin of the command using 
      //  process.getOutputStream(). 
      BufferedReader reader = new BufferedReader(
        new InputStreamReader(process.getInputStream())); 

      int read; 
      char[] buffer = new char[4096]; 
      StringBuffer output = new StringBuffer(); 
      while ((read = reader.read(buffer)) > 0) { 
       output.append(buffer, 0, read); 
      } 
      reader.close(); 

      // Waits for the command to finish. 
      process.waitFor(); 

      return output.toString(); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } catch (InterruptedException e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

을 : 장치가 다른 IS 뿌리하면 예외를 준 경우 "SU"명령은 실행됩니다.

+0

감사합니다. 감사합니다. 유용 할 경우 안녕하세요. –

1

나는 문제는 당신이 출력을 읽기 시작하고 프로그램이 시작될 때 스트림의 끝 부분에 도달 할 때까지 기다리는 것이 로그가 생성되는 속도보다 빠르기 때문이라고 생각한다. 따라서 잠시 동안 다시 기다렸다가 버퍼를 다시 읽어야합니다. 다음 코드는 나를 위해 작동합니다. ArrayAdapter + TextView 대신 ListView를 사용합니다. m_bTerminate를 true로 설정하면 다음 번에 스레드가 입력 스트림의 끝에 도달합니다.

Process p = Runtime.getRuntime().exec(m_command); 
InputStream is = p.getInputStream(); 

while(!m_bTerminate) { 
    while(is.available() <= 0) 
    { 
     try{ Thread.sleep(1000, 0); } catch(Exception e) {m_log.e(e);} 
    } 

    byte[] buff = new byte[4096]; 
    int read = is.read(buff); 
    if(0 < read) { 
     m_List.add(new String(buff, 0, read)); 
     m_handler.sendEmptyMessage(Handler.MSG_RADIO_LOG_NOTIFY_DATASET_CHANGED); 
     //if we call notify datasetchanged directly it raises 
     //android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views 
     //m_Adapter.notifyDataSetChanged(); 
    } 
} 

m_log.p(TAG, Log.DEBUG, "Command executed. Destroying thread."); 
is.close(); 
p.destroy();