Here is comparison between database api in java android and jdbc in java standard edition
In java SE (JDBC) id can be retrive using jse ps.getGeneratedKeys() return long where ps is PreparedStatement.
My Experience Notes These pages contain my experiences using technology. All of the works are working properly at the time when they wrote. You may use them for any purposes.
Here is comparison between database api in java android and jdbc in java standard edition
Operation | Java Android | Java SE (JDBC) |
INSERT | Returns new row ID (long) | Returns affected rows (int) |
UPDATE | Returns affected rows (int) | Same |
DELETE | Returns affected rows (int) | Same |
In java SE (JDBC) id can be retrive using jse ps.getGeneratedKeys() return long where ps is PreparedStatement.
add permission in project
AndroidManifest.xml
<manifest ...>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
checkPermissions();
....
}
/*
* check permission to read contact and write shared folder Download
*/
private void checkPermissions() {
List<String> permissions = new ArrayList<>();
// 1. Android 13+ Notification Permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissions.add(Manifest.permission.POST_NOTIFICATIONS);
}
// API require string convert List<String> to String[];
requestPermissionLauncher.launch(permissions.toArray(new String[0]));
}
/*
* callback permission request
*/
private final ActivityResultLauncher<String[]> requestPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
// Handle Notification permission (Android 13+)
boolean notificationsGranted = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
notificationsGranted = result.getOrDefault(Manifest.permission.POST_NOTIFICATIONS, false);
}
});
create MyNotificationService.java class
public class MyNotificationService {
public static final String CHANNEL_ID = "id_string_channel"; // todo
public static final int NOTIF_ID = 123456; // todo
/*
* to send notification
*/
public static void sendNotification(Context context, String title, String message) {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder myNotifBuilder = getNotificationBuilder(context);
myNotifBuilder
.setContentTitle(title)
.setContentText(message);
notificationManager.notify(NOTIF_ID, myNotifBuilder.build());
}
/*
* get notification for foreground
*/
public static Notification getForegroundNotification(Context context) {
Notification myNotif = getNotificationBuilder(context).build();
return myNotif;
}
/*
* Helper that returns the BUILDER so you can customize it before building
*/
private static NotificationCompat.Builder getNotificationBuilder(Context context) {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
NotificationChannel notifChannel = new NotificationChannel(
CHANNEL_ID,
"Background Sync Service",
NotificationManager.IMPORTANCE_LOW
);
notificationManager.createNotificationChannel(notifChannel);
}
}
return new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_notify_sync)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(Notification.CATEGORY_SERVICE);
//.setOngoing(true); // can not swap away
}
}
use just portrait for phone and w600 for tablet (bigger screen)
for portrait (phone)
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
>
<!-- Top TextView -->
<TextView
android:id="@+id/top_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Your Title Here"
android:textSize="18sp"
android:textStyle="bold"
android:padding="12dp"
android:gravity="center"
android:background="#DDDDDD" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/my_fragment_container_main"
android:name="[Your java main fragment with full package name]"
android:layout_width="0dp"
android:layout_height="match_parent"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
for w600 tablet
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<!-- Top TextView -->
<TextView
android:id="@+id/top_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Your Title Here"
android:textSize="18sp"
android:textStyle="bold"
android:padding="12dp"
android:gravity="center"
android:background="#DDDDDD" />
<!-- Horizontal Content -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="3">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/my_fragment_container_left"
android:name="[Your java left fragment with full package name]"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:id="@+id/divider_line"
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#000000" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/my_fragment_container_main"
android:name="[Your java main fragment with full package name]"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
</LinearLayout>
in main activity on onCreate(Bundle savedInstanceState)
FragmentManager fragmentManager = getSupportFragmentManager();
public boolean isDualPane = false; // default is portrait
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
isDualPane = findViewById(R.id.my_fragment_container_left) != null;
// R.id.main id for root portrait & w600
// Load Fragments only if this is a fresh start (savedInstanceState == null)
// This prevents overlapping fragments during screen rotation
if (savedInstanceState == null) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
// If system loaded the w600 layout, load both Fragment
if (isDualPane) {
transaction.replace(R.id.my_fragment_container_left, new [Your java left fragment with full package name]);
transaction.replace(R.id.my_fragment_container_main, new [Your java main fragment with full package name]);
} else {
// default load main container
transaction.replace(R.id.my_fragment_container_main, new [Your java main fragment with full package name]);
}
transaction.commit();
}
....
Add this and fix
private void replaceFragment(int containerId,
Fragment fragment,
boolean addToBackStack) {
FragmentTransaction transaction =
getSupportFragmentManager().beginTransaction();
transaction.replace(containerId, fragment);
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
to implement onbackpresseddispatcher pattern code, see this https://dedetoknotes.blogspot.com/2026/01/android-java-onbackpresseddispatcher.html
wifi and some device require compile in debian depend on kernel version. this documentation is intended as a small guide to tidy up your system.
list of ii and rc status of package
# uname -r
6.12.63+deb13-amd64
# dpkg -l | grep linux-image
rc linux-image-6.1.0-33-amd64 6.1.133-1 amd64 Linux 6.1 for 64-bit PCs (signed)
rc linux-image-6.1.0-34-amd64 6.1.135-1 amd64 Linux 6.1 for 64-bit PCs (signed)
rc linux-image-6.1.0-37-amd64 6.1.140-1 amd64 Linux 6.1 for 64-bit PCs (signed)
rc linux-image-6.1.0-9-amd64 6.1.27-1 amd64 Linux 6.1 for 64-bit PCs (signed)
rc linux-image-6.12.38+deb13-amd64 6.12.38-1 amd64 Linux 6.12 for 64-bit PCs (signed)
rc linux-image-6.12.38+deb13-amd64-unsigned 6.12.38-1 amd64 Linux 6.12 for 64-bit PCs
rc linux-image-6.12.41+deb13-amd64 6.12.41-1 amd64 Linux 6.12 for 64-bit PCs (signed)
rc linux-image-6.12.41+deb13-amd64-unsigned 6.12.41-1 amd64 Linux 6.12 for 64-bit PCs
rc linux-image-6.12.43+deb13-amd64 6.12.43-1 amd64 Linux 6.12 for 64-bit PCs (signed)
rc linux-image-6.12.43+deb13-amd64-unsigned 6.12.43-1 amd64 Linux 6.12 for 64-bit PCs
rc linux-image-6.12.48+deb13-amd64 6.12.48-1 amd64 Linux 6.12 for 64-bit PCs (signed)
rc linux-image-6.12.48+deb13-amd64-unsigned 6.12.48-1 amd64 Linux 6.12 for 64-bit PCs
rc linux-image-6.12.57+deb13-amd64 6.12.57-1 amd64 Linux 6.12 for 64-bit PCs (signed)
ii linux-image-6.12.57+deb13-amd64-unsigned 6.12.57-1 amd64 Linux 6.12 for 64-bit PCs
ii linux-image-6.12.63+deb13-amd64 6.12.63-1 amd64 Linux 6.12 for 64-bit PCs (signed)
ii linux-image-amd64 6.12.63-1 amd64 Linux for 64-bit PCs (meta-package)
Note about rc and ii
we can conclude these packages are not used anymore but still exist in our system:
We can remove those packages which is kernel left over, using this command:
# dpkg -l | awk '/^rc linux-image/ {print $2}' | xargs dpkg --purge
(Reading database ... 180811 files and directories currently installed.)
Purging configuration files for linux-image-6.1.0-33-amd64 (6.1.133-1) ...
Purging configuration files for linux-image-6.1.0-34-amd64 (6.1.135-1) ...
Purging configuration files for linux-image-6.1.0-37-amd64 (6.1.140-1) ...
Purging configuration files for linux-image-6.1.0-9-amd64 (6.1.27-1) ...
dpkg: warning: while removing linux-image-6.1.0-9-amd64, directory '/lib/modules' not empty so not removed
Purging configuration files for linux-image-6.12.38+deb13-amd64 (6.12.38-1) ...
Purging configuration files for linux-image-6.12.38+deb13-amd64-unsigned (6.12.38-1) ...
rmdir: failed to remove '/lib/modules/6.12.38+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.41+deb13-amd64 (6.12.41-1) ...
Purging configuration files for linux-image-6.12.41+deb13-amd64-unsigned (6.12.41-1) ...
rmdir: failed to remove '/lib/modules/6.12.41+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.43+deb13-amd64 (6.12.43-1) ...
Purging configuration files for linux-image-6.12.43+deb13-amd64-unsigned (6.12.43-1) ...
rmdir: failed to remove '/lib/modules/6.12.43+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.48+deb13-amd64 (6.12.48-1) ...
Purging configuration files for linux-image-6.12.48+deb13-amd64-unsigned (6.12.48-1) ...
rmdir: failed to remove '/lib/modules/6.12.48+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.57+deb13-amd64 (6.12.57-1) ...
I: /vmlinuz is now a symlink to boot/vmlinuz-6.12.63+deb13-amd64
I: /initrd.img is now a symlink to boot/initrd.img-6.12.63+deb13-amd64
rmdir: failed to remove '/lib/modules/6.12.57+deb13-amd64': Directory not empty
Assume:
Install unbound
# apt-get install unbound
Edit /etc/systemd/resolved.conf and set:
[Resolve]
DNS=127.0.0.1:5335
Domains=~.
Make sure this line in /etc/unbound/unbound.conf
...
include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"
...
Create and edit /etc/unbound/unbound.conf.d/google-doh.conf
server:
# Port 5335 is safer for laptops than 5353 (mDNS)
port: 5335
interface: 127.0.0.1
access-control: 127.0.0.0/8 allow
# Required for TLS verification
tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"
forward-zone:
name: "."
# Using DoT (Port 853) instead of DoH (Port 443)
forward-tls-upstream: yes
forward-addr: 8.8.8.8@853#dns.google
forward-addr: 8.8.4.4@853#dns.google
Enable unbound and restart all services
# systemctl enable unbound
# systemctl start unbound
# systemctl restart systemd-resolved
# systemctl restart NetworkManager
Test
# resolvectl query google.com
google.com: 172.253.118.138
172.253.118.102
172.253.118.101
172.253.118.113
172.253.118.139
172.253.118.100
2404:6800:4003:c11::8a
2404:6800:4003:c11::71
2404:6800:4003:c11::64
2404:6800:4003:c11::8b
# resolvectl query duckduckgo.com
duckduckgo.com: 20.43.161.105
-- Information acquired via protocol DNS in 54.3ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network