سؤال

I would like to display a log file that I save in the data directory of my application ("/data/data/mypackage/files/log.txt").

I need it to debug my application without eclipse.

At the moment, I display the content file in a textview, and when I want to refresh the view I click on a button that reload my textview. It is ugly but it works.

What I would like is an automatic refresh of my textview when my log file has been modified as in eclipse logcat.

So how can I do it ?

Here is what I have done :


My activity :


public class LogActivity extends Activity {

  private TextView textView;
  private String   fileName = "/data/data/my.package.app/files/log.txt";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.log);
    Typeface tf = Typeface.createFromAsset(getAssets(), "CONSOLA.TTF");
    textView = (TextView) findViewById(R.id.textView1);
    textView.setTypeface(tf);
    setTextView();

    new FileObserver(fileName) {
        @Override
        public void onEvent(int event, String path) {
            Log.e("File", "EVENT");
            if (event == FileObserver.MODIFY) {
                Log.e("File", "MODIFY");
                setTextView();
            }
        }
    }.startWatching();
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.log_activity, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_reload:
            setTextView();
            break;
        case R.id.menu_empty:
            File file = new File(fileName);
            file.delete();
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            setTextView();
            break;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
  }

  private void setTextView() {
    try {
        FileReader fileReader = new FileReader(new File(fileName));
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        String line = "";
        StringBuilder builder = new StringBuilder("");
        while ((line = bufferedReader.readLine()) != null) {
            builder.insert(0, line + "\n");
        }
        textView.setText(builder.toString());
        bufferedReader.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
  }
}

My layout


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<ScrollView
android:id="@+id/SCROLLER_ID"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:fillViewport="true">
    <TextView
        android:id="@+id/textView1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" 
        />
    </ScrollView>

</LinearLayout>

My menu :


 <menu xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:id="@+id/menu_reload"
    android:title="Recharger"
    android:orderInCategory="100"
    android:showAsAction="always" />
  <item android:id="@+id/menu_empty"
    android:title="Vider"
    android:orderInCategory="100"
    android:showAsAction="always" />
</menu>
  • When I modify my log file (through an Android Service), I have sometimes the event that the file has been modified but not each time. why ? (if I reload manually the view through the menu, then I see that the log file has been updated).

  • The call to setTextView() inside the FileObserver is never called ?

هل كانت مفيدة؟

المحلول

Finally here is my solution (even if the Arkadiusz's one is nice).

I have implemented a Service that is observing the file and I've registered it in my LogActivity :


The Service :


public class LogService extends Service {

public static final String BROADCAST_FILE_LOG_UPDATE = "my.package.app.log.update";
private String             fileName                  = "/data/data/my.package.app/files/log.txt";

/**
 * The intent thanks to which is forwarded the alarm to display.
 */
private Intent             logIntent;

private FileObserver       fileObserver;

@Override
public void onCreate() {
    Log.e("LogService", "oncreate");
    logIntent = new Intent(BROADCAST_FILE_LOG_UPDATE);
    fileObserver = new FileObserver(fileName) {
        @Override
        public void onEvent(int event, String path) {
            if (event == FileObserver.MODIFY) {
                broadcastLogUpdate();
            }
        }
    };
}

private void broadcastLogUpdate() {
    sendBroadcast(logIntent);
}

@Override
public void onStart(Intent intent, int startid) {
    fileObserver.startWatching();
}

@Override
public void onDestroy() {
    fileObserver.stopWatching();
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}
}

The LogActivity :


public class LogActivity extends Activity {

private TextView          textView;
private String            fileName          = "/data/data/my.package.app/files/log.txt";

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
                                                @Override
                                                public void onReceive(Context context, Intent intent) {
                                                    setTextView();
                                                }
                                            };
private Intent            serviceIntent;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    serviceIntent = new Intent(getApplicationContext(), LogService.class);
    setContentView(R.layout.log);
    Typeface tf = Typeface.createFromAsset(getAssets(), "CONSOLA.TTF");
    textView = (TextView) findViewById(R.id.textView1);
    textView.setTypeface(tf);
    setTextView();
}

@Override
protected void onResume() {
    super.onResume();
    try {
        startService(serviceIntent);
        registerReceiver(broadcastReceiver, new IntentFilter(LogService.BROADCAST_FILE_LOG_UPDATE));
    } catch (IllegalArgumentException e) {}
}

@Override
protected void onStop() {
    super.onStop();
    try {
        unregisterReceiver(broadcastReceiver);
    } catch (IllegalArgumentException e) {}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.log_activity, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_reload:
            Toast.makeText(getApplicationContext(), "reload", Toast.LENGTH_LONG).show();
            setTextView();
            break;
        case R.id.menu_empty:
            new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert)
                    .setTitle("Erase log file ?").setMessage("Sure ?")
                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            File file = new File(fileName);
                            file.delete();
                            try {
                                file.createNewFile();
                                unregisterReceiver(broadcastReceiver);
                                stopService(serviceIntent);
                                startService(serviceIntent);
                                registerReceiver(broadcastReceiver, new IntentFilter(
                                        LogService.BROADCAST_FILE_LOG_UPDATE));

                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            setTextView();
                        }

                    }).setNegativeButton("No", null).show();
            break;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}

private void setTextView() {
    try {
        FileReader fileReader = new FileReader(new File(fileName));
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        String line = "";
        StringBuilder builder = new StringBuilder("");
        while ((line = bufferedReader.readLine()) != null) {
            builder.insert(0, line + "\n");
        }
        textView.setText(builder.toString());
        bufferedReader.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

Of course, don't forget to add the new service in the manifest.


The manifest :


    <service android:name=".LogService" />

It works very well.

I hope it would be useful for somebody else.

نصائح أخرى

I have been strugling with the same task lately (not logtcat though) and I ended up using this library: http://www.informit.com/guides/content.aspx?g=java&seqNum=226

It uses RandomFileAccess class to get changes - by comparing current & last filepointer positions.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top