Published Date : 2021年1月31日10:22

2. 賃金階級年齢階級別労働者割合のアンドロイドアプリ
2. Android application for ratio of workers by wage class and age group


This blog has an English translation


ニコニコ動画にアップした動画のまとめ記事です。

This is a summary blog post about a video I uploaded to NicoNico.

細かい部分は動画を参考にしてください。

Please refer to the video for details.


目次

Table of Contents




① 動画の説明
① Video Description



前回の続きです。

Continued from last time.

まずはアセットフォルダからアセットマネージャを利用してCSVファイルを開きます。

First, open the CSV file from the asset folder using the asset manager.

AssetManager assetManager = context.getResources().getAssets();

トライアンドキャッチ文を使用して、ファイルが開けなかった時の処理も書きます。

It also uses a try catch statement to describe what happens when a file cannot be opened.

そしてインプットストリームリーダーを使用して、ファイルの中身のデータを連続したバイトとして取り込めるようにします。

It then uses the input stream reader to allow the data in the file to be captured as ordered sequence bytes.

そしてこのインプットストリームリーダーは文字を一文字ずつ取り込むことができます。

And this input stream reader can capture characters one by one.

漢字などのマルチバイト文字に有用で、コンストラクタに文字コードを指定することで、文字にデコードしてくれたりもします。

It is useful for multi-byte characters such as kanji, and can be decoded into characters by specifying character codes in constructors.

そのあと、そのインプットストリームをバッファードリーダーを使って、メモリ領域に一時的に蓄えることによって、ディスクインプットアウトプットを減らすことで変換効率を上げることができます。

You can then use a buffered reader to temporarily store the input stream in a memory area to improve conversion efficiency by reducing the disk input output.

そしてバッファードリーダーのリードラインメソッドを使用することによって、上記のクラスが連携してバイトの流れを文字として取り出し、そしてそれをメモリのバッファ領域へ蓄えてから、一行ずつまとめて取り出すことができるようになります。

By using the readline method of the buffered reader, the above classes can work together to retrieve a stream of bytes as characters, store them in a buffer of memory, and then retrieve them line by line.

InputStream inputStream = assetManager.open("table_7_2_2.csv");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferReader = new BufferedReader(inputStreamReader);

バッファードリーダーが最後の行を取得して処理を行ったあとに、ワイル文の先頭の条件式に戻り、何も行が存在しないnullをline変数に格納するので、その時点でワイル文を抜け出します。

After the buffered reader has retrieved and processed the last line, it returns to the conditional expression at the beginning of the while statement, and exits the while statement at that point because it stores a null with no lines in the line variable.

ワイル文の中では、1ループごとに新しく文字の配列変数を宣言します。

Within the while statement, declare a new string array variable for each loop.

そしてその変数にスプリットメソッドを使って一行をカンマで区切られた配列を格納します。

Then, uses the split method to store an array with rows separated by commas to the variable.

この一行ごとの配列がCSVファイルの行に相当します。

This line-by-line array corresponds to a row in the CSV file.

そして各行毎にヌルチェックをおこなって、新しく作成したアレイリストにリスト型に変換した文字列配列を格納します。

It then performs a null check on each line and stores the converted string array from string list in a newly created array list.

リストは新たに値を足したり削除したりすることができないので、簡単に足したり削除したりすることができるアレイに変換する必要があります。

You cannot add or delete new values from the list, so you need to convert it to an array that you can easily add or delete.

そして、ワイル文の外で定義したカウント変数を使って、最初の行、つまりCSVのヘッダー部分(年齢層)のみ別のメンバ変数に格納します。

It then uses the count variable defined outside of the while statement to store only the first row, That is, only the header portion of the CSV (age group) is stored in another member variable.

そこで使われているサブリストはPythonでいうスライスと同じ機能で、指定したインデックス間での配列の値を取り出してくれます。

The sublist used is equivalent to a slice in Python, it retrieves the array values between the specified indexes.

アレイリスト型はゲットメソッドを使って指定されたインデックスの値を取り出します。今回の配列の0番目はつまり賃金階級の列を表しています。

The array list type uses the get method to retrieve the value of the specified index. The 0 in this array represents the wage class.

そしてあとは、残りの割合を示す行の部分をCSVリストととしてメンバ変数に格納します。

Then, the remaining percentage of the line is stored in the member variable as a CSV list.

最後にバッファードリーダーをクローズする必要があるので忘れずに。

Finally, remember to close the buffered reader.

bufferReader.close();

[MainActivity.java]ファイルに戻り、ユーザーが[spinner]を使って値を選択できるようにするために必要なアダプターを作成する関数を別で作成します。

Return to the [MainActivity.java] file and You then create a separate function that creates the adapter needed to allow the user to select values using [spinner].

public void createAdapter(){
}

アダプターを使ってメインアクティビティレイアウトに用意したスピナーにドロップダウン選択のレイアウトをセットしましょう。

Let's set the layout of the drop-down selection to the spinner in the main activity layout by using the adapter.

そして賃金階級の割合の配列をゲッターを使って取り出し、Forループを使ってアダプターにセットしていきます。

You can then use a getter to get an array of wage class rates and use the For loop to set that value on the adapter.

デフォルトの値として配列の一番最初の値を使用するようにします。

Use the first value in the array as the default value.

このメソッドは計算ボタンが押されたら、選択された年齢と年収から賃金階級の割合を取り出すメソッドです。

