Tuesday, January 2, 2024

Android java: Tutorial Parcelable, HttpURLConnection, background process Handler, ExecutorService and Message

 

Android Studio Hedgehog | 2023.1.1

Note: For personal reference using Parcelable, HttpURLConnection, background process Handler, ExecutorService and Message in java

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- internet connection -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
...

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
    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"
    android:orientation="vertical"
    >
    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button_1"
        android:text="Thread"
        android:contentDescription="Thread"
        />
    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/button_2"
        android:text="Google"
        android:contentDescription="Google"
        />
    <androidx.appcompat.widget.AppCompatTextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textview_1"
        android:layout_weight="1"
        />
</androidx.appcompat.widget.LinearLayoutCompat>

MyThread.java 

package com.dedetok.tutorialthread;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyThread {

    ExecutorService executor = Executors.newSingleThreadExecutor();
    //ExecutorService executor = Executors.newFixedThreadPool(10);

    public void getMsg(Handler mainHandler) {
        Log.e("dedetok","getMsg called"); //debug
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                Log.e("dedetok","getMsg run"); //debug

                Message msg = Message.obtain(); // null
                Bundle bundle = new Bundle();
                bundle.putString(MainActivity.MYKEY, "Button Pressed");
                msg.setData(bundle);
                mainHandler.sendMessage(msg);
            }
        };
        executor.submit(myRunnable);
    }
}

MyDataModelParcel.java

package com.dedetok.tutorialthread;

import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;

public class MyDataModelParcel implements Parcelable {

    // https://www.vogella.com/tutorials/AndroidParcelable/article.html

    public String myString;

    public MyDataModelParcel(String myString) {
        this.myString = myString;
    }

    // -----------------------------------
    // implementation Parcelable START
    // -----------------------------------

    protected MyDataModelParcel(Parcel in) {
        // need implementation
        // must be write in order
        this.myString = in.readString();
    }

    // Required implement Parcelable generated by android studio
    public static final Creator<MyDataModelParcel> CREATOR = new Creator<MyDataModelParcel>() {
        @Override
        public MyDataModelParcel createFromParcel(Parcel in) {
            return new MyDataModelParcel(in);
        }

        @Override
        public MyDataModelParcel[] newArray(int size) {
            return new MyDataModelParcel[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel parcel, int i) {
        // need implementation
        // must be write in order MyDataModelParcel(Parcel in)
        parcel.writeString(this.myString);
    }

    // -----------------------------------
    // implementation Parcelable END
    // -----------------------------------

}

MainActivity.java 

package com.dedetok.tutorialthread;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import androidx.appcompat.widget.AppCompatTextView;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    // https://www.answertopia.com/android-studio/an-overview-of-java-threads-handlers-and-executors-in-android/
    // https://stackoverflow.com/questions/42475812/communication-between-ui-thread-and-other-threads-using-handler

    AppCompatTextView myTV1;

    public static final String MYKEY = "dedetok";
    public static final String MYKEY1 = "google";

    // UI Main Handler
    Handler myUIHandler = null;

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

        myTV1 = findViewById(R.id.textview_1);

        AppCompatButton myBut1 = findViewById(R.id.button_1);
        myBut1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e("dedetok","onClick"); //debug
                new MyThread().getMsg(myUIHandler);
            }
        });

        AppCompatButton myBut2 = findViewById(R.id.button_2);
        myBut2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e("dedetok","onClick"); //debug
                MyNetRepository.getRequest(myUIHandler,
                        MyNetRepository.MY_METHOD_GET,
                        "https://www.google.com",
                        null);
            }
        });

        // put at end to make sure view has created
        myUIHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);

                Log.e("dedetok","handling message"); //debug

                Bundle msgBundle = msg.getData();
                String myString = msgBundle.getString(MYKEY);
                MyDataModelParcel myParcel = msgBundle.getParcelable(MYKEY1);

                if (myParcel!=null) {
                    myTV1.setText(myParcel.myString);
                }
                if (myString!=null) {
                    myTV1.setText(myString);
                }
            }
        };
    }
}

MyNetRepository.java

package com.dedetok.tutorialthread;

