Strange behavior with ImageView reference and derived class - java

I created some custom component based on ConstraintLayout in Android Studio. First I created base abstract class called MyButton where I do some basic stuff (e.g. get references to my components). Next I created derived class called MySpecialButton that extends MyButton, but I have strange behavior when I attach onClickListener to my Button, that is a part of my custom component, and call method that modify element (reference) that exists only in MySpecialButton from onClickListener.
In a present code, when i try call setImage() from onClickListener, this end up with log: E/NULL: ImageView reference is null! which means that from point of view onClickListener, reference vImageViev is null, however it is initialized in inflateView call. But when I call setImage() not from onClickListener but directly from init() method after inflateView(R.layout.my_special_button) everything is OK.
Also when I move protected ImageView vImageView = null; declaration from MySpecialButton to MyButton everything is OK.
This is my MyButton class:
public abstract class MyButton extends ConstraintLayout
{
protected Context context = null;
protected View rootView = null;
protected Button vButton = null;
protected Switch vSwitch = null;
public MyButton(Context context)
{
super(context);
this.context = context;
init();
}
public MyButton(Context context, AttributeSet attrs)
{
this(context);
}
protected abstract void init();
protected void inflateView(int res)
{
rootView = inflate(context, res, this);
vButton = (Button)rootView.findViewById(R.id.vButton);
vSwitch = (Switch)rootView.findViewById(R.id.vSwitch);
}
}
and this is my MySpecialButton class:
public class MySpecialButton extends MyButton
{
protected ImageView vImageView = null;
public MySpecialButton(Context context)
{
super(context);
}
public MySpecialButton(Context context, AttributeSet attr)
{
this(context);
}
#Override
protected void inflateView(int res)
{
super.inflateView(res);
vImageView = (ImageView)rootView.findViewById(R.id.vImageView);
}
protected void init()
{
inflateView(R.layout.my_special_button);
vButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setImage();
}
});
}
protected void setImage()
{
if(vImageView == null)
Log.e("NULL", "ImageView reference is null!");
else
vImageView.setImageResource(R.drawable.ic_window);
}
}
What's going on? What I should do to be able call setImage() from onClickListener without null reference?

I think you are doing wrong super calls in your constructors:
This
public MySpecialButton(Context context, AttributeSet attr)
{
this(context);
}
Should be:
public MySpecialButton(Context context, AttributeSet attr)
{
super(context, attr);
}
Same for the other class. And move your custom init in a different function you call from each constructor.

thats because the setOnClickLisnter is called for the base class(which is ConstraintLayout) since you are not override it in the sub-class where the ImageView is not accessible.
try this:
public abstract class MyButton extends ConstraintLayout
{
protected Context context = null;
protected View rootView = null;
protected Button vButton = null;
protected Switch vSwitch = null;
//...
#Override
public void setOnClickListener(#Nullable OnClickListener l) {
vButton.setOnClickLisnter(l);
}
}

Related

Altering Java Program to use SQL data instead of Array in program MULTIPLE QUESTIONS [duplicate]

