Android实战之小说阅读器,带有水平翻页,记录上次读取页码数_安卓怎么计算小说章节页码-程序员宅基地

技术标签: android应用  阅读器  SQLite  小说  Android  

实现的效果图:


实现的步骤:

一,建立布局文件:3个布局xml

1,activity_main.xml:显示sdcard卡中所有的文件夹及文件

<LinearLayout 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:orientation="vertical" >
    <TextView
        android:id="@+id/title_text"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:text="当前位置: /mnt/sdcard"
        android:textSize="14sp" />
    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"
        android:cacheColorHint="#00000000" >
    </ListView>
</LinearLayout>

2.file_line.xml主要填充list中的文本数据

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
    <TextView
        android:id="@+id/file_img"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1" />
    <TextView
        android:id="@+id/file_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="4"
        android:textSize="14sp" />
</LinearLayout>

3.activity_detail.xml:这是小说显示的显示界面

<LinearLayout 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:background="#ffffff"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/txt_title"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" /> 

//这里自定义一个MyView用以显示小说的文本内容
    <com.example.ebook.view.MyView
        android:id="@+id/txt_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"
       />
<TextView
        android:id="@+id/txt_page"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center"
        android:textColor="#000000"
        android:textSize="14sp" />
</LinearLayout>

二、java代码部分:现在com.example.ebook.dbc包中创建DataBaseConnection类中建两个数据库:txt.db  和  page.db

package com.example.ebook.dbc;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DataBaseConnection extends SQLiteOpenHelper {
public DataBaseConnection(Context ctx){
super(ctx,"txt.db",null,1);
}
public DataBaseConnection(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
//初始化文本表
String sql = "CREATE TABLE txt (" +
"id integerprimarykey," +
"full_path text ," +
"now_page integer ," +
"over_flag integer " +
")";
db.execSQL(sql);
//初始化页码表
sql ="CREATE TABLE page(" +
"id integerprimary key," +
"txt_id integer ," +
"page_num integer ," +
"content text " +
")";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}
}

2.在util包中建类Globals:

package com.example.ebook.util;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import com.example.ebook.R;
import com.example.ebook.dbc.DataBaseConnection;
public class Globals {
public static int SCREEN_WIDTH;
public static int SCREEN_HEIGHT;

//建立一个map集合,里面封装了所有的扩展名对应的图片,以便进行文件图片的显示
public static Map<String,Integer> allIconImgs = new HashMap<String,Integer>();
public static DataBaseConnection dbc;
//每行显示的字数
public static int LINE_CHAR_COUNT = 20;
//字符间隔
public static int CHAR_SEP = 2;
//页边距
public static int PAGE_SEP = 20;
//每个字的大小
public static int CHAR_SIZE;
//行间隔
public static int LINE_SEP;
//计算行数
public static int LINE_COUNT;
//每一行文本之间的间隔文字
public static String TXT_SEP_FLAG = "LINE_SEP_FLAG_BU_NENG_CHONG_FU";

public static void init(Activity a){
SCREEN_WIDTH = a.getWindowManager().getDefaultDisplay().getWidth();
SCREEN_HEIGHT = a.getWindowManager().getDefaultDisplay().getHeight();

//初始化数据库
dbc = new DataBaseConnection(a);
dbc.getWritableDatabase();

//初始化所有扩展名和图片的对应的关系
allIconImgs.put("txt", R.drawable.txt_file);
allIconImgs.put("mp3", R.drawable.mp3_file);
allIconImgs.put("mp4", R.drawable.mp4_file);
allIconImgs.put("bmp", R.drawable.image_file);
allIconImgs.put("gif", R.drawable.image_file);
allIconImgs.put("png", R.drawable.image_file);
allIconImgs.put("jpg", R.drawable.image_file);
allIconImgs.put("dir_open", R.drawable.open_dir);
allIconImgs.put("dir_close", R.drawable.close_dir);

//计算数字= 屏幕宽度“字”总宽度/行字数 
//屏幕宽度“字”总宽度 = 屏幕宽度 - 页边距 * 2 - 字符间隔宽度
//字符间隔宽度 = (字符数-1)* 字符间距
CHAR_SIZE =(SCREEN_WIDTH - (PAGE_SEP * 2) - (LINE_CHAR_COUNT - 1)
* CHAR_SEP)/LINE_CHAR_COUNT;
//只使用屏幕高度的4/5来显示文字内容,计算所显示出的行数
//行数 = (屏幕*4/5)/(字的高度+行间距)
LINE_COUNT = SCREEN_HEIGHT * 4 / 5 / (CHAR_SIZE + LINE_SEP);
}

}

