I'm new to coding writing a small application to select time from a custom time picker and get time from it and use it.I'm getting a NullRefrenceError.
My xml file:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:key="init_Settings">
<PreferenceCategory
android:title="Set-Time">
<com.lambdahash.sonic.ui_app.fragments.TimePick
android:id="#+id/from_time"
android:title="Time from"
android:defaultValue="--:--"
android:summary="--:--"
android:key="time-from"
/>
<com.lambdahash.sonic.ui_app.fragments.TimePick
android:id="#+id/to_time"
android:title="Time to"
android:summary="--:--"
android:defaultValue="--:--"
android:key="time-to"
/>
</PreferenceCategory>
Here TimePick is a java class that works perfectly fine for picking time.
The code:
public class TimePick 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 TimePick(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));
}
}
This is where I'm getting error:
public class generalSettings extends PreferenceActivity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.general_settings);
TimePicker time_from = (TimePicker) findViewById(R.id.from_time);
TimePicker time_to = (TimePicker) findViewById(R.id.to_time);
time_from.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
#Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
//ts.timeFrom();
Log.d("TESTF:",hourOfDay+":"+minute+"\n");
}
});
}
}
Getting
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TimePicker.setOnTimeChangedListener(android.widget.TimePicker$OnTimeChangedListener)' on a null object reference
How do I workaround this?
Try this code
Preference time_from = findPreference("time-from");
time_from.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
#Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
//ts.timeFrom();
Log.d("TESTF:",hourOfDay+":"+minute+"\n");
}
});
Preference time_to= findPreference("time-to");
time_from.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
#Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
//ts.timeTo();
Log.d("TESTF:",hourOfDay+":"+minute+"\n");
}
});
You should be designing it differently. You should be extending the TimePick class, once for the time_from and once for time_two. Set the onClickListener in the extended class, not in the PreferencesScreen class. You should do that by overriding the onCreateDialogView function, like this.
#Override protected View onCreateDialogView() {
picker=super.onCreateDialogView();
picker.setOnTimeChangedListener(...);
return(picker);
}
Then in your XML, put in your Extended class, rather than the TimePick class.
Related
I have complex application with tons of fragments and sub-fragments, and I need listeners to listen in a fragment, not in activity. This usually works, but not with date or time pickers.
Here is the sample application with activity with one fragment inflated - TestFragmentMain. That inflated fragment have two more fragments - one with single EditText (TestFragment_InputBox) and another with single TextView (TestFragment_DateBox) and it is used to listen events (TextChangeListener and DateChangeListener).
On text change in first fragment, all works like a charm, main fragment is receiving result.
However, on date change, I receive and error:
java.lang.NullPointerException: Attempt to invoke interface method 'void com.gmail.xxx.xxx.test.DateChangeListener.dateChanged(int, int, int)' on a null object reference
at com.gmail.xxx.xxx.test.TestFragment_DatePicker.onDateSet(TestFragment_DatePicker.java:32)
I really do not understand why. Any help is appreciated.
Main activity:
public class TestClass extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
TestFragmentMain testFragmentMain = new TestFragmentMain();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.test_fragment_container, testFragmentMain);
ft.commitAllowingStateLoss();
}
}
Main fragment, with listeners
public class TestFragmentMain extends Fragment implements TextChangeListener, DateChangeListener {
#Override
public View onCreateView(#NotNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test_fragment, container, false);
TestFragment_InputBox testFragmentInputBox = new TestFragment_InputBox();
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.test_fragment_inputbox_container, testFragmentInputBox);
ft.commitAllowingStateLoss();
TestFragment_DateBox testFragmentDateBox = new TestFragment_DateBox();
ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.test_fragment_date_container, testFragmentDateBox);
ft.commitAllowingStateLoss();
return view;
}
#Override
public void onAttach(#NotNull Context context) {
super.onAttach(context);
}
#Override
public void textChanged() {
Log.d("LISTEN","Text has been changed...");
}
#Override
public void dateChanged(int year, int month, int day) {
Log.d("LISTEN","Date has been changed to ...");
}
}
Fragment with input box:
public class TestFragment_InputBox extends Fragment {
private TextChangeListener textChangeListener;
#Override
public View onCreateView(#NotNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test_input_box, container, false);
EditText editText = view.findViewById(R.id.input_view);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
textChangeListener.textChanged();
}
});
return view;
}
#Override
public void onAttach(#NotNull Context context) {
super.onAttach(context);
try {
textChangeListener = (TextChangeListener) getParentFragment();
} catch (ClassCastException e) {
e.printStackTrace();
}
}
}
Fragment with date box:
public class TestFragment_DateBox extends Fragment implements DateChangeListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test_date_box, container, false);
TextView textView = view.findViewById(R.id.date_view);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DialogFragment datePicker = new TestFragment_DatePicker();
datePicker.show(getActivity().getSupportFragmentManager(), "datePicker");
}
});
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void dateChanged(int year, int month, int day) {
Log.d("LISTEN","Date has been changed in box fragment with box ...");
}
}
Date Picker fragment
public class TestFragment_DatePicker extends DialogFragment implements DatePickerDialog.OnDateSetListener {
public DateChangeListener dateChangeListener;
#NotNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
return new DatePickerDialog(Objects.requireNonNull(getContext()), this, year, month, day);
}
#Override
public void onDateSet(DatePicker view, int year, int month, int day) {
dateChangeListener.dateChanged(year,month,day);
}
#Override
public void onAttach(#NotNull Context context) {
super.onAttach(context);
try {
dateChangeListener = (DateChangeListener) getParentFragment();
} catch (ClassCastException e) {
e.printStackTrace();
}
}
}
And listeners:
public interface TextChangeListener {
void textChanged();
}
public interface DateChangeListener {
void dateChanged(int year,int month,int day);
}
Your fragment TestFragment_DateBox calls the date picker and inherits DatePickerDialog.OnDateSetListener
public class TestFragment_DateBox extends Fragment implements DatePickerDialog.OnDateSetListener
and show the date picker fragment like so
TestFragment_DatePicker().show(this.childFragmentManager, "datepicker")
and override onDateSet
#Override
public void onDateSet(DatePicker view, int year, int month, int day) {
// As you are in the calling fragment you can use the values as you see fit
TextView textView = view.findViewById(R.id.date_view);
textView.text = year.toString()
}
In TestFragment_DatePicker have a listener
private lateinit var listener: DatePickerDialog.OnDateSetListener
then override onAttach
override fun onAttach(context: Context) {
super.onAttach(context)
// Verify that the dialog parent implements the callback interface
try {
// Instantiate the OnDateSetListener so we can send events to the host
listener = parentFragment as DatePickerDialog.OnDateSetListener
} catch (e: ClassCastException) {
// The parent doesn't implement the interface, throw exception
throw ClassCastException(("$context must implement OnDateSetListener"))
}
}
Apologies for the mix of java and kotlin but you get the idea!
The problem is that you not inflate your TestFragment_DatePicker which is a DialogFragment which is a Fragment but return a DatePickerDialog which is an AlertDialog which is a Dialog which don't have a mParentFragment. That's why getParentFragment() return null.
This looks like a bad architecture design that we inherited from old versions of android.
I have found a solution.
In TestFragmentMain, TestFragment_DateBox need to be transacted with same FragmentManager as DatePicker is. And this is the code in TestFragmentMain:
TestFragment_DateBox testFragmentDateBox = new TestFragment_DateBox();
FragmentTransaction ft2 = this.getChildFragmentManager().beginTransaction();
ft2.replace(R.id.test_fragment_date_container, testFragmentDateBox);
ft2.commitAllowingStateLoss();
Change is also in TestFragment_DateBox when opening DatePicker:
DialogFragment datePicker = new TestFragment_DatePicker();
datePicker.setTargetFragment(this, 0);
datePicker.show(this.getFragmentManager(), "datePicker");
We need to run setTargetFragment in order to work.
Now this test works.
RxTextView.textChanges(editText)
.map(CharSequence::toString)
.debounce(200, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(input -> {
output = //...do something with input
editText.setText(ouput)
}));
When I setText(output) it goes in loop. To set the text I first need to remove listener and then set listener again. How can I do this using RxJava?
When I setText(output) it goes in loop. To set the text I first need to remove listener and then set listener again. How can I do this using RxJava?
To meet the requirement I managed to extend the RxBinding source code as follows.
EditableTextViewTextObservable.java:
public class EditableTextViewTextObservable extends InitialValueObservable<CharSequence> {
private final TextView view;
EditableTextViewTextObservable(TextView view) {
this.view = view;
}
#Override
protected void subscribeListener(Observer<? super CharSequence> observer) {
EditableTextViewTextObservable.Listener listener = new EditableTextViewTextObservable.Listener(view, observer);
observer.onSubscribe(listener);
view.addTextChangedListener(listener);
}
#Override protected CharSequence getInitialValue() {
return view.getText();
}
final static class Listener extends MainThreadDisposable implements TextWatcher {
private final TextView view;
private final Observer<? super CharSequence> observer;
Listener(TextView view, Observer<? super CharSequence> observer) {
this.view = view;
this.observer = observer;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if (!isDisposed()) {
view.removeTextChangedListener(this);
observer.onNext(s);
view.addTextChangedListener(this);
}
}
#Override
protected void onDispose() {
view.removeTextChangedListener(this);
}
}
}
EditableRxTextView.java:
public final class EditableRxTextView {
#CheckResult
#NonNull
public static InitialValueObservable<CharSequence> textChanges(#NonNull TextView view) {
return new EditableTextViewTextObservable(view);
}
}
Usage:
EditableRxTextView.textChanges(editText)
.map(CharSequence::toString)
.debounce(200, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(input -> {
output = //...do something with input
editText.setText(ouput)
}));
My solution was to use editText.getText().replace(...) as to not trigger the TextWatcher when setting the text
I have multiple ViewHolders that work as separated views inside a vertical RecyclerView. I'm practicing with the new Architecture Components ViewModel.
Inside my ViewModel I have a couple of MutableLiveData lists that i want to observe, but how can I call
ViewModelProviders.of((AppCompatActivity)getActivity()).get(FilterViewModel.class)
and
mFilterViewModel.getCountries().observe(this, new Observer<ArrayList<TagModel>>() {
#Override
public void onChanged(#Nullable ArrayList<TagModel> tagModels) {
}
});
without leaking the activity or save the activity inside the adapter?
my ViewModel
public class FilterViewModel extends ViewModel {
private final MutableLiveData<ArrayList<TagModel>> mCountries;
private final MutableLiveData<ArrayList<TagModel>> mSelectedCountryProvinceList;
private final MutableLiveData<ArrayList<TagModel>> mDistanceList;
public FilterViewModel(){
mCountries = new MutableLiveData<>();
mSelectedCountryProvinceList = new MutableLiveData<>();
mDistanceList = new MutableLiveData<>();
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mCountries.setValue(object.getCountries());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 5){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(5,"parent");
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mSelectedCountryProvinceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 6){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(6,"parent");
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mDistanceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 51){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(51,"parent");
}
public void selectCountry(final TagModel country){
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mSelectedCountryProvinceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == country.getId()){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(country.getId(),"parent");
}
public LiveData<ArrayList<TagModel>> getCountries(){
return mCountries;
}
public LiveData<ArrayList<TagModel>> getDistances(){
return mDistanceList;
}
public LiveData<ArrayList<TagModel>> getProvinces(){
return mSelectedCountryProvinceList;
}
I am using Room Persistence library. Below is my code for recyclerview adapter using MVVM.
You can see CartViewModel and I have initialized it into the constructor. The constructor gets the context from the activity, and I have cast it into FragmentActivity.
private CartViewModel cartViewModel;
public CartListAdapter(Context context, List<CartModel> cartModels) {
this.context = context;
this.cartModels = cartModels;
cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
}
Here is my full adapter class. I hope it will help.
public class CartListAdapter extends RecyclerView.Adapter<CartListAdapter.CartListViewHolder> {
private static final String TAG = "CartListAdapter";
private Context context;
private List<CartModel> cartModels;
private Double totalQuantity = 0.0;
private CartViewModel cartViewModel;
public CartListAdapter(Context context, List<CartModel> cartModels) {
this.context = context;
this.cartModels = cartModels;
cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
}
#NonNull
#Override
public CartListViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CartListViewHolder(LayoutInflater.from(context).inflate(R.layout.list_all_cart_item,parent,false));
}
#Override
public void onBindViewHolder(#NonNull CartListViewHolder holder, int position) {
CartModel cartModel = cartModels.get(position);
Glide.with(context)
.load(cartModel.getPPICLocate())
.into(holder.cartItemImage);
holder.tvCartProductName.setText(cartModel.getProductName());
holder.tvCartProductCategory.setText(cartModel.getPCategorySubID());
holder.tvCartProductPrice.setText(cartModel.getPPriceSales());
holder.etCartProductQuantity.setText(cartModel.getPQuantity());
holder.btnCartPQtIncrease.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
totalQuantity = totalQuantity+1;
cartModel.setPQuantity(totalQuantity.toString());
updateCart(cartModel);
}
});
holder.btnCartPQtDecrease.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
totalQuantity = totalQuantity-1;
cartModel.setPQuantity(totalQuantity.toString());
updateCart(cartModel);
}
});
}
#Override
public int getItemCount() {
return cartModels.size();
}
public class CartListViewHolder extends RecyclerView.ViewHolder{
private ImageView cartItemImage;
private TextView tvCartProductName,tvCartProductCategory,tvCartProductPrice,
etCartProductQuantity,tvCartProductPrevPrice;
private ImageButton btnCartPQtIncrease,btnCartPQtDecrease;
public CartListViewHolder(#NonNull View itemView) {
super(itemView);
cartItemImage= itemView.findViewById(R.id.cartItemImage);
tvCartProductName= itemView.findViewById(R.id.tvCartProductName);
tvCartProductCategory= itemView.findViewById(R.id.tvCartProductCategory);
tvCartProductPrice= itemView.findViewById(R.id.tvCartProductPrice);
etCartProductQuantity= itemView.findViewById(R.id.etCartProductQuantity);
tvCartProductPrevPrice= itemView.findViewById(R.id.tvCartProductPrevPrice);
btnCartPQtIncrease= itemView.findViewById(R.id.btnCartPQtIncrease);
btnCartPQtDecrease= itemView.findViewById(R.id.btnCartPQtDecrease);
}
}
public void addItems(List<CartModel> cartModels) {
this.cartModels = cartModels;
notifyDataSetChanged();
}
private void updateCart(CartModel cartModel){
String tqt = String.valueOf(cartModel.getPQuantity());
Log.d(TAG, "updateQuantity: "+tqt);
/*cartRepository.updateCartRepo(cartModel);*/
cartViewModel.updateCartItemVM(cartModel);
}
}
You could create an OnClickListener interface instead, then implement the onClick method (defined in your interface) in your fragment or activity where you have access to your view model.
My solution to this issue is;
create a new variable(ViewModel) for the layout (fragment or activity layout)
in your activity or fragment get the instance of your viewModel with ViewModelProviders
hold the data which fills your recyclerView in MutableLiveData and observe it and fill the adapter of recyclerView with the value you observed
here you mut be careful not to create adapter instance in observe method.
if you create it in observe method, it will make leaks
I have a custom TimePickerDialog that extends from Android's. This dialog has an interface OnTimeSetListener that has to be implemented by its Context or parent Fragment.
CustomTimePickerDialog.java
public class CustomTimePickerDialog extends DialogFragment implements
android.app.TimePickerDialog.OnTimeSetListener {
...
private OnTimeSetListener listener;
public static TimePickerDialog newInstance(int hour, int minutes) {
TimePickerDialog fragment = new TimePickerDialog();
return fragment;
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new android.app.TimePickerDialog(getContext(), this, 0, 0, true);
}
#Override
public void onTimeSet(TimePicker timePicker, int hour, int minutes) {
listener.onTimeSet(hour, minutes);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
Object parent = getParentFragment() == null
? context
: getParentFragment();
if (parent instanceof OnTimeSetListener) {
listener = ((OnTimeSetListener) parent);
} else {
throw new RuntimeException(parent + " must implement OnTimeSetListener");
}
}
public interface OnTimeSetListener {
void onTimeSet(int hour, int minutes);
}
}
The problem is that I need to extends this class again to change the onTimeSet() behaviour, like this:
LimitedCustomTimePickerDialog.java
public class LimitedCustomTimePickerDialog extends CustomTimePickerDialog {
#Override
public void onTimeSet(TimePicker timePicker, int hour, int minutes) {
int standardMinutes = minutes < 30 ? 0 : 30;
super.onTimeSet(timePicker, hour, standardMinutes);
}
}
But it is never called! How can I achieve this?
You implemented interface both side so who is calling onTimeSet? Just implement where you want to use this method.
I crated a datetime component but it's constructed automatically (I have it in a XML layout and I don't want to create it manually) but I need to pass a reference to an Activity in order to create dialogs. How can I achieve that? I tried a setter after findViewById but it's not a good solution...
public class DateTimeComponent extends RelativeLayout {
private Activity activity;
public DateComponent(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
// rest ommited
initFields();
}
private void initFields() {
dateEditText = (EditText) findViewById(R.id.dateEditText);
dateEditText.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
activity.showDialog(DATE_PICKER_DIALOG);
}
});
timeEditText = (EditText) findViewById(R.id.timeEditText);
timeEditText.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
activity.showDialog(TIME_PICKER_DIALOG);
}
});
}
// rest ommited
public Dialog getDatePickerDialog() {
int year = selectedDateTime.get(YEAR);
int month = selectedDateTime.get(MONTH);
int day = selectedDateTime.get(DAY_OF_MONTH);
return new DatePickerDialog(activity, onDateSetListener, year, month, day);
}
public Dialog getTimePickerDialog() {
int hour = selectedDateTime.get(HOUR_OF_DAY);
int minute = selectedDateTime.get(MINUTE);
return new TimePickerDialog(activity, onTimeSetListener, hour, minute, true);
}
private final OnDateSetListener onDateSetListener = new OnDateSetListener() {
#Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
// do something
}
};
private final OnTimeSetListener onTimeSetListener = new OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// do something
}
};
}
Perhaps this may help you:
Option 1:
public class DateTimeComponent extends RelativeLayout {
private Activity activity;
public DateTimeComponent(Activity act){
activity = act;
}
public void someListener() {
activity.showDialog(...);
}
}
Option 2:
public class DateTimeComponent extends RelativeLayout {
public void someListener(Activity act) {
act.showDialog(...);
}
}
Option 3:
...
private Activity activity;
public DateComponent(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
activity = (Activity) getContext();
// rest ommited
initFields();
}
...
Two ways -
Create a constructor that accepts a Context parameter, and have a (private?) class variable of type Context which you can use whenever.
Add an extra Context context parameter for every method that will be needing it. In some cases you may need to make that final.
The context your constructor receives IS an Activity. So, you can cast it to it. For example like this
MyActivity a = (MyActivity) getContext();
P.S. You do not need to store activity in your own field:
private Activity activity; // not needed
it is already stored inside and can be obtained by http://developer.android.com/reference/android/view/View.html#getContext()
PROOF
Custom text view:
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
setText(Integer.toString(System.identityHashCode(context)));
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setText(Integer.toString(System.identityHashCode(context)));
}
}
Activity:
public class ContextActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText( Integer.toString(System.identityHashCode(this)) );
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/textView" />
<com.inthemoon.incubation.MyTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
The codes diplayed are identical.