You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:如何实现基于日期与用户输入自动更新的TextView?

Hey there! As someone who’s navigated the Android Studio learning curve, I’ll walk you through building this feature step by step. Let’s split it into actionable, easy-to-follow parts:

1. Build the User Interface

First, create a layout with inputs for the target value and monthly date, plus a TextView to display progress. Here’s a sample activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    android:gap="16dp">

    <!-- Target Value Input -->
    <EditText
        android:id="@+id/et_target_value"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter target value (e.g., 100000)"
        android:inputType="numberDecimal|numberSigned"/>

    <!-- Monthly Date Input -->
    <EditText
        android:id="@+id/et_monthly_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter monthly date (e.g., 15)"
        android:inputType="number"/>

    <!-- Confirm Button -->
    <Button
        android:id="@+id/btn_set_goal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Set Goal"/>

    <!-- Progress Display -->
    <TextView
        android:id="@+id/tv_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Current Progress: 0"
        android:textSize="20sp"
        android:textStyle="bold"/>

</LinearLayout>
2. Calculate Days Until Next Target Date

We’ll use Java’s modern java.time API (available on API 26+, or use desugar support for older versions) for clean date handling. Here’s a helper method to get remaining days:

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

public long getRemainingDays(int targetDay) {
    LocalDate today = LocalDate.now();
    LocalDate nextTargetDate;

    // If today is past the target day, use next month's date
    if (today.getDayOfMonth() > targetDay) {
        nextTargetDate = today.plusMonths(1).withDayOfMonth(targetDay);
    } else {
        nextTargetDate = today.withDayOfMonth(targetDay);
    }

    // Handle edge cases (e.g., 31st in February)
    if (nextTargetDate.getDayOfMonth() != targetDay) {
        nextTargetDate = nextTargetDate.withDayOfMonth(nextTargetDate.lengthOfMonth());
    }

    return ChronoUnit.DAYS.between(today, nextTargetDate);
}
3. Daily Increment & Auto-Update Logic

Step 3.1: Compute Daily Amount

Once you have remaining days, calculate the daily increment:

double targetValue = Double.parseDouble(et_target_value.getText().toString());
long remainingDays = getRemainingDays(targetDay);

// If today is the target date, jump straight to the target value
double dailyIncrement = remainingDays == 0 ? targetValue : targetValue / remainingDays;

Step 3.2: Use WorkManager for Daily Updates

WorkManager is the recommended tool for repeating background tasks (even if the app is closed). First, add the dependency to your module-level build.gradle:

dependencies {
    implementation "androidx.work:work-runtime:2.8.1"
}

Create a worker class to handle progress updates:

import android.content.Context;
import android.content.Intent;
import android.preference.PreferenceManager;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class ProgressUpdateWorker extends Worker {
    public ProgressUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        Context context = getApplicationContext();
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        
        // Load saved values
        double currentProgress = prefs.getFloat("current_progress", 0f);
        double dailyIncrement = prefs.getFloat("daily_increment", 0f);
        double targetValue = prefs.getFloat("target_value", 0f);

        // Update progress (don't exceed target)
        currentProgress += dailyIncrement;
        if (currentProgress > targetValue) currentProgress = targetValue;

        // Save updated progress
        prefs.edit()
                .putFloat("current_progress", (float) currentProgress)
                .apply();

        // Notify the activity to update the TextView
        Intent intent = new Intent("PROGRESS_UPDATED");
        intent.putExtra("current_progress", currentProgress);
        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

        return Result.success();
    }
}

Step 3.3: Schedule the Daily Task

In your MainActivity, schedule the worker when the user clicks "Set Goal":

import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
import java.util.concurrent.TimeUnit;

// Inside btn_set_goal's onClickListener
int targetDay = Integer.parseInt(et_monthly_date.getText().toString());
double targetValue = Double.parseDouble(et_target_value.getText().toString());
long remainingDays = getRemainingDays(targetDay);
double dailyIncrement = remainingDays == 0 ? targetValue : targetValue / remainingDays;

// Save values to persist across app restarts
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit()
        .putFloat("target_value", (float) targetValue)
        .putInt("target_day", targetDay)
        .putFloat("daily_increment", (float) dailyIncrement)
        .putFloat("current_progress", 0f) // Reset progress for new goal
        .apply();

// Cancel any existing work first
WorkManager.getInstance(this).cancelUniqueWork("daily_progress_update");

// Schedule daily updates
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
        ProgressUpdateWorker.class,
        1, TimeUnit.DAYS)
        .setInitialDelay(0, TimeUnit.MILLISECONDS) // Start immediately
        .build();

WorkManager.getInstance(this).enqueueUniqueWork(
        "daily_progress_update",
        ExistingPeriodicWorkPolicy.REPLACE,
        workRequest);

// Update TextView right away
updateProgressTextView(0);

Step 3.4: Receive Updates in the Activity

Add a broadcast receiver to update the TextView when progress changes:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

private BroadcastReceiver progressUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        double currentProgress = intent.getDoubleExtra("current_progress", 0);
        updateProgressTextView(currentProgress);
    }
};

@Override
protected void onResume() {
    super.onResume();
    LocalBroadcastManager.getInstance(this).registerReceiver(
            progressUpdateReceiver,
            new IntentFilter("PROGRESS_UPDATED"));
    // Load saved progress when returning to the app
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    double currentProgress = prefs.getFloat("current_progress", 0f);
    updateProgressTextView(currentProgress);
}

@Override
protected void onPause() {
    super.onPause();
    LocalBroadcastManager.getInstance(this).unregisterReceiver(progressUpdateReceiver);
}

private void updateProgressTextView(double progress) {
    tv_progress.setText(String.format("Current Progress: %.2f", progress));
}
4. Add Input Validation

Don’t skip checking for valid inputs to avoid crashes:

// Inside btn_set_goal's onClickListener
String targetValueStr = et_target_value.getText().toString();
String targetDayStr = et_monthly_date.getText().toString();

if (targetValueStr.isEmpty() || targetDayStr.isEmpty()) {
    Toast.makeText(this, "Please fill all fields", Toast.LENGTH_SHORT).show();
    return;
}

int targetDay = Integer.parseInt(targetDayStr);
if (targetDay < 1 || targetDay > 31) {
    Toast.makeText(this, "Enter a valid date (1-31)", Toast.LENGTH_SHORT).show();
    return;
}

double targetValue = Double.parseDouble(targetValueStr);
if (targetValue <= 0) {
    Toast.makeText(this, "Target value must be positive", Toast.LENGTH_SHORT).show();
    return;
}

内容的提问来源于stack exchange,提问作者Lars Bing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:28:19