import static java.net.HttpURLConnection.HTTP_OK;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyNetRepository {

    private final static String USER_AGENT = "Mozilla/5.0";

    public static final int MY_METHOD_GET = 1;
    public static final int MY_METHOD_POST = 2;

    ExecutorService executor = Executors.newSingleThreadExecutor();
    //ExecutorService executor = Executors.newFixedThreadPool(10);

    // prevent accidentally instantiate
    private MyNetRepository() {
        if (executor==null) {
            executor = Executors.newSingleThreadExecutor();
        }
    }

    /*
     * Handler myMainUIHandler is from main UI thread
     * String myURLString url e.q http://www.google.com or https://www.google.com
     * Map<String,String> myRequestParameters
     *      for method POST it is key val string e.q name myname
     *      for method GET, set null
     */
    public static void getRequest(Handler myMainUIHandler,
                                                  int myMethodRequest,
                                                  String myURLString,
                                                  Map<String,String> myRequestParameters) {
        MyNetRepository myNetRepository = new MyNetRepository();
        Log.e("dedetok","getMsg called"); //debug
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                String doMyNetworkJobString = doMyNetworkJob(myMethodRequest,
                        myURLString,
                        myRequestParameters);

                // send back result or process result before updating UI
                Message msg = Message.obtain(); // null
                Bundle bundle = new Bundle();
                //bundle.putString(MainActivity.MYKEY1, doMyNetworkJobString);
                bundle.putParcelable(MainActivity.MYKEY1, new MyDataModelParcel(doMyNetworkJobString));
                msg.setData(bundle);
                myMainUIHandler.sendMessage(msg);

            }
        };
        myNetRepository.executor.submit(myRunnable);
    }

    private static String doMyNetworkJob(int myMethodRequest,
                                  String myURLString,
                                  Map<String,String> myRequestParameters) {
        Log.e("dedetok","getMsg run"); //debug

        try {
            URL url = new URL(myURLString);

            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestProperty("User-Agent", MyNetRepository.USER_AGENT);

            if (myMethodRequest==MY_METHOD_POST) {
                urlConnection.setRequestMethod("POST");
                // to send data POST request
                // Don't need to set if GET request
                urlConnection.setDoOutput(true);
                java.io.OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
                // Iterating HashMap through for loop
                StringBuilder requestParameters = new StringBuilder();
                boolean firstData=true;
                for (Map.Entry<String, String> mySet :
                        myRequestParameters.entrySet()) {
                    if (!firstData) {
                        requestParameters.append("&");
                    } else {
                        firstData=false;
                    }
                    requestParameters.append(mySet.getKey());
                    requestParameters.append("=");
                    requestParameters.append(mySet.getValue());
                }
                byte[] dataPostRequestBytes = requestParameters.toString().getBytes();
                out.write(dataPostRequestBytes);
                out.flush();
                out.close();
                // end to send data post
            }
            if (myMethodRequest==MY_METHOD_GET) {
                urlConnection.setRequestMethod("GET");
            }

            // get status request if HTTP_OK process
            StringBuilder mySB = new StringBuilder(); // temp string response
            if (urlConnection.getResponseCode() == HTTP_OK) {
                // get respon from server
                InputStream in = new BufferedInputStream(urlConnection.getInputStream());
                BufferedReader myBR = new BufferedReader(new InputStreamReader(in));

                String tmpString = myBR.readLine();
                while (tmpString != null) {
                    mySB.append(tmpString);
                    tmpString = myBR.readLine();
                }
            } else {
                mySB.append("Error code: ");
                mySB.append(+urlConnection.getResponseCode());
            }

            Log.e("dedetok", mySB.toString()); // debug
            // disconnect
            urlConnection.disconnect();
            return mySB.toString();

        } catch (IOException e) {
            return e.getMessage();
        }
    }
}

NOTE:

Primitive data type accepted bellow Android 10/Q (<API 29)

writeByte(byte), readByte(), writeDouble(double), readDouble(), writeFloat(float), readFloat(), writeInt(int), readInt(), writeLong(long), readLong(), writeString(String), readString()

 

 

No comments:

Post a Comment