3.在com.example.ebook.util中添加TxtDAOUtil类

package com.example.ebook.util;
import java.util.HashMap;
import java.util.Map;
import android.database.Cursor;
public class TxtDAOUtil {
public static void insertData(String fullPath){
//先判断之前是否添加过
String sql = "SELECT id FROM txt WHERE full_path =?";
Cursor c = Globals.dbc.getReadableDatabase().rawQuery(sql,
new String[]{fullPath});

if(!c.moveToFirst()){
//数据库中没有这条数据,就需要添加,默认设置用户打开的页面是第一页, 同时还没有完成分页的操作
sql = "INSERT INTO txt (full_path,now_page,over_flag) VALUES (?,1,0)";

Globals.dbc.getWritableDatabase().execSQL(sql,new Object[]{fullPath});
}
c.close();
}

public static void updateOverFlag(int id){
String sql = "UPDATE txt SET over_flag =1 WHERE id =?";
Globals.dbc.getWritableDatabase().execSQL(sql, new Object[]{id});
}

public static void updateNowPage(int id,int nowPage){
String sql = "UPDATE txt SET now_page =? WHERE id =?";
Globals.dbc.getWritableDatabase().execSQL(sql, new Object[]{nowPage,id});
}

public static Map<String,Object> getTxtDataByFullPath(String fullPath){
Map<String,Object> map = new HashMap<String,Object>();
String sql = "SELECT id,now_page,over_flag FROM txt WHERE full_path = ?";
Cursor c = Globals.dbc.getReadableDatabase().rawQuery(sql,
new String[]{fullPath});
c.moveToFirst();
map.put("id", c.getInt(0));
map.put("nowPage", c.getInt(1));
map.put("overFlag", c.getInt(2));

return map;
}
}

4在com.example.ebook.util中建立PageDAOUtil

package com.example.ebook.util;
import java.util.Map;
import android.database.Cursor;
public class PageDAOUtils {
public static void insertData(Map<String, Object> map) {
String sql = "INSERT INTO page (txt_id,page_num,content) VALUES (?,?,?)";
Globals.dbc.getWritableDatabase().execSQL(
sql,
new Object[] { map.get("txtId"), map.get("pageNum"),
map.get("content") });
}
public static int getAllCount(int txtId) {
String sql = "SELECT COUNT(*) FROM page WHERE txt_id = ?";
Cursor c = Globals.dbc.getReadableDatabase().rawQuery(sql,
new String[] { String.valueOf(txtId) });
c.moveToFirst();
int count = c.getInt(0);
c.close();
return count;
}

public static void deletePageData(int txtId) {
String sql = "DELETE FROM page WHERE txt_id =?";
Globals.dbc.getWritableDatabase().execSQL(sql, new Object[] { txtId });
}

public static String getPageContent(int txtId, int pageNum) {
String sql = "SELECT content FROM page WHERE txt_id = ? AND page_num = ?";
Cursor c = Globals.dbc.getReadableDatabase()
.rawQuery(
sql,
new String[] { String.valueOf(txtId),
String.valueOf(pageNum) });

c.moveToFirst();
String content = c.getString(0);

c.close();
return content;
}
}

5. com.example.ebook.adapter中建立FileAdapter,这是解决sdcard卡显示布局的

package com.example.ebook.adapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.example.ebook.R;
import com.example.ebook.util.Globals;
import android.content.ContentValues;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class FileAdapter extends BaseAdapter {
private Context ctx;
private List<Map<String,Object>> allValues = new ArrayList<Map<String,Object>>();
public FileAdapter(Context ctx, List<Map<String, Object>> allValues) {
this.ctx = ctx;
this.allValues = allValues;
}

@Override
public int getCount() {
return allValues.size();
}

@Override
public Object getItem(int position) {
return allValues.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = LayoutInflater.from(ctx).inflate(R.layout.file_line, 
null);

//设置高度
convertView.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, Globals.SCREEN_HEIGHT /9));
}