I have listview app exploring cities each row point to diffrent city , in each city activity include button when clicked open new activity which is infinite gallery contains pics of that city , i add infinite gallery to first city and work fine , when i want to add it to the second city , it gave me red mark error in the class as follow :
1- The type InfiniteGalleryAdapter is already defined.
2-The type InfiniteGallery is already defined.
I tried to change class name with the same result, I delete R.java and eclipse rebuild it with same result. Also I unchecked the java builder from project properties and get same red mark error.
Please any help and advice will be appreciated
thanks
My Code:
public class SecondCity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
// Set the layout to use
setContentView(R.layout.main);
if (customTitleSupported) {
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.custom_title);
TextView tv = (TextView) findViewById(R.id.tv);
Typeface face=Typeface.createFromAsset(getAssets(),"BFantezy.ttf");
tv.setTypeface(face);
tv.setText("MY PICTURES");
}
InfiniteGallery galleryOne = (InfiniteGallery) findViewById(R.id.galleryOne);
galleryOne.setAdapter(new InfiniteGalleryAdapter(this));
}
}
class InfiniteGalleryAdapter extends BaseAdapter {
**//red mark here (InfiniteGalleryAdapter)**
private Context mContext;
public InfiniteGalleryAdapter(Context c, int[] imageIds) {
this.mContext = c;
}
public int getCount() {
return Integer.MAX_VALUE;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
private LayoutInflater inflater=null;
public InfiniteGalleryAdapter(Context a) {
this.mContext = a;
inflater = (LayoutInflater)mContext.getSystemService ( Context.LAYOUT_INFLATER_SERVICE)
}
public class ViewHolder{
public TextView text;
public ImageView image;
}
private int[] images = {
R.drawable.pic_1, R.drawable.pic_2,
R.drawable.pic_3, R.drawable.pic_4,
R.drawable.pic_5
};
private String[] name = {
"This is first picture (1) " ,
"This is second picture (2)",
"This is third picture (3)",
"This is fourth picture (4)",
" This is fifth picture (5)"
};
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i = getImageView();
int itemPos = (position % images.length);
try {
i.setImageResource(images[itemPos]); ((BitmapDrawable) i.getDrawable()).
setAntiAlias (true);
}
catch (OutOfMemoryError e) {
Log.e("InfiniteGalleryAdapter", "Out of memory creating imageview. Using empty view.", e);
}
View vi=convertView;
ViewHolder holder;
if(convertView==null){
vi = inflater.inflate(R.layout.gallery_items, null);
holder=new ViewHolder(); holder.text=(TextView)vi.findViewById(R.id.textView1);
holder.image=(ImageView)vi.findViewById(R.id.image);
vi.setTag(holder);
} else {
holder=(ViewHolder)vi.getTag();
}
holder.text.setText(name[itemPos]);
final int stub_id=images[itemPos];
holder.image.setImageResource(stub_id);
return vi;
}
private ImageView getImageView() {
ImageView i = new ImageView(mContext);
return i;
}
}
class InfiniteGallery extends Gallery {
**//red mark here (InfiniteGallery)**
public InfiniteGallery(Context context) {
super(context);
init();
}
public InfiniteGallery(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public InfiniteGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
// These are just to make it look pretty
setSpacing(25);
setHorizontalFadingEdgeEnabled(false);
}
public void setResourceImages(int[] name){
setAdapter(new InfiniteGalleryAdapter(getContext(), name));
setSelection((getCount() / 2));
}
}
You are getting those red marks as these class are already defined in one of your previous class. Java won't let have duplicate names. Also it seems you are trying to define same classes for every Actvitiy which is redundant.
Just remove the two classes completely from your SecondActivity java file as they are already defined in a previous activity. I would suggest you to make a separate package where the Adapter and InfiniteGallery are defined and kept to be reused .
public class SecondCity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
// Set the layout to use
setContentView(R.layout.main);
if (customTitleSupported) {
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.custom_title);
TextView tv = (TextView) findViewById(R.id.tv);
Typeface face=Typeface.createFromAsset(getAssets(),"BFantezy.ttf");
tv.setTypeface(face);
tv.setText("MY PICTURES");
}
InfiniteGallery galleryOne = (InfiniteGallery) findViewById(R.id.galleryOne);
galleryOne.setAdapter(new InfiniteGalleryAdapter(this));
}
}
You might have even defined the class with the same name on some other file in the same folder. Which can cause this error.
Use Ctrl+H -> Java Search -> Search for Type
It will tell you where the duplicated class is.

Getting MainActivity context in CustomView class

