Android定时检测MySQL新数据并推送通知的实现求助
Hey there! Let's figure out why your periodic database check isn't working and fix it up. First, let's recap your problem clearly, then break down the issues in your current code, and finally walk through a reliable solution.
I'm building a simple Android app that needs to check a MySQL database every 2 minutes for new data, then display that data in notifications. I've tried using the sev_data IntentService below, but it never works. The database itself runs fine, though I can't view your attached screenshots right now.
My Existing Code
sev_data.java
public class sev_data extends IntentService { public static boolean ServiceIsRun = false; public sev_data() { super("MyWebRequestService"); } @Override protected void onHandleIntent(@Nullable Intent intent) { while (ServiceIsRun) { int id_s=0; // Note: Original code had a syntax error (extra double quote) — fixed here String url0 = "http://172.17.100.2/sendapp.php?co=" + id_s; String msg; try { URL url = new URL(url0); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream in = new BufferedInputStream(urlConnection.getInputStream()); msg = Stream2String(in); in.close(); JSONObject jsonRootObject = new JSONObject(msg); JSONArray jsonArray = jsonRootObject.optJSONArray("date"); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); String id= jsonObject.optString("id"); String title = jsonObject.optString("title"); String mess = jsonObject.optString("mess"); // No logic here to handle new data (like saving the latest ID or showing notifications) } // Send broadcast with data intent = new Intent(); intent.setAction("com.example.Broadcast"); intent.putExtra("msg", msg); sendBroadcast(intent); } catch (Exception e) { // No logging here — you can't see what went wrong! e.printStackTrace(); // Add this to debug } try{ Thread.sleep(20000); // You wanted 2 minutes, but this is only 20 seconds }catch (Exception ex){ ex.printStackTrace(); } } } public String Stream2String(InputStream inputStream) { BufferedReader bureader=new BufferedReader( new InputStreamReader(inputStream)); String line ; String Text=""; try{ while((line=bureader.readLine())!=null) { Text+=line; } inputStream.close(); }catch (Exception ex){ ex.printStackTrace(); } return Text; } }
sendapp.php
<?php $hostname_mus_db = "localhost"; $database_mus_db = "musdb2"; $username_mus_db = "root"; $password_mus_db = ""; $tf=@mysql_connect($hostname_mus_db,$username_mus_db,$password_mus_db); if(!$tf) die('Connection problem1 ..'); $tf_db=mysql_select_db($database_mus_db); if(!$tf_db) { @mysql_close($tf_handle); die('selection problem2 ..'); } $co_array=array(); if (isset($_GET['co'])) { $co=$_GET['co']; $sql = mysql_query("SELECT * FROM mha1 where id>".$co); while($row = mysql_fetch_assoc($sql)){ $co_array[]=$row; } } header('Content-Type:application/json'); echo json_encode(array("date"=>$co_array)); ?>
Let's break down the key issues:
- IntentService isn't built for long-running loops: IntentService is designed for one-time tasks. Once
onHandleIntentfinishes executing, the service automatically stops and is destroyed. Your while loop tries to keep it running, but the system will kill it or it'll terminate on its own. - Syntax error: The original URL string had an extra double quote, which would cause a compile error (if you didn't fix it already).
- Static
id_svalue: You're always usingid_s=0, so you'll keep fetching all old data instead of only new entries. You need to track the latest ID you've fetched. - No error logging: You catch all exceptions but don't log them, so you have no way to debug issues like failed network requests or broken JSON parsing.
- Incorrect sleep time: You wanted a 2-minute interval, but
Thread.sleep(20000)only waits 20 seconds. Plus, usingThread.sleepin a service is unreliable on Android, especially with background restrictions.
Android 8.0+ has strict background service limits, so WorkManager is Google's recommended tool for periodic or delayed tasks. It works across all Android versions, survives system reboots, and handles background restrictions automatically.
Step 1: Add WorkManager Dependency
Add this to your app-level build.gradle:
dependencies { implementation "androidx.work:work-runtime:2.8.1" }
Step 2: Create a Worker Class (Replace IntentService)
This class will handle the database check and notification logic:
public class DatabaseCheckWorker extends Worker { private static final String TAG = "DatabaseCheckWorker"; private int lastId; // Tracks the latest ID we've fetched public DatabaseCheckWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); // Load the last saved ID from SharedPreferences SharedPreferences prefs = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE); lastId = prefs.getInt("last_id", 0); } @NonNull @Override public Result doWork() { try { // Fetch only new data (where ID > lastId) String url0 = "http://172.17.100.2/sendapp.php?co=" + lastId; URL url = new URL(url0); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("GET"); InputStream in = new BufferedInputStream(urlConnection.getInputStream()); String msg = streamToString(in); in.close(); urlConnection.disconnect(); // Parse JSON response JSONObject jsonRoot = new JSONObject(msg); JSONArray jsonArray = jsonRoot.optJSONArray("date"); if (jsonArray != null && jsonArray.length() > 0) { // Process each new entry for (int i = 0; i < jsonArray.length(); i++) { JSONObject entry = jsonArray.getJSONObject(i); String idStr = entry.optString("id"); String title = entry.optString("title"); String message = entry.optString("mess"); // Update lastId to the newest entry's ID int currentId = Integer.parseInt(idStr); if (currentId > lastId) { lastId = currentId; } // Show a notification for the new entry showNotification(title, message); } // Save the latest ID to avoid re-fetching old data SharedPreferences prefs = getApplicationContext().getSharedPreferences("AppPrefs", Context.MODE_PRIVATE); prefs.edit().putInt("last_id", lastId).apply(); } return Result.success(); // Task completed successfully } catch (Exception e) { Log.e(TAG, "Database check failed", e); return Result.retry(); // Retry the task later if it fails } } private String streamToString(InputStream inputStream) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); return sb.toString(); } private void showNotification(String title, String content) { // Create a notification channel (required for Android O+) String channelId = "NEW_MESSAGE_CHANNEL"; NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(channelId, "New Messages", NotificationManager.IMPORTANCE_DEFAULT); notificationManager.createNotificationChannel(channel); } // Build and show the notification NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), channelId) .setSmallIcon(R.drawable.ic_notification) // Replace with your notification icon .setContentTitle(title) .setContentText(content) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setAutoCancel(true); notificationManager.notify((int) System.currentTimeMillis(), builder.build()); } }
Step 3: Start the Periodic Task
In your Activity or Application class, start the 2-minute recurring task:
// Configure the periodic work request PeriodicWorkRequest periodicCheck = new PeriodicWorkRequest.Builder( DatabaseCheckWorker.class, 120, TimeUnit.SECONDS, // Run every 2 minutes 30, TimeUnit.SECONDS) // Allow a 30-second flexibility window .build(); // Submit the task to WorkManager WorkManager.getInstance(getApplicationContext()).enqueue(periodicCheck);
Bonus Optimizations
- Update PHP to use modern MySQL functions: Your current PHP uses deprecated
mysql_*functions. Switch tomysqlifor security and compatibility:
<?php $hostname_mus_db = "localhost"; $database_mus_db = "musdb2"; $username_mus_db = "root"; $password_mus_db = ""; // Use mysqli for secure, supported database access $conn = mysqli_connect($hostname_mus_db, $username_mus_db, $password_mus_db, $database_mus_db); if (!$conn) { die(json_encode(array("error" => "Connection failed: " . mysqli_connect_error()))); } $co_array = array(); if (isset($_GET['co'])) { $co = intval($_GET['co']); // Sanitize input to prevent SQL injection $sql = "SELECT * FROM mha1 WHERE id > ?"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, "i", $co); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); while ($row = mysqli_fetch_assoc($result)) { $co_array[] = $row; } mysqli_stmt_close($stmt); } header('Content-Type:application/json'); echo json_encode(array("date" => $co_array)); mysqli_close($conn); ?>
- Add Internet Permission: Make sure your
AndroidManifest.xmlincludes this:
<uses-permission android:name="android.permission.INTERNET" />
内容的提问来源于stack exchange,提问作者Mohamed Mrzook

