Sunday 13 October 2019

Post 78: Syntax highlighting on Blogger

<pre class="brush: xml;">
<!-- escaped code here. For example: -->
<!-- https://www.freeformatter.com/html-escape.html -->
</pre>

Post 77: Percentage vertical layout

Percentagelayout is deprecated in Android, but you can achieve the same results with LinearLayout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

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

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="40"
            android:orientation="vertical">
            <Button
                android:id="@+id/btnPlayer2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="Button" />

        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="20"
            android:orientation="vertical">
            <Button
                android:id="@+id/btnStart"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="Button" />

        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="40"
            android:orientation="vertical">

            <Button
                android:id="@+id/btnPlayer1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="Button" />

        </LinearLayout>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Friday 4 October 2019

Post 76: Read from local resource in Android

In this post I'll show you how to read from local resource in Android. In this case it's a text file "text_file.txt" in the folder "raw" under the "res" folder.

private final Context helperContext = this; // put this on top of your class
....

final Resources resources = helperContext.getResources();
InputStream inputStream = resources.openRawResource(R.raw.text_file);

BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

try {
    String line = "";
    while ((line = reader.readLine()) != null) {
       System.out.println(line);
       // do something..., e.g. add in to an ArrayList
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Post 75: Fetching data from Android app

Sometimes you want to fetch data from an API on some webserver from your Android app. Let say the server's adress is http://my-requested-data.com and let's say it returns you data in json format. This is how you do it:

        String url = "http://my-requested-data.com/?format=json";
       
        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        // optional default is GET
        con.setRequestMethod("GET");
        //add request header
        con.setRequestProperty("User-Agent", "Mozilla/5.0");
        int responseCode = con.getResponseCode();

        BufferedReader in = new BufferedReader(
                new InputStreamReader(con.getInputStream()));
        String inputLine;
        StringBuffer response = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();

        //Read JSON response and print
        JSONObject myResponse = new JSONObject(response.toString());
//Access node from the json object:
        float finalResult = Float.parseFloat(myResponse.getString("some_predicate"));

Post 74: Convert datasets in text file into json file with python

Sometimes you want to convert datasets from text file to json.

Let's say you have the following input text file:

 Japan 83.74 80.91 86.58
 Italy 83.31 80 86.49
 Switzerland 82.84 80.27 85.23
 Singapore 82.66 80.43 84.74
 Israel 82.64 79.59 85.61
 Iceland 82.3 80.73 83.84
 Spain 82.28 79.42 85.05
 Australia 83.42 80.33 86.56
 Hong Kong 82.07 80.18 83.82
 Sweden 81.93 80.1 83.71
 France (metropol.) 81.85 78.76 84.87
 Canada 81.78 79.69 83.78
...

The datasets above have 4 columns. The first column has also a heading space that we need to get rid of. The columns are separated by tabs (\t) and each line is sepearted by line breaks (\n). To convert this datasets into and json output file, we write the following python script:

import json
import re

f=open("input.txt", "r")

arr = []
jsonResult = []

if f.mode == 'r':
    contents =f.read()
    arr = re.split(r'\n+', contents)
    print(arr)

arr = arr[:-1] # remove last element

for x in arr:
    line = re.split(r'\t+', x)
    print(line)
    country = line[0].strip() # remove heading and trailing spaces spaces
    expected_age_overall = line[1]
    expected_age_male = line[2]
    expected_age_female = line[3]
    json_item = {
        "country": country,
        "expected_age_overall": expected_age_overall,
        "expected_age_male": expected_age_male,
        "expected_age_female": expected_age_female
    }
    jsonResult.append(json_item)

 
print(jsonResult) # display the result

with open('output.json', 'w') as json_file:
    json.dump(jsonResult, json_file)


Friday 27 September 2019

Post 73: How to create Android app that persistently saves custom objects

In almost any app you need to persistently save custom information in your app and later load it and display it to the user. Unfortunately Android doesn't provide you this functionality out of the box. Therefore in this tutorial I'll show you how to create an app that persistently saves custom objects with gson.
I'll use:

  1. Android studio
  2. android 28
  3. gson
  4. gradle


In it is mainly based on this post:

https://codinginflow.com/tutorials/android/save-arraylist-to-sharedpreferences-with-gson

But because some API has changed (for this have a look here: https://developer.android.com/jetpack/androidx/migrate/class-mappings) since then you won't be able to create an app if you follow the above mentioned tutorial. It took me a while to get it going. In order to save time, I create this tutorial for you. Also I added some additional information that was not mentioned in my reference post and that may be helpful for beginners.

First create a new app via android studio select the empty app template and call it "MyApplication".

Then add the following dependencies into your build.gradle file:

dependencies {
implementation 'com.android.support:design:28.0.+'
implementation 'com.google.code.gson:gson:2.8.5'
}

We need for our UI some designs that is not provided by the standard android SDK. Therefore we have to add the design dependency:
implementation 'com.android.support:design:28.0.+'

Google provides you with gson methods you can use to serialize and deserialize java objects
https://github.com/google/gson

Mind you, the number 28 in i.e. 'com.android.support:design:28.0.+' refers to your target SDK version. make sure that these are always the same number. In my example it's 28. Your's may differ. In order to know which target version you are using, you can also check in your gradle-file:

android {
    compileSdkVersion 28
    defaultConfig {
...
        targetSdkVersion 28
...
    }
}

Once you have added the above dependencies, click on the "sync" (at the top right corner) so gradle can download the needed dependencies.

The next step is to design our main layout. We want two input fields where we type in some data (that we will alter save) and two buttons: Insert and save. The Insert button inserts our newly created object into the list displayed in the main view. The save button saves it persistently on our app. In the "layout" folder write inside the "activity_main.xml" file this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="de.pandaquests.myapplication.MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="100dp"
        android:background="@android:color/darker_gray" />

    <EditText
        android:id="@+id/edittext_line_1"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="52dp"
        android:hint="Line 1" />

    <EditText
        android:id="@+id/edittext_line_2"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentBottom="true"
        android:hint="Line 2" />

    <Button
        android:id="@+id/button_insert"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/edittext_line_1"
        android:layout_marginStart="13dp"
        android:layout_marginTop="23dp"
        android:layout_toEndOf="@id/edittext_line_1"
        android:text="insert" />

    <Button
        android:id="@+id/button_save"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/button_insert"
        android:layout_toEndOf="@+id/button_insert"
        android:text="save" />

</RelativeLayout>

Next is we create the UI for our custom element. The custom element represents the data we insert into the list. Create in the "layout" folder a file named "example_item.xml" by right clicking and choose new -> Layout resource file. Write "example_item.xml" as the name and ignore the rest, because we will overwrite everything insdie of that file with the following code inside of it:

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="4dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="4dp">

        <TextView
            android:id="@+id/textview_line1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Line 1"
            android:textColor="@android:color/black"
            android:textSize="20sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/textview_line_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/textview_line1"
            android:layout_marginStart="8dp"
            android:text="Line 2"
            android:textSize="15sp" />

    </RelativeLayout>

</androidx.cardview.widget.CardView>

Once we are done with that, we will create the needed functionality for our main activity. Inside the "MainActivity.java" file write the following:

package de.pandaquests.myapplication;

import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    ArrayList<ExampleItem> mExampleList;
    private RecyclerView mRecyclerView;
    private ExampleAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

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

        loadData();
        buildRecyclerView();
        setInsertButton();

        Button buttonSave = findViewById(R.id.button_save);
        buttonSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                saveData();
            }
        });
    }

    private void saveData() {
        SharedPreferences sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        Gson gson = new Gson();
        String json = gson.toJson(mExampleList);
        editor.putString("task list", json);
        editor.apply();
    }

    private void loadData() {
        SharedPreferences sharedPreferences = getSharedPreferences("shared preferences", MODE_PRIVATE);
        Gson gson = new Gson();
        String json = sharedPreferences.getString("task list", null);
        Type type = new TypeToken<ArrayList<ExampleItem>>() {}.getType();
        mExampleList = gson.fromJson(json, type);

        if (mExampleList == null) {
            mExampleList = new ArrayList<>();
        }
    }

    private void buildRecyclerView() {
        mRecyclerView = findViewById(R.id.recyclerview);
        mRecyclerView.setHasFixedSize(true);
        mLayoutManager = new LinearLayoutManager(this);
        mAdapter = new ExampleAdapter(mExampleList);

        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
    }

    private void setInsertButton() {
        Button buttonInsert = findViewById(R.id.button_insert);
        buttonInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EditText line1 = findViewById(R.id.edittext_line_1);
                EditText line2 = findViewById(R.id.edittext_line_2);
                insertItem(line1.getText().toString(), line2.getText().toString());
            }
        });
    }

    private void insertItem(String line1, String line2) {
        mExampleList.add(new ExampleItem(line1, line2));
        mAdapter.notifyItemInserted(mExampleList.size());
    }
}