I have 2 classes: MainActivity and CustomView. I have an XML layout with this CustomView.
I want to access all my MainActivity variables from my CustomView class and also to modify them, I tried to get the context but it didn't work.
MainActivity class:
MyCustomView customV;
int myVar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_page);
customV = (MyCustomView) findViewById(R.id.view2);
myVar = 5;
}
MyCustomView class:
public class MyCustomView extends TextView {
public MyCustomView(Context context) {
super(context);
init();
}
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
context.myVar = 7 //this is what I'm trying to do...
I also tried getContext which didn't work.
By trying to access variables from your Activity directly in your TextView subclass, you introduce tight coupling between you subclass of Actity and your custom TextView, which essentially hinders the reusability of your custom TextView because it can then only be used in that type of Activity, using it in another layout would break everything. Basically, I would say it's bad design and would not recommend that approach.
You could simply add a method to your custom TextView, and use the variable there :
public class MyCustomView extends TextView {
// your code
public void setVariable(int myInt){
//use the int here, either set a member variable
//or use directly in the method
}
}
and in your Activity
customV = (MyCustomView) findViewById(R.id.view2);
customV.setVariable(5);
Best way to do so is,
public class MyCustomView extends TextView {
private MainActivity mActivity;
public void setActivity(MainActivity activity) {
mActivity = activity;
}
public MyCustomView(Context context) {
super(context);
init();
}
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
}
Instantiate,
customView = (MyCustomView) findViewById(R.id.view2);
customView.setActivity(this);
Access variable inside functions in MyCustomView,
mActivity.myVar = 10;
If you don't care about the fact that you are tightly coupling your two classes, then the only thing you need to do is typecast your "context" variable to MainActivity. Something like:
((MainActivity) context).myVar = 5;
will work. But you really should consider an alternate design that only loosely couples your classes.
or make the variable static and use it like this.
MainActivity.myVar=7;
or if you want to initialize in the custom view depend on a variable from the MainActivity then do it like that in the custom view.
private int myVar;
public void init(int myVar) {
this.myVar = myVar;
invalidate();
in MainActivity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_page);
customV = (MyCustomView) findViewById(R.id.view2);
myVar = 5;
customV.init(myVar);
}
i hope this help you.

How to create interface between Fragment and adapter?