//取得图片组件
TextView fileImg = (TextView) convertView.findViewById(R.id.file_img);
fileImg.getLayoutParams().height = Globals.SCREEN_HEIGHT/9;
TextView fileName = (TextView) convertView.findViewById(R.id.file_name);
//取得数据,设置到组件里
Map<String,Object> map = allValues.get(position);
//设置内容,文字
fileName.setText(map.get("fileName").toString());
//图片要根据扩展名取得
String extName = map.get("extName").toString();
//取得图片的id
int imgId = Globals.allIconImgs.get(extName);
//设置图片
fileImg.setBackgroundResource(imgId);
return convertView;
}
}

6.在package com.example.ebook中建立一个MainActivity类

package com.example.ebook;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.TextView;
import com.example.ebook.adapter.FileAdapter;
import com.example.ebook.util.Globals;
import com.example.ebook.util.TxtDAOUtil;

public class MainActivity extends Activity {
private TextView titleText;
private ListView list;
private FileAdapter adapter;
private List<Map<String,Object>> allValues = new ArrayList<Map<String,Object>>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Globals.init(this);
setContentView(R.layout.activity_main);
//取得组件
titleText = (TextView) findViewById(R.id.title_text);
list = (ListView) findViewById(R.id.list);

//准备数据
//取得SD卡根目录
File root = Environment.getExternalStorageDirectory();
loadFileData(root);

//建立Adapter
adapter = new FileAdapter(this, allValues);
list.setAdapter(adapter);
//加入监听事件
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
//取得当前操作的数据
Map<String,Object> map = allValues.get(arg2);
//判断所有点的是文件还是文件夹
boolean dirFlag = (Boolean) map.get("dirFlag");
if(dirFlag){
//文件夹
//建立该文件的File对象
//取得绝对路劲
String fullPath = (String) map.get("fullPath");
//建立File
File dir = new File(fullPath);

//先清空原有的数据
allValues.clear();

if(!Environment.getExternalStorageDirectory()
.getAbsolutePath().equals(fullPath)){

//加入返回上一级的操作数
Map<String,Object> parent = new HashMap<String,Object>();
parent.put("fileName", "返回上一级");
parent.put("extName", "dir_open");
parent.put("dirFlag", true);
parent.put("fullPath", dir.getParent());

//保存一个标志
parent.put("flag", "TRUE");
//将这一行加入到数据集合中
allValues.add(parent);
}

//加入新数据
loadFileData(dir);
//使用Adapter通知界面ListView,数据已经被修改了,你也要一起改
adapter.notifyDataSetChanged();
}else{
//将该文件保存到文本表中
TxtDAOUtil.insertData(map.get("fullPath").toString());

//切换界面
Intent in = new Intent(MainActivity.this,DetailActivity.class);
in.putExtra("fullPath", map.get("fullPath").toString());
startActivity(in);
}
}
});
list.setOnItemLongClickListener(new OnItemLongClickListener() {

@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
final int arg2, long arg3) {
//取得数据
Map<String,Object> map = allValues.get(arg2);
final File f = new File(map.get("fullPath").toString());

if(f.isFile()){
//弹出确认框
Builder builder = new Builder(MainActivity.this);
builder.setTitle("提示");
builder.setMessage("确认要删除该文件(" + f.getName() + ")吗?");
builder.setPositiveButton("确定",new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
//将SD卡中的文件删除
if(f.exists()){
f.delete();
}

//将列表中的数据删除
allValues.remove(arg2);
//通知
adapter.notifyDataSetChanged();
}
});
builder.setNegativeButton("取消", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {

}
});
builder.create().show();
}
return false;
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//根据keyCode判断用户按下了那个键
if(keyCode == KeyEvent.KEYCODE_BACK){
//判断当前是否在SD卡根目录下。
//取得第一行数据
Map<String,Object> map = allValues.get(0);
if("TRUE".equals(map.get("flag"))){
//里面,需要返回上一级
list.performItemClick(list.getChildAt(0),
0, list.getChildAt(0).getId());
}else{
//弹出提示框
Builder builder = new Builder(MainActivity.this);
builder.setTitle("提示");
builder.setMessage("亲,真的要离开我吗?");
builder.setPositiveButton("真的", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.setNegativeButton("取消", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {

}
});
builder.create().show();
}
return false;
}

return super.onKeyDown(keyCode, event);
}

private void loadFileData(File dir) {
//列出该目录下的所有文件
File[] allFiles = dir.listFiles();
//设置当前位置的提示信息
titleText.setText("当前位置:"+ dir.getAbsolutePath());

//判断
if(allFiles != null){
//循环
for(int i=0;i<allFiles.length;i++){
File f = allFiles[i];
Map<String,Object> map = new HashMap<String,Object>();
map.put("fileName", f.getName());
//多保存一个文件的绝对路径,方便在进行点击时使用
map.put("fullPath", f.getAbsolutePath());
//判断是文件夹还是文件
if(f.isDirectory()){
//是文件夹
map.put("extName", "dir_close");
map.put("dirFlag", true);
}else{
//是文件,截取出扩展名
String extName = f.getName()
.substring(f.getName().lastIndexOf(".")+1)
.toLowerCase();
map.put("extName", extName);
map.put("dirFlag", false);
}
//只有文件夹或是文本文件才要显示
if(f.isDirectory() || "txt".equals(map.get("extName"))){
allValues.add(map);
}
}
}
}
}


7.在 com.example.ebook.view中建立MyView类

package com.example.ebook.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import com.example.ebook.DetailActivity;
import com.example.ebook.R;
import com.example.ebook.util.Globals;
import com.example.ebook.util.PageDAOUtils;
public class MyView extends View {
private int pageNum;
private int txtId;

// 多查询上一页和下一页的文本,作为缓存保存下来,一边翻页时显示使用
private String preContent;
private String content;
private String nextContent;

// 加入监听,可以让当前的内容,跟着手指一起移动
// 开始时按下的位置
private float startX = 0;
// 移动后的位置
private float nowX = 0;
// 准备好TxtPage
private TextView txtPage;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// 为自己加入监听,这里的点击事件不需要实现,但是要写
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
this.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// 判断当前操作的状态
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// 按下是,记录横坐标的位置
startX = event.getX();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
nowX = event.getX();
// 平移界面中绘制的内容。
postInvalidate();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
// 翻页操作
// 判断手指的位置
nowX = event.getX();
if (Math.abs(nowX - startX) < 50) {
// 不变
} else if (nowX > startX) {
// 翻上一页
if (pageNum > 1) {
pageNum--;
// 重新查询当前页的数据
changePage();
}
} else {
// 翻下一页
if (pageNum < PageDAOUtils.getAllCount(txtId)) {
pageNum++;
changePage();
}
}
nowX = 0;
startX = 0;
}
return false;
}

});
}