You'll probably see lots of erros. But don't worry it's because there are still files missing. Next we create the "ExampleAdapter.java". Create in your project folder (the folder where also your MainActiviy.java file is) a file named "ExampleAdapter.java"

package de.pandaquests.myapplication;

import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> {
    private ArrayList<ExampleItem> mExampleList;

    public static class ExampleViewHolder extends RecyclerView.ViewHolder {
        public TextView mTextViewLine1;
        public TextView mTextViewLine2;

        public ExampleViewHolder(View itemView) {
            super(itemView);
            mTextViewLine1 = itemView.findViewById(R.id.textview_line1);
            mTextViewLine2 = itemView.findViewById(R.id.textview_line_2);
        }
    }

    public ExampleAdapter(ArrayList<ExampleItem> exampleList) {
        mExampleList = exampleList;
    }

    @Override
    public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.example_item, parent, false);
        ExampleViewHolder evh = new ExampleViewHolder(v);
        return evh;
    }

    @Override
    public void onBindViewHolder(ExampleViewHolder holder, int position) {
        ExampleItem currentItem = mExampleList.get(position);

        holder.mTextViewLine1.setText(currentItem.getLine1());
        holder.mTextViewLine2.setText(currentItem.getLine2());
    }

    @Override
    public int getItemCount() {
        return mExampleList.size();
    }
}