I have fragment with ListView, say MyListFragment, and custom CursorAdapter.
I'm setting onClickListener in this adapter for the button in the list row.
public class MyListAdapter extends CursorAdapter {
public interface AdapterInterface {
public void buttonPressed();
}
...
#Override
public void bindView(final View view, final Context context, final Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
...
holder.button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// some action
// need to notify MyListFragment
}
});
}
}
public MyListFragment extends Fragment implements AdapterInterface {
#Override
public void buttonPressed() {
// some action
}
}
I need to notify fragment when the button is pressed. How to invoke this interface?
Help, please.
Make a new constructor and an instance variable:
AdapterInterface buttonListener;
public MyListAdapter (Context context, Cursor c, int flags, AdapterInterface buttonListener)
{
super(context,c,flags);
this.buttonListener = buttonListener;
}
When the Adapter is made, the instance variable will be given the proper reference to hold.
To call the Fragment from the click:
public void onClick(View v) {
buttonListener.buttonPressed();
}
When making the Adapter, you will have to also pass your Fragment off to the Adapter. For example
MyListAdapter adapter = new MyListAdapter (getActivity(), myCursor, myFlags, this);
since this will refer to your Fragment, which is now an AdapterInterface.
Keep in mind that on orientation of the Fragment changes, it will most likely be recreated. If your Adapter isn't recreated, it can potentially keep a reference to a nonexistent object, causing errors.
Using Eventbus:
Examples:
https://github.com/kaushikgopal/RxJava-Android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus
or
https://github.com/greenrobot/EventBus
Using Interfaces:
I understand the current answer but needed a more clear example. Here is an example of what I used with an Adapter(RecyclerView.Adapter) and a Fragment.
Create Callback Interface:
public interface AdapterCallback {
void onMethodCallback();
}
Passing in Callback/Fragment:
This will implement the interface that we have in our Adapter. In this example, it will be called when the user clicks on an item in the RecyclerView.
In your Fragment:
public class MyFragment extends Fragment implements AdapterCallback {
private MyAdapter mMyAdapter;
#Override
public void onMethodCallback() {
// do something
}
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mMyAdapter = new MyAdapter(this); // this class implements callback
}
}
Use the Callback in your Adapter:
In the Fragment, we initiated our Adapter and passed this as an argument to the constructer. This will initiate our interface for our callback method. You can see that we use our callback method for user clicks.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(AdapterCallback callback) {
this.mAdapterCallback = callback;
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mAdapterCallback.onMethodCallback();
}
});
}
}
or Use the Fragment in your Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(Fragment fragment) {
try {
this.mAdapterCallback = ((AdapterCallback) fragment);
} catch (ClassCastException e) {
throw new ClassCastException("Fragment must implement AdapterCallback.");
}
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
mAdapterCallback.onMethodCallback();
} catch (ClassCastException exception) {
// do something
}
}
});
}
}
Follow the 2 steps below for receive callback from Adapter in Fragment (or Activity)
First: In your Adapter
public class ListAdapter extends RecyclerView.Adapter < RecyclerListAdapter.ItemViewHolder > {
...
private ListAdapterListener mListener;
public interface ListAdapterListener { // create an interface
void onClickAtOKButton(int position); // create callback function
}
public RecyclerListAdapter(Context mContext, ArrayList < Items > listItems, ListAdapterListener mListener) { // add the interface to your adapter constructor
...
this.mListener = mListener; // receive mListener from Fragment (or Activity)
}
...
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
holder.btnOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// use callback function in the place you want
mListener.onClickAtOKButton(position);
}
});
...
}
...
}
Second: In your Fragment (or Activity), there are 2 ways for implement callback method
Way 1
public MyListFragment extends Fragment {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
...
ListAdapter adapter = new ListAdapter(getActivity(), listItems, new ListAdapter.ListAdapterListener() {
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
});
...
}
}
Way 2
public MyListFragment extends Fragment implements ListAdapter.ListAdapterListener {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
ListAdapter adapter = new ListAdapter (getActivity(), listItems, this);
...
}
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
}
This is very similar to the way an activity and a fragment should communicate. In the constructor of your adapter, pass a reference of your fragment, cast it to your interface and just call yourReference.buttonPressed() on your onClick method.
a solution for NPE is first to make conctractor in your Fragment like that
public MyFragment MyFragment(){
return this;
}
then initialize your listener is adapter like that
Lisener lisener = new MyFragment();
Make a constructor like that:
public MyAdapter(Activity activity,AlertMessageBoxOk alertMessageBoxOk) {
this.mActivity = activity;
mAlertMessageBoxOk = alertMessageBoxOk;
}
call the interface from adapter use any event
mAlertMessageBoxOk.onOkClick(5);
after that implement AlertMessageBoxOk interface to your fragment like this,
class MyFragment extends Fragment implements AlertMessageBoxOk {
#Override
public void onOkClick(int resultCode) {
if(resultCode==5){
enter code here
}
}
}

Android webview is playing video only once