This method extracts the wage class percentage from the selected age and annual income when the Calculate button is pressed.

public void calculatePercentage(View view) {
}

では[WageDriver.java]に実際に計算をするメソッドを作成していきましょう。

Now let's create a method that does the actual computation in [WageDriver.java].

public List<Object> calculatePercentage(int wageIndex, int ageIndex){
}

全ての結果を格納する為のアレイリスト変数を初期化し、その変数に選択された年齢や年収、計算結果等を格納していきます。

It initializes an array list variable to store all the results, and stores the selected age, annual income, calculation results, etc. in the variable.

リスト型にオブジェクト型を指定しているのは、このアレイリストには整数型や文字列型やリスト型が混在して格納される為です。

List types are specified as object types. This is because the array list contains a mix of integer, string, and list types.

通常ならば、初期化をする際に、どの型がリストに含まれるか予め宣言しておかなければ型エラーが起こります。

Normally, when initializing, a type error occurs if you do not predeclare which types are in the list.

しかし、このようにすれば様々な型が事前に決めておかなくてもリストに格納できるようになります。

This way, however, various types can be stored in the list without having to predetermine them.

続いて、選択された年齢層における平均年収を計算するための変数を作成します。

You then create a variable to calculate the average annual income for the selected age group.

イズエンプティメソッドはその変数が空であるかどうかを判定してくれます。別の判定方法はこのようになります。

The [is empty method] determines whether the variable is empty. Another method of determine is as follows.

フォーループの中で、選択された年収の幅から中間の値を求めて、その値に選択された年齢における割合を掛け合わせます。

Calculates the middle value of the selected salary range in the For Loop statement and multiplies it by the percentage of the selected age range.

余計な文字列を削除して、指定した文字で数値を二つに分けます。

Removes extra strings and splits the number into two with the given characters.

数値は文字列になっているので、パースフロートを使用して、フロートの値に戻してから計算する必要があります。

Because the number is a string, you must use parse float to return to the float value before you calculate it.

あとは計算結果の全てを先ほど用意した変数に格納して、その変数をメソッドの返り値とします。

Then, store all the results of the calculation in the variable you just prepared and use that variable as the return value of the method.

[MainActivity.java]ファイルに戻り、先ほどのメソッドから結果の値を取り出します。

Return to the [MainActivity.java] file and Get the result value from the previous method.

resultList = wageDriver.calculatePercentage(selectedWageIdx, selectedAgeIdx);

String percentage = (String) resultList.get(0);
String wage = (String) resultList.get(1);
String age = (String) resultList.get(2);

さらに強調したい文字列等があるため、その値を利用して結果の表示をHTMLに変換して表示させます。

Since there is a character string to be further emphasized, the display of the result is converted to HTML by using the value.

結果の表示が正常にされたら、指定された年齢層における賃金階級の割合の棒グラフを表示するアクティビティへの変移ボタンを表示させます。

If the results display successfully, display a transition button to an activity that displays a bar chart of the percentage of the wage class in the specified age group.

アクティビティへの変移ボタンが押された時の処理を行うメソッドを作成します。

Create a method to handle when the transition to activity button is pressed.

public void showChartBtn(View view) {
}

おなじみのインテントを使用していますが、前回の時と異なるのはアクティビティへ渡す値がアレイリスト型であることです。

The familiar [intent] is used here, but the difference from the last time is that the value passed to the activity is an array list type.

そこで通常の値の渡し方では上手くアクティビティへ値を渡せないので、渡す値をSerializableを使用してバイト配列としてメモリへ保存する必要があります。

The usual way of passing values is not good enough to pass values to the activity, so you need to use Serializable to store the passed values in memory as byte arrays.

こうすることで、異なる型を持った配列変数のインスタンスは別のアクティビティでも認識できるようになります。

This allows an instance of an array variable of a different type to be recognized by another activity.

つまり、この配列変数のインスタンスはメモリ内で直列化され保存されるので、それを取り出して復元できる状態にあるからです。

That is, an instance of this array variable is serialized and stored in memory so that it can be retrieved and restored.

Pythonのピックルを扱ったことのある人は直観的に理解できるかもしれません。

If you've ever worked with Python pickle, you might be able to understand it intuitively.

PythonピックルもPythonのオブジェクトをバイト列として直列化してファイルとして保存でき、別のPythonファイルからそのオブジェクトをそのままPythonオブジェクトととして復元できるからです。

The reason for this is that Python pickle can also serialize Python objects as a sequence of bytes and save them as a file, and then restore them directly as Python objects from another Python file.

それでは棒グラフを表示するアクティビティの[DisplayBarChart.java]へ移動して、送られた変数を取り出し、実際にグラフを表示させるクラスファイルにその値を入れる処理を書きましょう。

Now go to the [DisplayBarChart.java] of the activity that displays the bar chart, and write a process that takes the submitted variable and puts its value in the class file that actually displays the chart.

public class DisplayBarChart extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_display_bar_chart);

        Intent intent = getIntent();
        List<Object> receivedData = (List<Object>) intent.getSerializableExtra("SEND_DATA");


        DisplayView displayView = new DisplayView(this, receivedData);
        setContentView(displayView);
    }
}

では実際にグラフを表示させるクラスファイルの[DisplayView.java]を作成していきましょう。

Now let's create a class file [DisplayView.java] that will actually display the chart.

class DisplayView extends View {
}

パート3へと続く。

Continue to Part 3.



以上です。お疲れ様です。

That's all. Thank you for your hard work.