public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public void initPage(int txtId, int pageNum) {
this.txtId = txtId;
this.pageNum = pageNum;
changePage();
}
private void changePage() {
// 查询当前页的文本内容,并刷新显示到界面上
content = PageDAOUtils.getPageContent(txtId, pageNum);
// 同时查询出上一页和下一页的数据
if (pageNum > 1) {
// 有上一页
preContent = PageDAOUtils.getPageContent(txtId, pageNum - 1);
} else {
preContent = null;
}
if (pageNum < PageDAOUtils.getAllCount(txtId)) {
// 有下一页
nextContent = PageDAOUtils.getPageContent(txtId, pageNum + 1);
} else {
nextContent = null;
}

DetailActivity a = (DetailActivity) getContext();

if (txtPage == null) {
txtPage = (TextView) a.findViewById(R.id.txt_page);
}
// 改变底部的显示文字
txtPage.setText("分页完成,当前:" + pageNum + "/"
+ PageDAOUtils.getAllCount(txtId));

// 修改Activity中的nowPage
a.setNowPage(pageNum);
// 刷新显示内容
super.postInvalidate();
}
// 绘制组件中的具体内容
@Override
protected void onDraw(Canvas canvas) {
// 先清空之前绘制的所有内容
super.onDraw(canvas);
if (content != null) {
// 拆分每页的文本,变成每行的文本形式
String[] allStr = content.split(Globals.TXT_SEP_FLAG);

// 建立绘制参数对象
Paint paint = new Paint();
// 通过该对象设置绘制的颜色,文字大小,填充状态等信息
paint.setTextSize(Globals.CHAR_SIZE);
paint.setColor(Color.BLACK);
// 循环绘制 当前页的文字
for (int i = 0; i < allStr.length; i++) {
for (int j = 0; j < allStr[i].length(); j++) {
// 文字需要根据手指的移动位置有一个偏移
canvas.drawText(String.valueOf(allStr[i].charAt(j)),
Globals.PAGE_SEP + j
* (Globals.CHAR_SIZE + Globals.CHAR_SEP)
+ (nowX - startX), (i + 1)
* (Globals.CHAR_SIZE + Globals.LINE_SEP),
paint);
}
}

// 绘制上一页或下一页的文字
if (nowX < startX && nextContent != null) {
allStr = nextContent.split(Globals.TXT_SEP_FLAG);

// 正在翻向下一页,需要将下一页的内容显示出来
for (int i = 0; i < allStr.length; i++) {
for (int j = 0; j < allStr[i].length(); j++) {
// 文字需要根据手指的移动位置有一个偏移
canvas.drawText(
String.valueOf(allStr[i].charAt(j)),
Globals.PAGE_SEP
+ j
* (Globals.CHAR_SIZE + Globals.CHAR_SEP)
+ (nowX - startX)
+ Globals.SCREEN_WIDTH,
(i + 1)
* (Globals.CHAR_SIZE + Globals.LINE_SEP),
paint);
}
}
}
if (nowX > startX && preContent != null) {
allStr = preContent.split(Globals.TXT_SEP_FLAG);
// 正在翻向上一頁,需要將上一頁的內容显示出来
for (int i = 0; i < allStr.length; i++) {
for (int j = 0; j < allStr[i].length(); j++) {
// 文字需要根据手指的移动位置有一个偏移
canvas.drawText(
String.valueOf(allStr[i].charAt(j)),
Globals.PAGE_SEP
+ j
* (Globals.CHAR_SIZE + Globals.CHAR_SEP)
+ (nowX - startX)
- Globals.SCREEN_WIDTH,
(i + 1)
* (Globals.CHAR_SIZE + Globals.LINE_SEP),
paint);
}
}
}
}
}
}

8。最后建立DetailActivity

package com.example.ebook;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import android.R.integer;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
import com.example.ebook.util.Globals;
import com.example.ebook.util.PageDAOUtils;
import com.example.ebook.util.TxtDAOUtil;
import com.example.ebook.view.MyView;
public class DetailActivity extends Activity {

//声明这个handler类
private Handler handler;
//文本信息
private Map<String,Object> txtMap;
private Map<String,Object> pageMap = new HashMap<String,Object>();

private int lineCount;
private int pageNum;
private StringBuilder builder;
private String fullPath;
//取得底部显示分页的信息
private TextView txtPage;
//显示文本内容的标志
private boolean showedFlag = false;
//当前的页数
private int nowPage = 1;
public int getNowPage() {
return nowPage;
}

public void setNowPage(int nowPage) {
this.nowPage = nowPage;
}
private MyView txtContent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
txtPage = (TextView) findViewById(R.id.txt_page);
txtContent = (MyView) findViewById(R.id.txt_content);

//接受传入的文本,查询数据库中该文件是否完成了分页
fullPath = getIntent().getStringExtra("fullPath");
txtMap  = TxtDAOUtil.getTxtDataByFullPath(fullPath);
//建立Handler
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 0){
//显示已经处理好的页面
txtPage.setText("已经处理好了:"+(pageNum - 1)+"页的数据");
}else{
txtPage.setText("分页完成,当前:1/"+(pageNum-1));
}
}
};