I am using webview in android to play a video. The problem is that video is playing once. I have seen some answers about how to fix it, but still not working. Here's my code:
public class MyChromeClient extends WebChromeClient implements
OnCompletionListener, OnErrorListener {
private Activity _activity;
private VideoView mCustomVideoView;
private LinearLayout mContentView;
private FrameLayout mCustomViewContainer;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT, Gravity.CENTER);
public MyChromeClient(Activity context) {
super();
_activity = context;
}
#Override
public void onShowCustomView(View view, CustomViewCallback callback) {
super.onShowCustomView(view, callback);
if (view instanceof FrameLayout) {
FrameLayout frame = (FrameLayout) view;
if (frame.getFocusedChild() instanceof VideoView) {
mCustomVideoView = (VideoView) frame.getFocusedChild();
frame.removeView(mCustomVideoView);
_activity.setContentView(mCustomVideoView);
mCustomVideoView.setOnCompletionListener(this);
mCustomVideoView.setOnErrorListener(this);
mCustomVideoView.start();
}
}
}
public void onHideCustomView() {
if (mCustomVideoView == null)
return;
// Hide the custom view.
mCustomVideoView.setVisibility(View.GONE);
// Remove the custom view from its container.
mCustomViewContainer.removeView(mCustomVideoView);
mCustomVideoView = null;
mCustomViewContainer.setVisibility(View.GONE);
mCustomVideoView.stopPlayback();
mCustomViewCallback.onCustomViewHidden();
// Show the content view.
mContentView.setVisibility(View.VISIBLE);
}
public void onCompletion(MediaPlayer mp) {
//Intent intent = new Intent(_activity, _activity.getClass());
//intent.setClass(_activity, _activity.getClass());
//_activity.startActivity(intent);
//_activity.finish();
}
public boolean onError(MediaPlayer mp, int what, int extra) {
return true;
}
}
try this
add this in show method
WebChromeClient.CustomViewCallback CustomViewCallback; mCustomViewCallback = callback;
then in hide method...
mCustomViewCallback.onCustomViewHidden(); mCustomViewCallback = null; HTML5WebView.this.goBack();
EDIT :-
public class HTML5WebView extends WebView {
static final String LOGTAG = "HTML5WebView";
private void init(Context context) {
mContext = context;
Activity a = (Activity) mContext;
mLayout = new FrameLayout(context);
mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(a).inflate(R.layout.custom_screen, null);
mContentView = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.main_content);
mCustomViewContainer = (FrameLayout) mBrowserFrameLayout.findViewById(R.id.fullscreen_custom_content);
mLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
// Configure the webview
WebSettings s = getSettings();
s.setBuiltInZoomControls(true);
s.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
s.setUseWideViewPort(true);
s.setLoadWithOverviewMode(true);
s.setSaveFormData(true);
s.setJavaScriptEnabled(true);
mWebChromeClient = new MyWebChromeClient();
setWebChromeClient(mWebChromeClient);
setWebViewClient(new WebViewClient());
setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
s.setDomStorageEnabled(true);
mContentView.addView(this);
}
public HTML5WebView(Context context) {
super(context);
init(context);
}
public HTML5WebView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public HTML5WebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public FrameLayout getLayout() {
return mLayout;
}
public boolean inCustomView() {
return (mCustomView != null);
}
public void hideCustomView() {
mWebChromeClient.onHideCustomView();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((mCustomView == null) && canGoBack()){
goBack();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
private class MyWebChromeClient extends WebChromeClient {
private Bitmap mDefaultVideoPoster;
private View mVideoProgressView;
FrameLayout frame;
#Override
public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback)
{
HTML5WebView.this.setVisibility(View.GONE);
isVideoPlaying = true;
// if a view already exists then immediately terminate the new one
if (mCustomView != null) {
callback.onCustomViewHidden();
return;
}
mCustomViewContainer.addView(view);
mCustomView = view;
frame = (FrameLayout) mCustomView;
mCustomViewCallback = callback;
VideoView mVideoView;
if(frame.getFocusedChild() instanceof VideoView){
mVideoView = (VideoView) frame.getFocusedChild();
}
mCustomViewContainer.setVisibility(View.VISIBLE);
}
#Override
public void onHideCustomView() {
if (mCustomView == null)
return;
// Hide the custom view.
mCustomView.setVisibility(View.GONE);
// Remove the custom view from its container.
mCustomViewContainer.removeView(mCustomView);
mCustomView = null;
mCustomViewContainer.setVisibility(View.GONE);
mCustomViewCallback.onCustomViewHidden();
mCustomViewCallback = null;
HTML5WebView.this.setVisibility(View.VISIBLE);
HTML5WebView.this.goBack();
}
}
}
I would like to offer an alternative, it may not be perfect, but from a web programming point of view, after beating my head against this for some time, the trick was to covert the video to base64 and the feed it to the source tag (jquery in my case). If it isn't in the assets folder it can't get confuse!

How to pass an Activity reference to my own component

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.

Categories