FBReaderJ阅读器书籍渲染显示过程

阅读器内容的渲染过程:

从阅读器开始(FBReader类开启),到页面显示完成的过程

首先在FBReader中实现了fileFromIntent()方法,从Intent对象中读取要打开的文本路径,因为是直接打开所以此处获得的路径为null,用这个去实例化一个

@Override

protected ZLFile fileFromIntent(Intent intent) {

//如果是从文本打开的方式进入,则此处能够获取到文件路径

String filePath = intent.getStringExtra(BOOK_PATH_KEY);

if (filePath == null) {

final Uri data = intent.getData();

if (data != null) {

filePath = data.getPath();

}

}

return filePath != null ? ZLFile.createFileByPath(filePath) : null;

}

@Override

protected FBReaderApp createApplication(ZLFile file) {

if (SQLiteBooksDatabase.Instance() == null) {

new SQLiteBooksDatabase(this"READER");

}

return new FBReaderApp(file != null ? file.getPath() : null);

}

 

 

ZLAndroidActivityOnCreate中调用

final ZLFile fileToOpen = fileFromIntent(getIntent());

if (((ZLAndroidApplication) getApplication()).myMainWindow == null) {

ZLApplication application = createApplication(fileToOpen);

((ZLAndroidApplication) getApplication()).myMainWindow = new ZLAndroidApplicationWindow(

application);

application.initWindow();

else {

ZLApplication.Instance().openFile(fileToOpen);

}

详解:

由于fileToOpennull,且并未为myMainWindow初始化,则

首先创建FBReaderApp对象,之后再通过instance()方法就能够得到该对象,

由于ZLApplication和其子类FBReaderApp都实现了initWindow(),则会调用子类的(因为此处的applicationFBReaderApp对象),如下:

/**

 * 该方法在ZLAndroidActivity的OnCreate中有调用

 */

public void initWindow() {

super.initWindow();

wait("loadingBook"new Runnable() {

public void run() {

Book book = createBookForFile(ZLFile.createFileByPath(myArg0));

if (book == null) {

book = Library.getRecentBook();

}

if ((book == null) || !book.File.exists()) {

book = Book.getByFile(Library.getHelpFile());

//book = Book.getByFile(ZLResourceFile.createResourceFile("data/help/Noname1.txt"));

}

openBookInternal(book, null);

}

});

}

wait()方法即打开书籍并显示等待进度条,等待进度条的信息根据当前语言而有所不同。

运行到这里,preparePaintInfo执行前,会呈现图书加载中,请等待...的进度框。

 

 

在该构造方法中调用了setView方法,如下:

protected final void setView(ZLView view) {

if (view != null) {

myView = view;

final ZLViewWidget widget = getViewWidget();

if (widget != null) {

widget.reset();

widget.repaint();

}

            //隐藏活动popup

onViewChanged();

}

}

此时getViewWidget()null,则里面的if不执行。

接着,初始化myMainWindow,并初始化,初始化时在ZLAndroidApplicationWindow父类构造方法中,把该window加载到FBReaderApp上了

接着调用FBReaderApp.initWindow()方法,其内部同样调用了setView方法,不同之处在于此时getViewWidget()不为null

public final ZLViewWidget getViewWidget() {

return myWindow != null ? myWindow.getViewWidget() : null;

}

如上,因为此时myWindow不为null,则调用 myWindow.getViewWidget()方法

此方法最终执行如下:

public ZLAndroidWidget getWidget() {

if (myWidget == null) {

myWidget = (ZLAndroidWidget)myActivity.findViewById(R.id.main_view);

}

return myWidget;

}

即能够获得当前Activity中的idmain_viewWidget

所以调用如下:

widget.reset();

widget.repaint();

上面的对BitmapManager进行初始化其页码。

下面的调用重画Widget

 

Widget就是小说画面的承载类,提供了如点击左右方翻页,点击下方出菜单等功能。其具有onDrawInScrolling(),onDrawStatic()方法,分别是翻页中画,和静止中画。

我们主要关注静止中(分页中主要就是一些计算和动画)。

/**

 * 静止中画

 * 

 * @param canvas

 */

private void onDrawStatic(Canvas canvas) {

//System.out.println("ondrawstatic invoke");

// 重新设置小说部分的宽高(主题部分的高是要减去底部

myBitmapManager.setSize(getWidth(), getMainAreaHeight());

// 画出小说部分

canvas.drawBitmap(myBitmapManager.getBitmap(ZLView.PageIndex.current),

0, 0, myPaint);

drawFooter(canvas);

}

我们看到其调用了:

myBitmapManager.getBitmap(ZLView.PageIndex.current);

 

该方法如下:

/**

 * 通过传入的页面参数决定返回的位图

 * @param index

 * @return

 */

Bitmap getBitmap(ZLView.PageIndex index) {

for (int i = 0; i < SIZE; ++i) {

if (index == myIndexes[i]) {

return myBitmaps[i];

}

}

final int iIndex = getInternalIndex(index);

myIndexes[iIndex] = index;

if (myBitmaps[iIndex] == null) {

myBitmaps[iIndex] = Bitmap.createBitmap(myWidthmyHeight, Bitmap.Config.RGB_565);

}

//向myBitmaps[index]上画bitmap

myWidget.drawOnBitmap(myBitmaps[iIndex], index);

return myBitmaps[iIndex];

}

最主要的就是: myWidget.drawOnBitmap(myBitmaps[iIndex], index);

如下:

/**

 * 在位图上画

 * 该方法在BitmapManager中调用。

 * 

 * @param bitmap

 * @param index

 */

void drawOnBitmap(Bitmap bitmap, ZLView.PageIndex index) {

final ZLView view = ZLApplication.Instance().getCurrentView();

if (view == null) {

return;

}

//把ZLAndroidWigetPaintContext与Bitmap进行绑定

final ZLAndroidPaintContext context = new ZLAndroidPaintContext(

new Canvas(bitmap), getWidth(), getMainAreaHeight(),

view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);

view.paint(context, index);

}

 

最主要的仍是最后一句: view.paint(context,index)

此方法代码较长,详情参见ZLTextView. paint(ZLPaintContext context, PageIndex pageIndex) 

 

重要代码如下:

//以上为画背景色

 

ZLTextPage page;

switch (pageIndex) {

default:

case current:

page = myCurrentPage;

break;

case previous:

page = myPreviousPage;

if (myPreviousPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {

//如果下一页没东西画,则画当前页

preparePaintInfo(myCurrentPage);

myPreviousPage.EndCursor.setCursor(myCurrentPage.StartCursor);

myPreviousPage.PaintState = PaintStateEnum.END_IS_KNOWN;

}

break;

case next:

page = myNextPage;

if (myNextPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {

//如果下一页没东西画,则画当前页

preparePaintInfo(myCurrentPage);

myNextPage.StartCursor.setCursor(myCurrentPage.EndCursor);

myNextPage.PaintState = PaintStateEnum.START_IS_KNOWN;

}

}

 

page.TextElementMap.clear();

//准备要画的页面

preparePaintInfo(page);

 

//以下为页面显示

 

 

请见preparePaintInfo(page);方法,该方法传入的是ZLTextPage对象,该对象具有开始和结束cursor,以及每一列文字的信息。即每页的记录类。即为该page绑定要显示的数据开头和结尾信息,以便显示。

 

以上就是图书显示的过程。

总结如下:

ZLAndroidActivity.onCreate() --> FBReaderApp生成,ZLAndroidWidget获取,ZLAndroidWindow创建,FBReaderAPP.initWindow()调用--->ZLAndroidWidget重画

 

所以如果我们想在一开始就加载自己的书籍,就可以在FBReaderAppinitWindow中下功夫。

wait("loadingBook"new Runnable() {

public void run() {

Book book = createBookForFile(ZLFile.createFileByPath(myArg0));

if (book == null) {

book = Library.getRecentBook();

}

if ((book == null) || !book.File.exists()) {

book = Book.getByFile(Library.getHelpFile());

//book = Book.getByFile(ZLResourceFile.createResourceFile("data/help/Noname1.txt"));

}

openBookInternal(book, null);

}

});

 

只需要把,此处的myArg0更换成自己的书籍路径即可!!

 

阅读器内容的渲染过程:

从阅读器开始(FBReader类开启),到页面显示完成的过程

首先在FBReader中实现了fileFromIntent()方法,从Intent对象中读取要打开的文本路径,因为是直接打开所以此处获得的路径为null,用这个去实例化一个

@Override

protected ZLFile fileFromIntent(Intent intent) {

//如果是从文本打开的方式进入,则此处能够获取到文件路径

String filePath = intent.getStringExtra(BOOK_PATH_KEY);

if (filePath == null) {

final Uri data = intent.getData();

if (data != null) {

filePath = data.getPath();

}

}

return filePath != null ? ZLFile.createFileByPath(filePath) : null;

}

@Override

protected FBReaderApp createApplication(ZLFile file) {

if (SQLiteBooksDatabase.Instance() == null) {

new SQLiteBooksDatabase(this"READER");

}

return new FBReaderApp(file != null ? file.getPath() : null);

}

 

 

ZLAndroidActivityOnCreate中调用

final ZLFile fileToOpen = fileFromIntent(getIntent());

if (((ZLAndroidApplication) getApplication()).myMainWindow == null) {

ZLApplication application = createApplication(fileToOpen);

((ZLAndroidApplication) getApplication()).myMainWindow = new ZLAndroidApplicationWindow(

application);

application.initWindow();

else {

ZLApplication.Instance().openFile(fileToOpen);

}

详解:

由于fileToOpennull,且并未为myMainWindow初始化,则

首先创建FBReaderApp对象,之后再通过instance()方法就能够得到该对象,

由于ZLApplication和其子类FBReaderApp都实现了initWindow(),则会调用子类的(因为此处的applicationFBReaderApp对象),如下:

/**

 * 该方法在ZLAndroidActivity的OnCreate中有调用

 */

public void initWindow() {

super.initWindow();

wait("loadingBook"new Runnable() {

public void run() {

Book book = createBookForFile(ZLFile.createFileByPath(myArg0));

if (book == null) {

book = Library.getRecentBook();

}

if ((book == null) || !book.File.exists()) {

book = Book.getByFile(Library.getHelpFile());

//book = Book.getByFile(ZLResourceFile.createResourceFile("data/help/Noname1.txt"));

}

openBookInternal(book, null);

}

});

}

wait()方法即打开书籍并显示等待进度条,等待进度条的信息根据当前语言而有所不同。

运行到这里,preparePaintInfo执行前,会呈现图书加载中,请等待...的进度框。

 

 

在该构造方法中调用了setView方法,如下:

protected final void setView(ZLView view) {

if (view != null) {

myView = view;

final ZLViewWidget widget = getViewWidget();

if (widget != null) {

widget.reset();

widget.repaint();

}

            //隐藏活动popup

onViewChanged();

}

}

此时getViewWidget()null,则里面的if不执行。

接着,初始化myMainWindow,并初始化,初始化时在ZLAndroidApplicationWindow父类构造方法中,把该window加载到FBReaderApp上了

接着调用FBReaderApp.initWindow()方法,其内部同样调用了setView方法,不同之处在于此时getViewWidget()不为null

public final ZLViewWidget getViewWidget() {

return myWindow != null ? myWindow.getViewWidget() : null;

}

如上,因为此时myWindow不为null,则调用 myWindow.getViewWidget()方法

此方法最终执行如下:

public ZLAndroidWidget getWidget() {

if (myWidget == null) {

myWidget = (ZLAndroidWidget)myActivity.findViewById(R.id.main_view);

}

return myWidget;

}

即能够获得当前Activity中的idmain_viewWidget

所以调用如下:

widget.reset();

widget.repaint();

上面的对BitmapManager进行初始化其页码。

下面的调用重画Widget

 

Widget就是小说画面的承载类,提供了如点击左右方翻页,点击下方出菜单等功能。其具有onDrawInScrolling(),onDrawStatic()方法,分别是翻页中画,和静止中画。

我们主要关注静止中(分页中主要就是一些计算和动画)。

/**

 * 静止中画

 * 

 * @param canvas

 */

private void onDrawStatic(Canvas canvas) {

//System.out.println("ondrawstatic invoke");

// 重新设置小说部分的宽高(主题部分的高是要减去底部

myBitmapManager.setSize(getWidth(), getMainAreaHeight());

// 画出小说部分

canvas.drawBitmap(myBitmapManager.getBitmap(ZLView.PageIndex.current),

0, 0, myPaint);

drawFooter(canvas);

}

我们看到其调用了:

myBitmapManager.getBitmap(ZLView.PageIndex.current);

 

该方法如下:

/**

 * 通过传入的页面参数决定返回的位图

 * @param index

 * @return

 */

Bitmap getBitmap(ZLView.PageIndex index) {

for (int i = 0; i < SIZE; ++i) {

if (index == myIndexes[i]) {

return myBitmaps[i];

}

}

final int iIndex = getInternalIndex(index);

myIndexes[iIndex] = index;

if (myBitmaps[iIndex] == null) {

myBitmaps[iIndex] = Bitmap.createBitmap(myWidthmyHeight, Bitmap.Config.RGB_565);

}

//向myBitmaps[index]上画bitmap

myWidget.drawOnBitmap(myBitmaps[iIndex], index);

return myBitmaps[iIndex];

}

最主要的就是: myWidget.drawOnBitmap(myBitmaps[iIndex], index);

如下:

/**

 * 在位图上画

 * 该方法在BitmapManager中调用。

 * 

 * @param bitmap

 * @param index

 */

void drawOnBitmap(Bitmap bitmap, ZLView.PageIndex index) {

final ZLView view = ZLApplication.Instance().getCurrentView();

if (view == null) {

return;

}

//把ZLAndroidWigetPaintContext与Bitmap进行绑定

final ZLAndroidPaintContext context = new ZLAndroidPaintContext(

new Canvas(bitmap), getWidth(), getMainAreaHeight(),

view.isScrollbarShown() ? getVerticalScrollbarWidth() : 0);

view.paint(context, index);

}

 

最主要的仍是最后一句: view.paint(context,index)

此方法代码较长,详情参见ZLTextView. paint(ZLPaintContext context, PageIndex pageIndex) 

 

重要代码如下:

//以上为画背景色

 

ZLTextPage page;

switch (pageIndex) {

default:

case current:

page = myCurrentPage;

break;

case previous:

page = myPreviousPage;

if (myPreviousPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {

//如果下一页没东西画,则画当前页

preparePaintInfo(myCurrentPage);

myPreviousPage.EndCursor.setCursor(myCurrentPage.StartCursor);

myPreviousPage.PaintState = PaintStateEnum.END_IS_KNOWN;

}

break;

case next:

page = myNextPage;

if (myNextPage.PaintState == PaintStateEnum.NOTHING_TO_PAINT) {

//如果下一页没东西画,则画当前页

preparePaintInfo(myCurrentPage);

myNextPage.StartCursor.setCursor(myCurrentPage.EndCursor);

myNextPage.PaintState = PaintStateEnum.START_IS_KNOWN;

}

}

 

page.TextElementMap.clear();

//准备要画的页面

preparePaintInfo(page);

 

//以下为页面显示

 

 

请见preparePaintInfo(page);方法,该方法传入的是ZLTextPage对象,该对象具有开始和结束cursor,以及每一列文字的信息。即每页的记录类。即为该page绑定要显示的数据开头和结尾信息,以便显示。

 

以上就是图书显示的过程。

总结如下:

ZLAndroidActivity.onCreate() --> FBReaderApp生成,ZLAndroidWidget获取,ZLAndroidWindow创建,FBReaderAPP.initWindow()调用--->ZLAndroidWidget重画

 

所以如果我们想在一开始就加载自己的书籍,就可以在FBReaderAppinitWindow中下功夫。

wait("loadingBook"new Runnable() {

public void run() {

Book book = createBookForFile(ZLFile.createFileByPath(myArg0));

if (book == null) {

book = Library.getRecentBook();

}

if ((book == null) || !book.File.exists()) {

book = Book.getByFile(Library.getHelpFile());

//book = Book.getByFile(ZLResourceFile.createResourceFile("data/help/Noname1.txt"));

}

openBookInternal(book, null);

}

});

 

只需要把,此处的myArg0更换成自己的书籍路径即可!!

 

你可能感兴趣的:(FBReaderJ)