2015/11/12

Android 土炮閱讀小說(Txt)App

有位朋友請我幫他寫一個能看小說的App,僅提供格式為Txt,並沒有限制長度大小
想了一下就土炮出第一版,是直接將內容讀取完畢,不過等待跑完約莫30秒了Orz
所以將其改為初始讀取20行,使用者滑動卷軸時會讀取5行,這樣的方式讀取的時間會比較久,不過這樣較為符合朋友的需求吧XDDDD
不然30秒後才看得到小說也太悲劇XD

不過App有錯請見諒,與周公有約XD


XML:
<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="com.cyfang.textreader.MainActivity" >

    <ScrollView
        android:id="@+id/scrollView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/textView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:singleLine="false" />

        </LinearLayout>
    </ScrollView>

</RelativeLayout>





Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cyfang.textreader"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="14" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" android:largeHeap="true">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Code:
package com.cyfang.textreader;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

 /** 卷軸 */
 private ScrollView scrollView;

 /** 小說 */
 private TextView textView;

 /** 小說清單 */
 private String[] files;

 /** 小說預設路徑 */
 private final String PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/小說/";

 /** 資料夾 */
 private File file = new File(PATH);

 /** 讀取路徑 */
 private String currentReadPath = "";

 /** 文字大小 */
 private static int fontSize = 16;

 /** 讀取長度 */
 private static int readLength = 20;

 /** 讀取小說 */
 private static BufferedReader reader;

 /** 第一次執行 */
 private static Boolean isFirst = false;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  // 建立小說資料夾
  file.mkdirs();
  textView = (TextView) findViewById(R.id.textView);
  // 設定文字大小
  textView.setTextSize(fontSize);
  scrollView = (ScrollView) findViewById(R.id.scrollView1);
  // 卷軸在捲動時再繼續讀取資料近來
  scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
   @Override
   public void onScrollChanged() {
    try {
     if (isFirst)
      readContent();
    } catch (NullPointerException e) {
     isFirst = false;
     readLength = 20;
     Toast.makeText(MainActivity.this, "已經讀取完畢了喔", 1).show();
    } catch (IOException e) {
     Toast.makeText(MainActivity.this, "讀取錯誤", 1).show();
    }

   }
  });

  // 沒有選取小說則讓跳出選擇視窗
  if (currentReadPath.equals(""))
   showChoiceFile();

 }

 /** 讀取小說 */
 private void readContent() throws NullPointerException, IOException {
  if (reader == null)
   throw new NullPointerException();

  String str = reader.readLine();
  for (int index = 0; index < readLength; index++) {
   if (str == null) {
    reader.close();
    break;
   } else {
    textView.append(str + "\n");
    str = reader.readLine();
   }
  }

  if (!isFirst) {
   readLength /= 4;
   isFirst = true;
  }
 }

 private void showChoiceFile() {
  File[] files = file.listFiles();
  if (files == null) {
   Toast.makeText(MainActivity.this, "你的檔案沒有任何檔案喔!", 1).show();
   return;
  }

  if (this.files == null) {
   this.files = new String[files.length];
   for (int index = 0; index < files.length; index++) {
    this.files[index] = files[index].getAbsolutePath();
   }
  }

  new AlertDialog.Builder(MainActivity.this).setNegativeButton("閱讀", new OnClickListener() {

   @Override
   public void onClick(DialogInterface dialog, int which) {
    try {
     reader = new BufferedReader(new InputStreamReader(new FileInputStream(currentReadPath), "UTF-8"));
     readContent();
    } catch (UnsupportedEncodingException e) {
     Toast.makeText(MainActivity.this, "編碼並非為UTF8", 1).show();
    } catch (FileNotFoundException e) {
     Toast.makeText(MainActivity.this, "找不到該檔案", 1).show();
    } catch (IOException e) {
     Toast.makeText(MainActivity.this, "讀取錯誤", 1).show();
    }

   }
  }).setSingleChoiceItems(this.files, 0, new OnClickListener() {

   @Override
   public void onClick(DialogInterface dialog, int which) {
    currentReadPath = MainActivity.this.files[which];
   }
  }).show();

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   showChoiceFile();
   return true;
  } else if (id == R.id.action_Add) {
   fontSize += 2;
   textView.setTextSize(fontSize);
   return true;
  } else if (id == R.id.action_Sub) {
   fontSize -= 2;
   textView.setTextSize(fontSize);
   return true;
  }
  return super.onOptionsItemSelected(item);
 }
}



執行結果: