The problem wit onSelectedDayChange is that, when i open the calendarview and click on the focused day, nothing happens. For example i want to see details for today. Now i open the calendarview and today is focused. So i have to click on a other day ond click back on today to view the details. Is there any trick do fix this?
CalendarView derives from View which can generate onClick() events. You could try capturing the onClick() event from the view. Just a thought
I made the following class to solve this problem.
public class CustomCalendarView extends CalendarView {
private final String LOG_HEADER = "CAL:VW";
private Date previousSelectedDate = new Date();
private OnDateChangeListener listener;
private CheckSameSelectedDateAsyncTask task = new CheckSameSelectedDateAsyncTask();
public CustomCalendarView(Context context) {
super(context);
}
public CustomCalendarView(Context context, AttributeSet attribute) {
super(context, attribute);
}
public CustomCalendarView(Context context, AttributeSet attribute, int defStyle) {
super(context, attribute, defStyle);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if ((task.getStatus() == AsyncTask.Status.PENDING) || (task.getStatus() == AsyncTask.Status.FINISHED)) {
task = new CheckSameSelectedDateAsyncTask();
task.execute();
}
return false;
}
private void checkSameSelectedDate() {
Date selectedDate = new Date(super.getDate());
if (selectedDate.getDay() == previousSelectedDate.getDay() &&
selectedDate.getMonth() == previousSelectedDate.getMonth() &&
selectedDate.getYear() == previousSelectedDate.getYear()) {
if (listener != null) {
this.listener.onSameSelectedDayChange(this, selectedDate.getYear(), selectedDate.getMonth(), selectedDate.getDay());
}
}
this.previousSelectedDate = selectedDate;
}
public void setSameSelectedDayChangeListener(OnDateChangeListener listener) {
this.listener = listener;
}
public interface OnDateChangeListener extends CalendarView.OnDateChangeListener {
void onSameSelectedDayChange(CalendarView view, int year, int month, int day);
}
private class CheckSameSelectedDateAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
//Note: Breaking point between 75 - 100
Thread.sleep(300);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
checkSameSelectedDate();
}
}
}
Related
I have an EditText what I populate via
editText.setText(content)
The reason this is an EditText and not a TextView is because I also want to paste stuff (later when user is operating the app) in it or manually type in it, if applicable.
But I have to
reset a flag if editText set via setText()
and nothing if pasted by user
How can I distinguish how a EditText was populated? addTextChangedListener()'s callbacks are triggered in each case.
You can set Listener Class:
public interface GoEditTextListener {
void onUpdate();
}
Custom Edittext
public class GoEditText extends EditText
{
ArrayList<GoEditTextListener> listeners;
public GoEditText(Context context)
{
super(context);
listeners = new ArrayList<>();
}
public GoEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
listeners = new ArrayList<>();
}
public GoEditText(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
listeners = new ArrayList<>();
}
public void addListener(GoEditTextListener listener) {
try {
listeners.add(listener);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
/**
* Here you can catch paste, copy and cut events
*/
#Override
public boolean onTextContextMenuItem(int id) {
boolean consumed = super.onTextContextMenuItem(id);
switch (id){
case android.R.id.cut:
onTextCut();
break;
case android.R.id.paste:
onTextPaste();
break;
case android.R.id.copy:
onTextCopy();
}
return consumed;
}
public void onTextCut(){
}
public void onTextCopy(){
}
/**
* adding listener for Paste for example
*/
public void onTextPaste(){
for (GoEditTextListener listener : listeners) {
listener.onUpdate();
}
}
}
xml
<com.yourname.project.GoEditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/editText1"/>
Code
private GoEditText editText1;
editText1 = (GoEditText) findViewById(R.id.editText1);
editText1.addListener(new GoEditTextListener() {
#Override
public void onUpdate() {
//here do what you want when text Pasted
}
});
Simply extend EditText, include the flag, and override setText:
public class MyEditText extends EditText {
boolean fromSetText;
#Override
public void setText(String text) {
super.setText(text);
fromSetText = true;
}
}
You can define your own setters/getters and constructors based on your requirements.
I have a frustrating problem, I have created a custom preference for Android, using the support library.
public class CustomTimePreference extends DialogPreference {
public int hour = 0;
public int minute = 0;
public CustomTimePreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public static int parseHour(String value) {
try {
String[] time = value.split(":");
return (Integer.parseInt(time[0]));
} catch (Exception e) {
return 0;
}
}
public static int parseMinute(String value) {
try {
String[] time = value.split(":");
return (Integer.parseInt(time[1]));
} catch (Exception e) {
return 0;
}
}
public static String timeToString(int h, int m) {
return String.format("%02d", h) + ":" + String.format("%02d", m);
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String value;
if (restoreValue) {
if (defaultValue == null) value = getPersistedString("00:00");
else value = getPersistedString(defaultValue.toString());
} else {
value = defaultValue.toString();
}
hour = parseHour(value);
minute = parseMinute(value);
}
public void persistStringValue(String value) {
persistString(value);
}
}
and
public class CustomTimePreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat implements DialogPreference.TargetFragment {
TimePicker timePicker = null;
#Override
protected View onCreateDialogView(Context context) {
timePicker = new TimePicker(context);
return (timePicker);
}
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
timePicker.setIs24HourView(true);
CustomTimePreference pref = (CustomTimePreference) getPreference();
timePicker.setCurrentHour(pref.hour);
timePicker.setCurrentMinute(pref.minute);
}
#Override
public void onDialogClosed(boolean positiveResult) {
if (positiveResult) {
CustomTimePreference pref = (CustomTimePreference) getPreference();
pref.hour = timePicker.getCurrentHour();
pref.minute = timePicker.getCurrentMinute();
String value = CustomTimePreference.timeToString(pref.hour, pref.minute);
if (pref.callChangeListener(value)) pref.persistStringValue(value);
}
}
#Override
public Preference findPreference(CharSequence charSequence) {
return getPreference();
}
}
For completeness, the xml contained within the preferences.xml is:
<customcontrols.CustomTimePreference
android:key="time_pace_preference"
android:title="#string/title_time_pace_preference"
android:defaultValue="#string/settings_default_pace"
android:summary="Set some time"
/>
However, when I attempt to call
PreferenceManager.setDefaultValues(mContext, preferences, true);
I receive
java.lang.ClassCastException: customcontrols.CustomTimePreference cannot be cast to android.preference.Preference
Why is this happening? as CustomTimePreference extends DialogPreference which itself extends Preference, this should be fine?!
If I don't call the setDefaultValues() I am able to go into my settings fragment and view the custom control?
What am I doing wrong, and how do I fix it!?
If you are extending android.support.v7.preference.DialogPreference that will cause this crash.
If so, you can use android.support.v7.preference.PreferenceManager#setDefaultValues(android.content.Context, int, boolean) instead.
For custom preferences, e.g. a time picker preference, I use the following XML in Android:
<com.my.package.TimePreference android:key="notification_time" android:selectable="true" android:title="#string/notification_time" android:enabled="true" android:summary="#string/setTime" android:defaultValue="00:00" />
Where the class "TimePreference" is:
package com.my.package;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
private int lastHour = 0;
private int lastMinute = 0;
private TimePicker picker = null;
private boolean is_24_hours = true;
public static int getHour(String time) {
String[] pieces = time.split(":");
return(Integer.parseInt(pieces[0]));
}
public static int getMinute(String time) {
String[] pieces = time.split(":");
return(Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt) {
this(ctxt, null);
}
public TimePreference(Context ctxt, AttributeSet attrs) {
this(ctxt, attrs, 0);
}
public TimePreference(Context ctxt, AttributeSet attrs, int defStyle) {
super(ctxt, attrs, defStyle);
setPositiveButtonText(ctxt.getString(R.string.save));
setNegativeButtonText(ctxt.getString(R.string.cancel));
try {
is_24_hours = DateFormat.is24HourFormat(ctxt);
}
catch (Exception e) {
is_24_hours = true;
}
}
#Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
if (is_24_hours) {
picker.setIs24HourView(true);
}
else {
picker.setIs24HourView(false);
}
return(picker);
}
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
picker.clearFocus(); // important - otherwise manual input is not saved
lastHour = picker.getCurrentHour();
lastMinute = picker.getCurrentMinute();
String time = String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time = null;
if (restoreValue) {
if (defaultValue == null) {
time = getPersistedString("00:00");
}
else {
time = getPersistedString(defaultValue.toString());
}
}
else {
time = defaultValue.toString();
}
lastHour = getHour(time);
lastMinute = getMinute(time);
}
}
This has always worked great on Android 2.2 and 2.3 - but now that I've switched to Android 4.0 I can see that this preference does not adjust to the preference screen's layout:
How can I solve this problem? Is there a solution better than setting margin/padding manually?
Finally found the problem:
The constructor super() must be called that takes only two arguments (and no int defStyle argument).
In the code from the question, super() is called with a predefined defStyle value of 0 whcih prevents Android from choosing any nice layout. If you call super() without giving a default style argument, super class DialogPreference's constructor chooses the best style on its own.
I'd like to create a preference field called Interval and I want to be able to popup a TimePicker and set a mm:ss formated value with minimal value 00:30 and step 30 seconds.
Is it possible to use TimePicker in PreferenceScreen ?
There is no TimePreference built into Android. However, creating your own is fairly easy. Here's one I did:
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
private int lastHour=0;
private int lastMinute=0;
private TimePicker picker=null;
public static int getHour(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[0]));
}
public static int getMinute(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
#Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext());
return(picker);
}
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time=null;
if (restoreValue) {
if (defaultValue==null) {
time=getPersistedString("00:00");
}
else {
time=getPersistedString(defaultValue.toString());
}
}
else {
time=defaultValue.toString();
}
lastHour=getHour(time);
lastMinute=getMinute(time);
}
}
I have modified the code from first answer:
it stores selected time in long form (milliseconds) which is easier to work with (using Calendar) then string
it automatically shows selected time in summary field in user's format (12 or 24 hour)
Updated code:
public class TimePreference extends DialogPreference {
private Calendar calendar;
private TimePicker picker = null;
public TimePreference(Context ctxt) {
this(ctxt, null);
}
public TimePreference(Context ctxt, AttributeSet attrs) {
this(ctxt, attrs, android.R.attr.dialogPreferenceStyle);
}
public TimePreference(Context ctxt, AttributeSet attrs, int defStyle) {
super(ctxt, attrs, defStyle);
setPositiveButtonText(R.string.set);
setNegativeButtonText(R.string.cancel);
calendar = new GregorianCalendar();
}
#Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
return (picker);
}
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));
picker.setCurrentMinute(calendar.get(Calendar.MINUTE));
}
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
calendar.set(Calendar.HOUR_OF_DAY, picker.getCurrentHour());
calendar.set(Calendar.MINUTE, picker.getCurrentMinute());
setSummary(getSummary());
if (callChangeListener(calendar.getTimeInMillis())) {
persistLong(calendar.getTimeInMillis());
notifyChanged();
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return (a.getString(index));
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue) {
if (defaultValue == null) {
calendar.setTimeInMillis(getPersistedLong(System.currentTimeMillis()));
} else {
calendar.setTimeInMillis(Long.parseLong(getPersistedString((String) defaultValue)));
}
} else {
if (defaultValue == null) {
calendar.setTimeInMillis(System.currentTimeMillis());
} else {
calendar.setTimeInMillis(Long.parseLong((String) defaultValue));
}
}
setSummary(getSummary());
}
#Override
public CharSequence getSummary() {
if (calendar == null) {
return null;
}
return DateFormat.getTimeFormat(getContext()).format(new Date(calendar.getTimeInMillis()));
}
}
For those whom the implementation of a custom Preference isn't so obvious (like it wasn't for me), you have to add this to your preferences.xml or whatever you're calling it.
You'll end up with something like this:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:key="editTextPref_Key"
android:title="#string/editTextPref_title"/>
<com.example.myapp.TimePreference
android:key="timePrefA_Key"
android:title="#string/timePrefA_title"/>
<com.example.myapp.TimePreference
android:key="timePrefB_Key"
android:title="#string/timePrefB_title"/>
</PreferenceScreen>
Assuming you added the TimePreference to your own root package:
(src/com/example/myapp/TimePreference.java)
For Preferences Support Library different code is needed. It requires two custom classes TimePreference and TimePreferenceDialogFragmentCompat, as well as overide of onDisplayPreferenceDialog method in PreferenceFragmentCompat extension class.
TimePreference.java
package com.test;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v7.preference.DialogPreference;
import android.util.AttributeSet;
public class TimePreference extends DialogPreference
{
public int hour = 0;
public int minute = 0;
public static int parseHour(String value)
{
try
{
String[] time = value.split(":");
return (Integer.parseInt(time[0]));
}
catch (Exception e)
{
return 0;
}
}
public static int parseMinute(String value)
{
try
{
String[] time = value.split(":");
return (Integer.parseInt(time[1]));
}
catch (Exception e)
{
return 0;
}
}
public static String timeToString(int h, int m)
{
return String.format("%02d", h) + ":" + String.format("%02d", m);
}
public TimePreference(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index)
{
return a.getString(index);
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
{
String value;
if (restoreValue)
{
if (defaultValue == null) value = getPersistedString("00:00");
else value = getPersistedString(defaultValue.toString());
}
else
{
value = defaultValue.toString();
}
hour = parseHour(value);
minute = parseMinute(value);
}
public void persistStringValue(String value)
{
persistString(value);
}
}
TimePreferenceDialogFragmentCompat.java
package com.test;
import android.content.Context;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceDialogFragmentCompat;
import android.view.View;
import android.widget.TimePicker;
public class TimePreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat implements DialogPreference.TargetFragment
{
TimePicker timePicker = null;
#Override
protected View onCreateDialogView(Context context)
{
timePicker = new TimePicker(context);
return (timePicker);
}
#Override
protected void onBindDialogView(View v)
{
super.onBindDialogView(v);
timePicker.setIs24HourView(true);
TimePreference pref = (TimePreference) getPreference();
timePicker.setCurrentHour(pref.hour);
timePicker.setCurrentMinute(pref.minute);
}
#Override
public void onDialogClosed(boolean positiveResult)
{
if (positiveResult)
{
TimePreference pref = (TimePreference) getPreference();
pref.hour = timePicker.getCurrentHour();
pref.minute = timePicker.getCurrentMinute();
String value = TimePreference.timeToString(pref.hour, pref.minute);
if (pref.callChangeListener(value)) pref.persistStringValue(value);
}
}
#Override
public Preference findPreference(CharSequence charSequence)
{
return getPreference();
}
}
Required modifications in PreferenceFragmentCompat extension class
public static class PreferencesFragment extends PreferenceFragmentCompat
{
....
#Override
public void onDisplayPreferenceDialog(Preference preference)
{
DialogFragment dialogFragment = null;
if (preference instanceof TimePreference)
{
dialogFragment = new TimePreferenceDialogFragmentCompat();
Bundle bundle = new Bundle(1);
bundle.putString("key", preference.getKey());
dialogFragment.setArguments(bundle);
}
if (dialogFragment != null)
{
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(this.getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG");
}
else
{
super.onDisplayPreferenceDialog(preference);
}
}
}
With above code time preference can be used in preferences xml file like this
<com.test.TimePreference
android:key="some_time"
android:title="Set some time"
android:defaultValue="12:00"
android:summary="Set some time"/>
CommonsWare's solution has a few problems, which I fixed:
It doesn't update the field properly after it is changed
The minutes value only persists a single digit, e.g. 10:2 instead of 10:02
If you use PreferenceManager.setDefaultPreferences to set initial default preferences in your app, it won't work because onSetInitialValue needs to persist it
The formatting of the result isn't tailored to the user's Locale (e.g. US uses AM/PM)
Here's my code, enjoy.
public class TimePreference extends DialogPreference {
private int lastHour=0;
private int lastMinute=0;
private TimePicker picker=null;
public static int getHour(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[0]));
}
public static int getMinute(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
#Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext());
return(picker);
}
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
setSummary(getSummary());
String lastMinuteString = String.valueOf(lastMinute);
String time = String.valueOf(lastHour) + ":" + (lastMinuteString.length() == 1 ? "0" + lastMinuteString : lastMinuteString);
if (callChangeListener(time)) {
persistString(time);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time;
String defaultValueStr = (defaultValue != null) ? defaultValue.toString() : "00:00";
if (restoreValue)
time = getPersistedString(defaultValueStr);
else {
time = defaultValueStr;
if (shouldPersist())
persistString(defaultValueStr);
}
lastHour=getHour(time);
lastMinute=getMinute(time);
setSummary(getSummary());
}
#Override
public CharSequence getSummary() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, lastHour);
cal.set(Calendar.MINUTE, lastMinute);
DateFormat sdf = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT);
return sdf.format(cal.getTime());
}
}
add this for Summary:
#Override
public CharSequence getSummary() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, lastHour, lastMinute);
return DateFormat.getTimeFormat(getContext()).format(new Date(cal.getTimeInMillis()));
}
and add
setSummary(getSummary());
to end of onSetInitialValue and onDialogClosed.
I have modified CommonsWare answer to use JodaTime library:
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
import org.joda.time.LocalTime;
public class TimePreference extends DialogPreference {
private int lastHour;
private int lastMinute;
private TimePicker picker;
public TimePreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
#Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
return(picker);
}
#Override
protected void onBindDialogView(#NonNull View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour = picker.getCurrentHour();
lastMinute = picker.getCurrentMinute();
LocalTime localTime = new LocalTime(lastHour, lastMinute);
String time = localTime.toString();
if (callChangeListener(time)) {
persistString(time);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
LocalTime time;
if (restoreValue) {
if (defaultValue == null) {
time = LocalTime.parse(getPersistedString("08:00:00.000"));
}
else {
time = LocalTime.parse(getPersistedString(defaultValue.toString()));
}
} else {
time = LocalTime.parse(defaultValue.toString());
}
lastHour = time.getHourOfDay();
lastMinute = time.getMinuteOfHour();
}
}
Also you will need to add a Custom preference like Sikora said.
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:key="editTextPref_Key"
android:title="#string/editTextPref_title"/>
<com.example.myapp.TimePreference
android:key="timePrefA_Key"
android:title="#string/timePrefA_title"/>
<com.example.myapp.TimePreference
android:key="timePrefB_Key"
android:title="#string/timePrefB_title"/>
</PreferenceScreen>
With Android 6, "current hour" and "current minute" are deprecated. Use this to ensure Marshmallow compatibility:
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
private int lastHour;
private int lastMinute;
private TimePicker picker;
public TimePreference(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
setPositiveButtonText(ctx.getString(android.R.string.ok));
setNegativeButtonText(ctx.getString(android.R.string.cancel));
}
#Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
picker.setIs24HourView(true);
return picker;
}
#SuppressWarnings("deprecation")
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
} else {
picker.setHour(lastHour);
picker.setMinute(lastMinute);
}
}
#SuppressWarnings("deprecation")
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
lastHour = picker.getCurrentHour();
lastMinute = picker.getCurrentMinute();
} else {
lastHour = picker.getHour();
lastMinute = picker.getMinute();
}
String time = String.valueOf(lastHour) + ":" + String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time;
if (restoreValue) {
if (defaultValue == null) {
time = getPersistedString("00:00");
} else {
time = getPersistedString(defaultValue.toString());
}
} else {
time = defaultValue.toString();
}
lastHour = getHour(time);
lastMinute = getMinute(time);
}
public static int getHour(String time) {
String[] pieces = time.split(":");
return Integer.parseInt(pieces[0]);
}
public static int getMinute(String time) {
String[] pieces = time.split(":");
return Integer.parseInt(pieces[1]);
}
}
Like LEO87, I was seeing ClassCastException's. The problem was due to stale persisted data from a previous control of the same name. Possible solutions are to clear the app data, use a different name (key), or if you must use the same key name, catch the exception as follows:
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue) {
long persistedValue;
try {
persistedValue = getPersistedLong(System.currentTimeMillis());
} catch (Exception e) {
//Stale persisted data may be the wrong type
persistedValue = System.currentTimeMillis();
}
calendar.setTimeInMillis(persistedValue);
} else if (defaultValue != null) {
calendar.setTimeInMillis(Long.parseLong((String) defaultValue));
} else {
//!restoreValue, defaultValue == null
calendar.setTimeInMillis(System.currentTimeMillis());
}
setSummary(getSummary());
}
Could someone help me to create user defined listener interface with some code snippets?
Create a new file:
MyListener.java:
public interface MyListener {
// you can define any parameter as per your requirement
public void callback(View view, String result);
}
In your activity, implement the interface:
MyActivity.java:
public class MyActivity extends Activity implements MyListener {
#override
public void onCreate(){
MyButton m = new MyButton(this);
}
// method is invoked when MyButton is clicked
#override
public void callback(View view, String result) {
// do your stuff here
}
}
In your custom class, invoke the interface when needed:
MyButton.java:
public class MyButton {
MyListener ml;
// constructor
MyButton(MyListener ml) {
//Setting the listener
this.ml = ml;
}
public void MyLogicToIntimateOthers() {
//Invoke the interface
ml.callback(this, "success");
}
}
please do read observer pattern
listener interface
public interface OnEventListener {
void onEvent(EventResult er);
// or void onEvent(); as per your need
}
then in your class say Event class
public class Event {
private OnEventListener mOnEventListener;
public void setOnEventListener(OnEventListener listener) {
mOnEventListener = listener;
}
public void doEvent() {
/*
* code code code
*/
// and in the end
if (mOnEventListener != null)
mOnEventListener.onEvent(eventResult); // event result object :)
}
}
in your driver class MyTestDriver
public class MyTestDriver {
public static void main(String[] args) {
Event e = new Event();
e.setOnEventListener(new OnEventListener() {
public void onEvent(EventResult er) {
// do your work.
}
});
e.doEvent();
}
}
I have created a Generic AsyncTask Listener which get result from AsycTask seperate class and give it to CallingActivity using Interface Callback.
new GenericAsyncTask(context,new AsyncTaskCompleteListener()
{
public void onTaskComplete(String response)
{
// do your work.
}
}).execute();
Interface
interface AsyncTaskCompleteListener<T> {
public void onTaskComplete(T result);
}
GenericAsyncTask
class GenericAsyncTask extends AsyncTask<String, Void, String>
{
private AsyncTaskCompleteListener<String> callback;
public A(Context context, AsyncTaskCompleteListener<String> cb) {
this.context = context;
this.callback = cb;
}
protected void onPostExecute(String result) {
finalResult = result;
callback.onTaskComplete(result);
}
}
Have a look at this , this question for more details.
There are 4 steps:
1.create interface class (listener)
2.use interface in view 1 (define variable)
3.implements interface to view 2 (view 1 used in view 2)
4.pass interface in view 1 to view 2
Example:
Step 1: you need create interface and definde function
public interface onAddTextViewCustomListener {
void onAddText(String text);
}
Step 2: use this interface in view
public class CTextView extends TextView {
onAddTextViewCustomListener onAddTextViewCustomListener; //listener custom
public CTextView(Context context, onAddTextViewCustomListener onAddTextViewCustomListener) {
super(context);
this.onAddTextViewCustomListener = onAddTextViewCustomListener;
init(context, null);
}
public CTextView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
public void init(Context context, #Nullable AttributeSet attrs) {
if (isInEditMode())
return;
//call listener
onAddTextViewCustomListener.onAddText("this TextView added");
}
}
Step 3,4: implements to activity
public class MainActivity extends AppCompatActivity implements onAddTextViewCustomListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//get main view from layout
RelativeLayout mainView = (RelativeLayout)findViewById(R.id.mainView);
//create new CTextView and set listener
CTextView cTextView = new CTextView(getApplicationContext(), this);
//add cTextView to mainView
mainView.addView(cTextView);
}
#Override
public void onAddText(String text) {
Log.i("Message ", text);
}
}
Create listener interface.
public interface YourCustomListener
{
public void onCustomClick(View view);
// pass view as argument or whatever you want.
}
And create method setOnCustomClick in another activity(or fragment) , where you want to apply your custom listener......
public void setCustomClickListener(YourCustomListener yourCustomListener)
{
this.yourCustomListener= yourCustomListener;
}
Call this method from your First activity, and pass the listener interface...
In the year of 2018, there's no need for listeners interfaces. You've got Android LiveData to take care of passing the desired result back to the UI components.
If I'll take Rupesh's answer and adjust it to use LiveData, it will like so:
public class Event {
public LiveData<EventResult> doEvent() {
/*
* code code code
*/
// and in the end
LiveData<EventResult> result = new MutableLiveData<>();
result.setValue(eventResult);
return result;
}
}
and now in your driver class MyTestDriver:
public class MyTestDriver {
public static void main(String[] args) {
Event e = new Event();
e.doEvent().observe(this, new Observer<EventResult>() {
#Override
public void onChanged(final EventResult er) {
// do your work.
}
});
}
}
For more information along with code samples you can read my post about it, as well as the offical docs:
When and why to use LiveData
Official docs
In Android,you can create an interface such as Listener,and your Activity implements it,but i don't think it is a good idea.
if we have many components to listen the changes of their state,we can create a BaseListener implements interface Listener,and use type code to handle them.
we can bind the method when we create XML file,for example:
<Button
android:id="#+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button4"
android:onClick="Btn4OnClick" />
and the source code:
public void Btn4OnClick(View view) {
String strTmp = "点击Button04";
tv.setText(strTmp);
}
but i don't think it is a good idea...
I have done it something like below for sending my model class from the Second Activity to First Activity. I used LiveData to achieve this, with the help of answers from Rupesh and TheCodeFather.
Second Activity
public static MutableLiveData<AudioListModel> getLiveSong() {
MutableLiveData<AudioListModel> result = new MutableLiveData<>();
result.setValue(liveSong);
return result;
}
"liveSong" is AudioListModel declared globally
Call this method in the First Activity
PlayerActivity.getLiveSong().observe(this, new Observer<AudioListModel>() {
#Override
public void onChanged(AudioListModel audioListModel) {
if (PlayerActivity.mediaPlayer != null && PlayerActivity.mediaPlayer.isPlaying()) {
Log.d("LiveSong--->Changes-->", audioListModel.getSongName());
}
}
});
May this help for new explorers like me.
Simple method to do this approach. Firstly implements the OnClickListeners in your Activity class.
Code:
class MainActivity extends Activity implements OnClickListeners{
protected void OnCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(R.layout.activity_main.xml);
Button b1=(Button)findViewById(R.id.sipsi);
Button b2=(Button)findViewById(R.id.pipsi);
b1.SetOnClickListener(this);
b2.SetOnClickListener(this);
}
public void OnClick(View V)
{
int i=v.getId();
switch(i)
{
case R.id.sipsi:
{
//you can do anything from this button
break;
}
case R.id.pipsi:
{
//you can do anything from this button
break;
}
}
}