//判断当前的文本是否被分页完成,如果没有被分页过,就需要自己进行分页处理
if((Integer)(txtMap.get("overFlag"))==0){
//首先这里必须子进程对内容进行读取,防止主线程读取卡屏
Thread t = new Thread(){
@Override
public void run() {
//进行分页的处理,就是要读取文本
try{
//将之前分页处理的结果删除,防止之前分页到一半,用户退出造成问题
PageDAOUtils.deletePageData((Integer) txtMap.get("id"));

//windows上的文本必须转码 
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(
new File(fullPath)),"GBK"));
String line = null;
builder = new StringBuilder();

//计算已经读取的内容,在手机上显示的行数,当满足一页时,将其保存到数据库里,再重新计算行数,以便保存下一页
lineCount = 0;
//当前加入了的页数
pageNum = 1;

while((line = reader.readLine()) != null){
//对line进行拆分
//通过一个循环来截取内容
while(line.length() > 20){
//截取出一行
String tempStr = line.substring(0, 20);
addPageLineData(tempStr);

//截取后半部分,继续循环
line = line.substring(20);
}
//这里应该剩下一行,对该行也进行相同的处理
addPageLineData(line);
}
//剩下不到一页的内容,也要保存到数据库里
pageMap.put("txtId", txtMap.get("id"));
pageMap.put("pageNum", pageNum++);
pageMap.put("content", builder.toString());

PageDAOUtils.insertData(pageMap);
//如果整个文件都读取完成了,但还没有显示数据,就需要自己进行显示处理
if(!showedFlag){
showedFlag = true;
txtContent.initPage((Integer) txtMap.get("id"), 1);
}
//修改状态
TxtDAOUtil.updateOverFlag((Integer) txtMap.get("id"));
handler.sendEmptyMessage(1);
reader.close();
}catch(Exception e){
e.printStackTrace();
}
}
};
t.start();
}else{
//如果已经初始化好了分页
//需要显示出上次看到的位置
showedFlag = true;
txtContent.initPage((Integer)txtMap.get("id"), (Integer)txtMap.get("nowPage"));
}
}
@Override
protected void onDestroy() {
//退出时,需要记录下当前看到的页数
TxtDAOUtil.updateNowPage((Integer) txtMap.get("id"), nowPage);
super.onDestroy();
}
private void addPageLineData(String lineData) throws InterruptedException {
lineCount++;
builder.append(lineData);
builder.append(Globals.TXT_SEP_FLAG);

if(lineCount == Globals.LINE_COUNT){
//满一页,就需要保存
pageMap.put("txtId", txtMap.get("id"));
pageMap.put("pageNum", pageNum++);
pageMap.put("content", builder.toString());

PageDAOUtils.insertData(pageMap);

handler.sendEmptyMessage(0);
//如果已经够了10页,就可以显示了
if(!showedFlag){
showedFlag =  true;
txtContent.initPage((Integer) txtMap.get("id"), 1);
}

Thread.sleep(5);
//添加后,都需要将一些数据清空
builder = new StringBuilder();
lineCount = 0;
}
}
}

全部代码上传完毕,在翻页效果时,有那种说面的效果必须是需要算法的。这里后期的文章里将尝试解决。需要素材或是源码,评价中说明下



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u014078192/article/details/23605819

智能推荐

Hashtable与HashMap的区别_hashmap效率高于hashtable-程序员宅基地

文章浏览阅读411次,点赞5次,收藏5次。Hashtable与HashMap的区别 HashMap不是线程安全的,HashTable是线程安全。 HashMap允许空(null)的键和值(key),HashTable则不允许。 HashMap性能优于Hashtable。 Map1.Map是一个以键值对存储的接口。Map下有两个具体的实现,分别是HashMap和HashTable.2.Ha_hashmap效率高于hashtable

ICLR 2019评审意见上线:论文得分中位数连年下滑,最高分论文出炉-程序员宅基地

文章浏览阅读1.5k次。林鳞 编译整理量子位 出品 | 公众号 QbitAIAttention:ICLR 2019大部分论文的得分和评审意见已经新鲜出炉了。这两天,openreview网站放出了..._icml最高分

Java编程之伪共享与缓存行填充-程序员宅基地

文章浏览阅读165次。最近在回顾Disruptor的相关知识,觉得Disruptor在计算机底层的领域确实比一般人厉害不少,以前在写程序的时候,基本是从应用逻辑的角度考虑,觉得设计模式+少量算法+ 优美的代码=理想的结果,但看完Disruptor的设计后,觉得只考虑应用本身是有一定的局限性,还需要懂底层,硬件层面的东西,就像Disruptor一样,通过底层优化,让程序有质的飞跃。下面就Disruptor提到的CPU缓存话题,做了一些尝试和研究,如Disruptor所说,CPU有缓存伪共享的问题,并且通过缓存行填充能完美的解决这

使用sqlyog 把excel数据导入到数据表中_sqlyog怎么将excel导入到表中-程序员宅基地

文章浏览阅读1.8k次。使用sqlyog 把excel数据导入到数据表中先说一点注意事项, 我的电脑中最开始装的是 office 2010, 是的没错, 都2020年12月份了, 我还在用 office 2010 因为它是一个破解版的, 不用去找激活码, 所以就一直在用当我使用我的 sqlyog 来导入excel 数据表的时候, sqlyog 给我报错说一个AccessDatabaseEngine_X64.exe文件没有安装, 但是 office 2010是 32位的, 又装不了这个, 所以最终只有卸载了 office ._sqlyog怎么将excel导入到表中

C语言绘图_c语言画图像-程序员宅基地

文章浏览阅读938次,点赞4次,收藏2次。在C语言中使用OpenGL进行绘图,首先需要包含OpenGL的头文件,并初始化OpenGL。然后,你可以使用OpenGL的函数来创建和操作图形对象,例如多边形、线条、圆形等等。但是,你可以使用外部库来进行绘图,比如SDL,OpenGL,或者Windows的GDI库。此外,除了以上提到的SDL和OpenGL,还有许多其他的C语言绘图库可供选择。以上这些是常见的C语言绘图库,每个库都有其独特的特点和优势,你可以根据自己的需求选择适合自己的库。首先,你需要在你的计算机上安装SDL库。来设置渲染颜色,然后使用。_c语言画图像

2022年6月TIOBE编程语言排名:Python、C、Java_tiobe 语言排名-程序员宅基地

文章浏览阅读4.3k次。2022年6月TIOBE编程语言排名:Python、C、Java。6 月榜单中TIOBE 官方用“C++ 即将超越 Java”为标题凸显出了最大的变化,早在2021年,Python 在人工智能这条大船下势不可挡也超越了Java,Java排名第三。_tiobe 语言排名

随便推点

python 变量命名与使用_name1什么意思python-程序员宅基地

文章浏览阅读1k次。一, 变量命名1,概念:变量名只有在第一次出现的时候,才是定义变量。当再次出现时,不是定义变量,而是直接使用之前定义的变量。2,命名1)变量名可以包括字母、数字、下划线,但是数字不能做为开头。例如:name1是合法变量名,而1name就不可以。2)系统关键字不能做变量名使用3)除了下划线之个,其它符号不能做为变量名使用4)Python的变量名是除分大小写的注:可以使用驼峰命名法大驼峰:每一个单词的首字母都大写 FirstName LastName小驼峰:第一个单词以小写字母开始_name1什么意思python

向0圆整 matlab,matlab学习笔记-程序员宅基地

文章浏览阅读614次。1、ceil 是向离它最近的大整数圆整 对x朝正无穷大方向取整如a = [-1.9, -0.2, 3.4, 5.6, 7, 2.4+3.6i]圆整后:a=[-1,0,4, 6, 7 ,3+4i]fix向0靠拢取整: fix(3.2)ans =3>> fix(3.7)ans =3>> fix(-3.7)ans =-3>> fix(-3.2)ans =-3floor..._向大圆整

自定义对话框——7种_没有窗口时如何定义对话框的所有者-程序员宅基地

文章浏览阅读829次。Activities提供了一种方便管理的创建、保存、回复的对话框机制,例如 onCreateDialog(int), onPrepareDialog(int, Dialog), showDialog(int), dismissDialog(int)等方法,如果使用这些方法的话,Activity将通过getOwnerActivity()方法返回该Activity管理的对话框(dialog)._没有窗口时如何定义对话框的所有者

求基于图像处理的身份证号码识别的程序-程序员宅基地

文章浏览阅读1.6k次。要求是MATLAB编写的根据身份证号码来进行识别,0~9和一个x来进行识别(不是通过姓名(汉字))识别要求最后能显示详细信息例如姓名:性别:身份证号:籍贯:

探索ArcMap2SLD:GIS领域的效率提升利器-程序员宅基地

文章浏览阅读193次,点赞3次,收藏6次。探索ArcMap2SLD:GIS领域的效率提升利器项目地址:https://gitcode.com/sufan89/ArcMap2SLD项目简介ArcMap2SLD 是一个基于Python编写的开源工具,专为地理信息系统(GIS)用户设计。它旨在帮助用户将ArcGIS ArcMap中的图层样式快速转换为可共享的 Styled Layer Descriptor (SLD) 格式,从而实现地图样...

GetSecurityInfo-程序员宅基地

文章浏览阅读2.5k次。ISecurityInformation::GetSecurity 该函数通过句柄找到某一对象,并获取该对象的安全描述符。DWORD GetSecurityInfo( HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID* ppsidOwner,_getsecurityinfo