In the previous post, after managing to scrape all the posts from a specific user from Lang8, I've created a Python GUI desktop application to read them in a more convenient way.
So now, I'm gonna show you how to create the same application, but on Android. Start with the official tutorial for learning basics Android concept.
It's a small and simple application, but helps me a lot to improve my Japanese by daily reviewing these posts on my smartphone.
Here's how it looks like :
Pretty similar to the desktop version isn't it ?
Here's the code for the MainActivity.java :
package com.example.lang8yoo;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Random;
import java.util.Scanner;
public class MainActivity extends Activity {
TextView currentPageDisplay;
EditText pageSearchLine;
Button pageSearchButton;
TextView textView;
Button previousButton;
Button randomButton;
Button nextButton;
public int current_page_index;
public int entries_total;
public String lastReadEntryIndex_FILE = "lastReadEntryIndex.txt";
public int last_read_entry_index;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
currentPageDisplay = (TextView) findViewById(R.id.currentPageDisplay);
pageSearchLine = (EditText) findViewById(R.id.pageSearchLine);
pageSearchButton = (Button) findViewById(R.id.pageSearchButton);
textView = (TextView) findViewById(R.id.textView);
previousButton = (Button) findViewById(R.id.previousButton);
randomButton = (Button) findViewById(R.id.randomButton);
nextButton = (Button) findViewById(R.id.nextButton);
try {
entries_total = getAssets().list("yamasvEntries").length;
BufferedReader br = new BufferedReader(new
InputStreamReader(openFileInput(lastReadEntryIndex_FILE)));
last_read_entry_index = Integer.parseInt(br.readLine());
br.close();
updateScreenWith(last_read_entry_index);
} catch (IOException e) {
e.printStackTrace();
}
}
public void randomPageDisplay(View view) throws IOException {
int random_page_index = new Random().nextInt(entries_total+1)+1;
updateScreenWith(random_page_index);
}
public void nextPageDisplay(View view) throws IOException {
int next_page_index = current_page_index < entries_total ? current_page_index + 1 : current_page_index;
updateScreenWith(next_page_index);
}
public void previousPageDisplay(View view) throws IOException {
int previous_page_index = current_page_index > 1 ? current_page_index - 1 : current_page_index;
updateScreenWith(previous_page_index);
}
public void searchPage(View view) throws IOException {
if (TextUtils.isDigitsOnly(pageSearchLine.getText())) {
int page_to_search_index = Integer.parseInt(pageSearchLine.getText().toString());
if (1 <= page_to_search_index && page_to_search_index <= entries_total){
updateScreenWith(page_to_search_index);
}
}
}
public void updateScreenWith(int page_to_display_index) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(
getAssets().open("yamasvEntries/" + page_to_display_index + ".txt")));
String page_to_display_text = "";
String entry_line;
while ((entry_line = br.readLine()) != null ){
page_to_display_text += entry_line + "\n";
}
br.close();
textView.setTextSize(22);
textView.setText(page_to_display_text);
current_page_index = page_to_display_index;
currentPageDisplay.setText(current_page_index+"/"+entries_total);
// Android can't write the assets folder read-only files,
// instead it create/write file on internal storage with openFileOutput
FileOutputStream outputStream;
try {
outputStream = openFileOutput(lastReadEntryIndex_FILE, Context.MODE_PRIVATE);
outputStream.write(Integer.toString(current_page_index).toString().getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
And here's the activity_main.xml layout main file :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
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.example.lang8yoo.MainActivity"
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true" >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:weightSum="1">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_weight="0.02">
<TextView
android:text="80/1520"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/currentPageDisplay"
android:layout_weight="1"
android:textSize="24sp" />
<EditText
android:layout_width="70dp"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:id="@+id/pageSearchLine"
android:layout_weight="0.15" />
<Button
android:text="Search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/pageSearchButton"
android:textSize="14sp"
android:onClick="searchPage"/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="489dp">
<TextView
android:text="Lang8 yoo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:layout_weight="1.07" />
</ScrollView>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="67dp">
<Button
android:text="Previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/previousButton"
android:layout_weight="1"
android:textSize="14sp"
android:onClick="previousPageDisplay"/>
<Button
android:text="Random"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/randomButton"
android:layout_weight="1"
android:textSize="14sp"
android:onClick="randomPageDisplay"/>
<Button
android:text="Next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/nextButton"
android:layout_weight="1"
android:textSize="14sp"
android:onClick="nextPageDisplay"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
The code itself is pretty similar to the Python version one. So, I stored the 1520 scraped entries files in a folder. With Android, you have to store all your static files under a folder called assets that you have to create beforehand, which is located at
But to 'remember' the last entry number I've read, I have to store the entry index somewhere, in a file like in the desktop version, so that the next time I open the app, it's gonna read the entry index and display the corresponding entry.
But one thing to note: in Android, statics files stored in the assets folder can only be read and not writed ! So, it's not possible to write in a file in the assets folder since the APK file is not extensible in size or something like that, so you have to write in a file located on the internal storage. This is done in the last part of the code in the MainActivity.java.
And if you are interested, here is the APK file for the simple Android application to read these entries.
All credit goes to yamasv, I post the app here with his approval :)
For the complete code, please check my GitHub repository.
© 2020, Philippe Khin