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()