原文地址:http://wangliping.net/read-big-txt
由于现在TXT文本很多,特别是好多小说也是以这个文件格式出现,毕竟这个格式所占用不必要的空间比较小。像我这样的人就非常喜欢在手机上看小说, 经常下载好多的TXT格式小说存到手机上以便空闲时候看。于是乎也试图做了一下如何在Android上实现看大文本的txt文档。
虽然现在类似的应用还真不少,不过个人看到的基本不公布源码,而公布源码的基本都是不能看大文本的,所以自己去实现了一下。现在只是粗 略实现了,实现方法是每次当滑动到屏幕底端时,从文件读2048字节出来显示到屏幕上。到屏幕底端再读是为了不给用户有刷屏的感觉,使用起来感觉不到只读 了2048字节出来,比较流畅。现在由于只是试验流畅性,所以只写了向下浏览的,而没有写往回读,也就是说往回翻是无效的。
废话不多说,代码是王道。这个是主文件:
import java.io.FileInputStream ;
import java.io.IOException ;
import java.io.InputStreamReader ;
import java.nio.CharBuffer ;
import android.app.Activity ;
import android.net.Uri ;
import android.os.AsyncTask ;
import android.os.Bundle ;
import android.os.Handler ;
import android.os.Message ;
import android.text.TextUtils ;
import android.util.Log ;
import android.widget.ScrollView ;
import net.wangliping.test.R ;
public class TxtReader extends Activity implements
RealTimeTextView . OnTextChangedListener {
private static final String LOG_TAG = "TxtReader" ;
private static final int SHOW_TXT = 1 ;
private SwanTextView mTextShow ;
private ScrollView mScrollView ;
private String mStringShow = null ;
private boolean mContinueRead = true ;
private boolean mHaveNewText = false ;
private int mCurBottom = - 1 ;
private int mNum = - 1 ;
private final Handler mHandler = new Handler () {
@Override
public void handleMessage (Message msg ) {
switch (msg . what ) {
case SHOW_TXT:
mTextShow . setText ((CharBuffer ) msg . obj );
break ;
default :
super . handleMessage (msg );
}
}
};
public void onCreate (Bundle savedInstanceState ) {
super . onCreate (savedInstanceState );
setContentView (R . layout . txt_reader );
Uri uri = getIntent (). getData ();
mScrollView = (ScrollView ) findViewById (R . id . text_show_scroll );
mTextShow = (RealTimeTextView ) findViewById (R . id . text_show );
mTextShow . setOnTextChangedListener (this );
new TextShowTask (). execute (uri );
}
private void showText (Uri uri ) throws IOException , InterruptedException {
InputStreamReader is = new InputStreamReader (new FileInputStream (
uri . getPath ()), "GB2312" );
StringBuilder sb = new StringBuilder ();
char [] buf = new char [ 1024 * 2 ];
while (true ) {
if (mCurBottom == mScrollView . getScrollY ()) {
Log . d (LOG_TAG , "curBtm:" + mCurBottom + " scroll:"
+ mScrollView . getScrollY ());
mCurBottom = - 1 ;
mNum ++;
if (mNum % 2 == 0 ) {
mContinueRead = true ;
Log . d (LOG_TAG , "YES" );
}
}
if (mContinueRead && is . read (buf ) > 0 ) {
mContinueRead = false ;
if (sb. length () > 4096 ) {
sb. delete (0 , 2048 );
Message msg = mHandler . obtainMessage (SHOW_TXT );
msg . obj = CharBuffer . wrap (sb. toString ());
mHandler . sendMessage (msg );
mStringShow = sb. append (buf ). toString ();
mHaveNewText = true ;
} else {
while (sb. length () < 4096 ) {
sb. append (buf );
is . read (buf );
}
sb. append (buf );
Message msg = mHandler . obtainMessage (SHOW_TXT );
msg . obj = CharBuffer . wrap (sb. toString ());
mHandler . sendMessage (msg );
}
}
}
}
private class TextShowTask extends AsyncTask < Object , Object , Object > {
@Override
protected void onPostExecute (Object param ) {
Log . d (LOG_TAG , "Send broadcast" );
}
@Override
protected Object doInBackground (Object ... params ) {
Uri uri = (Uri ) params [ 0 ];
try {
showText (uri );
} catch (Exception e ) {
Log . d (LOG_TAG , "Exception" , e );
}
return null ;
}
}
@Override
public void onPreOnDraw (int bottom ) {
mCurBottom = bottom - mScrollView . getHeight ();
if (mHaveNewText && ! TextUtils . isEmpty (mStringShow )) {
mHaveNewText = false ;
Message msg = mHandler . obtainMessage (SHOW_TXT );
msg . obj = CharBuffer . wrap (mStringShow );
mHandler . sendMessage (msg );
}
}
}
这个为了得到TextView底部的位置而扩展了TextView类:
import android.content.Context ;
import android.graphics.Canvas ;
import android.util.AttributeSet ;
import android.widget.TextView ;
public class SwanTextView extends TextView {
private int mPreBottom = - 1 ;
private OnTextChangedListener textChangedListener = null ;
public SwanTextView (Context context ) {
super (context );
}
public SwanTextView (Context context , AttributeSet attrs ) {
super (context , attrs );
}
public SwanTextView (Context context , AttributeSet attrs ,
int defStyle ) {
super (context , attrs , defStyle );
}
@Override
protected void onDraw (Canvas canvas ) {
if (mPreBottom != getBottom ()) {
mPreBottom = getBottom ();
if (textChangedListener != null )
textChangedListener . onPreOnDraw (mPreBottom );
}
super . onDraw (canvas );
}
public static interface OnTextChangedListener {
public void onPreOnDraw (int bottom );
}
public void setOnTextChangedListener (OnTextChangedListener listener ) {
textChangedListener = listener ;
}
}
这个就是资源文件了:
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
android:id= "@+id/text_show_linear" android:layout_width= "wrap_content"
android:layout_height= "wrap_content" >
<ScrollView android:id= "@+id/text_show_scroll"
android:layout_width= "fill_parent" android:layout_height= "fill_parent" >
<net.wangliping.filemanager.SwanTextView
android:id= "@+id/text_show" android:layout_width= "fill_parent"
android:layout_height= "wrap_content" android:scrollbars= "none" >
</net.wangliping.filemanager.SwanTextView>
</ScrollView>
</LinearLayout>
代码不成熟,见笑了