Now we only need our custom Object. Let's create "ExampleItem.java" file in your project folder and paste in the following code:

package de.pandaquests.myapplication;
public class ExampleItem {
    private String mLine1;
    private String mLine2;

    public ExampleItem(String line1, String line2) {
        mLine1 = line1;
        mLine2 = line2;
    }

    public String getLine1() {
        return mLine1;
    }

    public String getLine2() {
        return mLine2;
    }
}

We should now be set. Press on run and you should see a working sample app that saves custom data.

If you like it, then please share it with others.

You can download the app here from my gitHub and tweak it as you like:
https://github.com/pandaquests/AndroidSaveData

Use it as a base for your own projects. If you want, then tell me what projects you intend or have done with. I'm really curious to know. So long

Thursday 26 September 2019

Post 72: How to create evenly divided buttons that fills the entire space of the viewport on Android apps

I had to try different layout and read through several Stackoverflow posts until I could achieve what I wanted: buttons evenly spread on the viewport. At first I thought you can easily achieve that with a GridLayout. But no, you can achieve this with nested LinearLayout:

<?xml version="1.0" encoding="utf-8"?>
    <!--tools:showIn="@layout/activity_test_widget"-->
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="test.TodoWidget">

    <LinearLayout
        android:layout_width="368dp"
        android:layout_height="439dp"
        android:orientation="vertical"
        app:layout_constraintVertical_weight="1"
        tools:layout_editor_absoluteY="8dp"
        tools:layout_editor_absoluteX="8dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal">

            <EditText
                android:id="@+id/editTextTaskInput"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:hint="test"
                android:ems="10"
                android:inputType="textMultiLine" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            app:layout_constraintHorizontal_weight="1"
            android:orientation="horizontal">

            <Button
                android:id="@+id/b1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:text="b1" />

            <Button
                android:id="@+id/b2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:text="b2" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            app:layout_constraintHorizontal_weight="1"
            android:orientation="horizontal">
            <Button
                android:id="@+id/b3"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:text="b3" />
            <Button
                android:id="@+id/b4"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:text="b4" />
        </LinearLayout>
    </LinearLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/nextButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_media_next"
        android:layout_weight="1"
        app:layout_constraintBottom_toBottomOf="parent"

        app:layout_constraintEnd_toEndOf="parent"
        tools:layout_editor_absoluteX="328dp" />

</android.support.constraint.ConstraintLayout>

Sunday 8 September 2019

Post 71: Publish gitHub page with VueJS + Vue cli


  1. Create a project on gitHub
  2. clone that gitHub project on your computer with `git clone ...`
  3. in your terminal, go to that project with `cd .....`
  4. create a vue project in that folder with `vue create .`
  5. install all dependencies `yarn install`
  6. in the `.gitignore` file comment out the folder `/dist` (we will later publish our vueJS page in that `dist` folder and push it on gitHub)
  7. create a new branch with `git co -b gh-pages`
  8. create a new file `vue.config.js` with `touch vue.config.js`
  9. in that file write: module.exports = { publicPath: ‘<my-project>’ }
  10. modify the changes you want to make
  11. test your changes with `yarn serve`
  12. if you are satisfied we can build for production with `yarn build`
  13. add the changes you want to push: `git add dist && git commit -m "Initial dist subtree commit`
  14. push only the dist folder to your gh-branch on gitHub: `git subtree push --prefix dist origin gh-pages`. This part is very important. If you push everything into gitHub, then nothing will be displayed. The trick is to only push the `dist` folder on to gitHub. In order not to lose any changes, I would commit and push everything to `master` and on the branch `gh-pages`, I'd only push the `dist` changes  
  15. go to gitHub and then to the settings
  16. in the section gitHub pages you should see a link where your vueJS can be reached. Click on that and you should see the same page you see earlier with `yarn serve` 

Tuesday 27 August 2019

Post 70: Remove blue background on form input fields in Chrome

Chrome adds a default blue background color in your form input fields, e.g. text fields or password input fields.

In order to remove it apply this styling

<style>  input:-webkit-autofill,  input:-webkit-autofill:hover,  input:-webkit-autofill:focus textarea:-webkit-autofill,  textarea:-webkit-autofill:hover textarea:-webkit-autofill:focus,  select:-webkit-autofill,  select:-webkit-autofill:hover,  select:-webkit-autofill:focus {
    transition: background-color 5500s ease-in-out 0s;  }
</style>
Tweet