我希望能够设置可重复使用的计时器(例如20秒),然后让它开始倒计时,但我也可以最小化应用程序,做其他事情,并让计时器仍然通知我。计时器也应该是启动/停止/暂停/重置。
我已经看过AlarmManager ,但我读到它似乎在几台设备上被破坏了。有更强大的解决方案吗?
编辑:尝试服务
The Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.packagename.timertest"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".TimerService"
android:exported="false"/>
</application>
</manifest>
启动片段的MainActivity:
public class MainActivity extends AppCompatActivity {
private Button launchTimerPanelButton;
private FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
launchTimerPanelButton = (Button) findViewById(R.id.launch_timer_button);
launchTimerPanelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TimerDialogFragment dialogFragment = TimerDialogFragment.newInstance(10);
dialogFragment.setStyle(DialogFragment.STYLE_NORMAL, R.style.CustomDialog);
dialogFragment.show(fragmentManager,"");
}
});
}
}
MainActivity的XML:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="com.packagename.timertest.MainActivity">
<Button
android:id="@+id/launch_timer_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Launch Timer Panel"/>
</android.support.constraint.ConstraintLayout>
DialogFragment:
public class TimerDialogFragment extends DialogFragment {
private static final String ARGUMENT_NUM_SECONDS = "state_num_seconds";
private static final String STATE_NUM_SECONDS = "state_num_seconds";
public static final String STATE_IS_BROADCAST_RECEIVER_REGISTERED = "state_is_broadcast_receiver_registered";
private int numSecondsInitial;
private int numSeconds;
private TextView secondsRemainingTextView;
private Button startButton;
private Button pauseButton;
private Button resetButton;
private Button closeButton;
private BroadcastReceiver restTimerReceiver;
private boolean isBroadcastReceiverRegistered;
public static TimerDialogFragment newInstance(int numSeconds) {
Bundle args = new Bundle();
TimerDialogFragment fragment = new TimerDialogFragment();
args.putInt(ARGUMENT_NUM_SECONDS, numSeconds);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
numSecondsInitial = getArguments().getInt(ARGUMENT_NUM_SECONDS);
if (savedInstanceState == null) {
numSeconds = numSecondsInitial;
}
else {
numSeconds = savedInstanceState.getInt(STATE_NUM_SECONDS);
}
isBroadcastReceiverRegistered = false;
if (savedInstanceState != null) {
isBroadcastReceiverRegistered = savedInstanceState.getBoolean(STATE_IS_BROADCAST_RECEIVER_REGISTERED);
}
restTimerReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//???????
}
};
registerBroadcastReceiver();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.dialogfragment_timer, container, false);
getDialog().setTitle("Timer");
secondsRemainingTextView = (TextView) contentView.findViewById(R.id.seconds_remaining_textview);
secondsRemainingTextView.setText(numSeconds + "");
startButton = (Button) contentView.findViewById(R.id.start_button);
pauseButton = (Button) contentView.findViewById(R.id.pause_button);
resetButton = (Button) contentView.findViewById(R.id.reset_button);
closeButton = (Button) contentView.findViewById(R.id.close_button);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
pauseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
resetButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//end the timer first?
unregisterBroadcastReceiver();
dismiss();
}
});
return contentView;
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(STATE_NUM_SECONDS, numSeconds);
super.onSaveInstanceState(outState);
}
@Override
public void onResume() {
registerBroadcastReceiver();
super.onResume();
}
@Override
public void onPause() {
unregisterBroadcastReceiver();
super.onPause();
}
@Override
public void onDestroy() {
unregisterBroadcastReceiver();
super.onDestroy();
}
private void registerBroadcastReceiver() {
if (!isBroadcastReceiverRegistered) {
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(restTimerReceiver, new IntentFilter(TimerService.TIMER_SERVICE));
isBroadcastReceiverRegistered = true;
}
}
private void unregisterBroadcastReceiver() {
if (isBroadcastReceiverRegistered) {
isBroadcastReceiverRegistered = false;
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(restTimerReceiver);
}
}
}
其布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:gravity="center">
<TextView
android:id="@+id/seconds_remaining_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center"
android:text="10"/>
<Button
android:id="@+id/start_button"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"
android:text="Start Timer"/>
<Button
android:id="@+id/pause_button"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"
android:text="Pause Timer"/>
<Button
android:id="@+id/reset_button"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"
android:text="Reset Timer"/>
<Button
android:id="@+id/close_button"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"
android:text="Close / End Timer"/>
</LinearLayout>
服务:
public class TimerService extends Service {
private String LOG_TAG = TimerService.class.getSimpleName();
public static final String TIMER_SERVICE = "timer_service";
@Override
public void onCreate() {
super.onCreate();
Log.i(LOG_TAG, "OnCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOG_TAG, "In onStartCommand");
new Thread(new Runnable() {
public void run() {
//something
}
}).start();
return START_REDELIVER_INTENT;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(LOG_TAG, "OnBind");
return null;
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.i(LOG_TAG, "In onTaskRemoved");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(LOG_TAG, "In onDestroy");
}
}
答案 0 :(得分:0)
答案 1 :(得分:0)
另一种选择是使用FirebaseJobDispatcher
以下是一个例子:
// Create a new dispatcher using the Google Play driver.
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Bundle myExtrasBundle = new Bundle();
myExtrasBundle.putString("some_key", "some_value");
Job myJob = dispatcher.newJobBuilder()
// the JobService that will be called
.setService(MyJobService.class)
// uniquely identifies the job
.setTag("my-unique-tag")
// one-off job
.setRecurring(false)
// don't persist past a device reboot
.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
// start between 0 and 60 seconds from now
.setTrigger(Trigger.executionWindow(0, 60))
// don't overwrite an existing job with the same tag
.setReplaceCurrent(false)
// retry with exponential backoff
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
// constraints that need to be satisfied for the job to run
.setConstraints(
// only run on an unmetered network
Constraint.ON_UNMETERED_NETWORK,
// only run when the device is charging
Constraint.DEVICE_CHARGING
)
.setExtras(myExtrasBundle)
.build();
dispatcher.mustSchedule(myJob);
取消该职位:
dispatcher.cancel("my-unique-tag");
如果要替换上一个计划的作业,该标记很有用。请记住,它有一个时间窗口,因此它不如AlarmManager准确。
这里有一张表格,可以比较您拥有的不同选项:
https://github.com/firebase/firebase-jobdispatcher-android#comparison-to-other-libraries
在该表格中,您会找到Evernote's library。它不依赖于Google Play,而是一种自定义实现,它根据您运行的用户操作系统使用不同的策略。