This is a followup to this post:
findViewById in a subclassed SurfaceView throwing RuntimeException
Based on Romain Guy's feedback (which I'll accept shortly as it is a solution), I'd like to obtain the calling Activity from within the View, so that I can use it to obtain the desired TextView resource.
I don't see any methods in View that return Activity. What is the proper way to do this? Or is there a better alternative for working with TextViews from within another View context.
Basically, I am calling setContentView(R.layout.xxx) in onCreate() (as usual), so I don't really have a way to pass in references to additional TextViews unless I awkwardly retrieve the View after setContentView and then make calls on it.
An Activity is a Context, but there is no guarantee that the Context used by a View is always an Activity. Getting the views from onCreate() to do some setup is perfectly valid and is how Android applications are usually written. You could do something like this for instance:
setContentView(...);
MySurfaceView v = findViewById(R.id.theusrface);
TextView t = findViewById(R.id.thecontent);
v.setContent(v);
The logic should not go in your Views.
If you already know the Activity class your View is in, i.e. MyActivity, you can use the static member MyActivity.this from inside your View and its listeners, as in the following example:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
MyActivity.this.finish();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
which I've found in this Android tutorial:
http://developer.android.com/guide/topics/ui/dialogs.html
It worked wonders for me.
PJ_Finnegan
Related
I'm developing an Android app. Currently I've implemented custom list view in Alert Dialog. This is the code so far:
private void setupAlertDialogBuilder(final Context context) {
GiftStoreCountriesAdapter giftStoreCountriesAdapter = new GiftStoreCountriesAdapter(context,
R.layout.gift_store_countries_row,
giftStoreCountriesViewModel.fetchCountriesFromLocalDatabase(),
(HomeActivity) context);
builder = new AlertDialog.Builder(context)
.setIcon(R.drawable.ic_currency_icon)
.setAdapter(giftStoreCountriesAdapter, new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
handleCountrySelection(dialog, which);
}
});
builder.create().getListView().setFastScrollEnabled(true);
builder.create().getListView().smoothScrollToPosition(scrollToPosition(context));
}
Everything works fine except one thing. How can I programmatically scroll that custom list view to the some position or index of row as soon as alert dialog is shown to user. I've tried with this:
builder.create().getListView().setFastScrollEnabled(true);
builder.create().getListView().smoothScrollToPosition(scrollToPosition(context));
but it doesn't work. If I put just:
getListView().smoothScrollToPosition(scrollToPosition(context));
without builder.create() I get NullPointerException. This is in class that is custom Alert Dialog and it extends AlertDialog. I need to automatically scroll this list when it's shown to user. I appreciate all your help.
I have a little problem with a Dialog.
It's a ListView of Videos with thumbnails that load the videos with an Adapter. The ListView register an OnItemClickListener and inside the OnClickItem method I try to raise the Dialog.
I've tried with various types of Dialog but nothing happened. A simplified piece of code it's here:
public class ListOfVideos extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_of_videos);
init_phone_video_grid();
}
private void init_phone_video_grid() {
// Here's some code for the video reading
// The ListView
videolist = (ListView) findViewById(R.id.PhoneVideoList);
videolist.setAdapter(new VideoAdapter(getApplicationContext()));
videolist.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
// Here's some code for the video reading
/** ============= Here's the problem ================ **/
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
builder.setMessage("Example Message")
.setTitle("This is the title!!")
.setCancelable(false)
.setNeutralButton("Ok",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
System.out.println("[debug]" + "Open File " + filename);
}
});
}
The list of videos load perfectly. But when I click on an Item:
The Dialog does not show
I got a error message in the LogCat, that state: "show() Dialog's window is null!"
The println debug message, appears ok in the LogCat
I have searched for that message error, but there's not much information.
I think the problem could be on the Context that receive the Builder, but I'm stuck on this point.
Any advice will be apreciated
That error message is saying that the Context given to the AlertDialog.Builder has no attached window, which Dialogs need as a UI anchor, basically. An Activity is what should be used for such a Context, as it will have the required window.
Without seeing VideoAdapter's code, the root cause is presumably new VideoAdapter(getApplicationContext()), which is handing your VideoAdapter the application Context to build Views with. That likely means that the v passed into onItemClick() is one such View, and v.getContext() is returning that application Context in new AlertDialog.Builder(v.getContext()).
That application Context does not have a window but your Activity does, as mentioned. Furthermore, the Activity is actually what you want to give to VideoAdapter to build Views with anyway, to ensure that they are created with the correct theme and styling. Change that relevant line to:
videolist.setAdapter(new VideoAdapter(ListOfVideos.this));
That alone might solve the issue, depending on what VideoAdapter does internally. However, it's arguably better to specify the Activity again in the AlertDialog.Builder constructor call, just so there's no question:
AlertDialog.Builder builder = new AlertDialog.Builder(ListOfVideos.this);
As a final note, whenever a Context is needed for any UI component, you usually want to use the immediately available Activity.
Here is a example of How to create dialog box..
String message = "Hello";
AlertDialog.Builder alt_bld = new AlertDialog.Builder(
CurrentActi.this);
alt_bld.setTitle("Alert")
.setMessage(message)
.setCancelable(false)
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//here right the code that you want perform onClick
dialog.cancel();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = alt_bld.create();
alert.setTitle("Alert");
alert.show();
May be it will help you..
Could someone point out a working example of a custom dialog that takes an ArrayAdapter as input and shows a selectable list.
I have tried to create a Dialog using an AlertDialog Builder as such...
final ArrayAdapter<MyObject> myAdapter = getMyobjects();
final AlertDialog.Builder builder = new AlertDialog.Builder(this).setTitle("Pick an item").setAdapter(myAdapter,
new android.content.DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int item) {
Toast.makeText(Islands.this, myAdapter.getItem(item).toString(), Toast.LENGTH_SHORT).show();
}
});
final AlertDialog alert = builder.create();
return alert;
My problem is that my dialog is not updating then i called
#Override
protected void onPrepareDialog(final int id, final Dialog dialog) {
switch (id) {
case DIALOG_GET_AVAIL_DESTS:
((AlertDialog) dialog).getListView().setAdapter( getDestinations());
break;
}
}
However the onClick listener listens to the initial set of items...
Indeed AlertDialog is implements Facade design pattern with this class behind :
http://www.netmite.com/android/mydroid/frameworks/base/core/java/com/android/internal/app/AlertController.java
And the whole code is such a mess...
I took 3 hours to try to do that, and I am going to build a dialog from scratch, using android.R.layout as a basis.
Steff
You have to make a call to
invalidateViews()
on your listview - that will cause it to redraw the view with the updates.
Since you are using onPrepareDialog(int id, Dialog dialog), I am guessing you're initially setting up the dialog in onCreateDialog(int id).
Doing so cause the system to save the dialog you initially create. In order to achieve the desired functionality, when the dialog is dismissed, tell the system to discard it by calling android.app.Activity.removeDialog(int id).
Any subsequent invocations will have your dialog regenerated through the onCreateDialog(int id) method, causing the set of items to be updated.
I'm using and ArrayAdapter to populate a ListView. After selecting and item, it displays a confirmation Y/N dialog. If the user's choice is negative, then he should be able to select another item showing the same dialog. And so on.
Here's my code:
lView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(final AdapterView<?> parent, final View v, final int index, final long id) {
Toast.makeText("Selected file"+ mFiles.get(index).getfileName(),
Toast.LENGTH_SHORT).show();
SelectedFile = mFiles.get(index);
showDialog(DIALOG_CONFIRMIMPORT_ID);
}
});
The weird thing is that while the "Toast" shows the clicked item every time, only the first selected item since the Activity is initiated is being passed to "SelectedFile". No matter how many times you click a diferent item, "SelectedFile" always assumes the same value, the value of the first clicked item, outside of this code.
Heres's my Dialog code:
Protected Dialog onCreateDialog(int id) {
switch(id) {
case DIALOG_CONFIRMIMPORT_ID:
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String message = String.format(getString(R.string.importstudentfileconfirm),SelectedFile.getfileName());
builder.setMessage(message)
.setCancelable(false)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Activity.this.finish();
// startActivity(new Intent(Activity.this, LOL.class));
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SelectedFile = null;
dismissDialog(DIALOG_CONFIRMIMPORT_ID);
mFiles.notifyAll();
}
});
AlertDialog alert = builder.create();
return alert;
}
}
return null;
}
Thank you very much for any help!
I'm guessing this has something to do with the fact that the onCreateDialog method is only called the first time the dialog is created. So the first time you see the dialog it will have the correct filename.
After onCreateDialog is called, onPrepareDialog(...) is called. onPrepareDialog, allows you to change the dialog after it has been created, but before it gets displayed.
Remember that underneath everything, Android isn't creating a new Dialog for you every time you want to show the DIALOG_CONFIRMIMPORT_ID dialog. It is too computationally expensive to instantiate a new dialog every time. Instead, it creates it once, which causes onCreatDialog to be called, followed by the onPrepareDialog. Every other time the dialog is shown, it only calls onPrepareDialog.
Check out the following article on the Android Developer site. It explains things pretty clearly.
http://developer.android.com/guide/topics/ui/dialogs.html#ShowingADialog
So try using onCreateDialog just for initialization of stuff that won't change between showings of the dialog, then use the onPrepareDialog method to dynamically update the contents of the dialog (i.e. getting the new filename)
Cheers!
I have a multiplechoice dialog on my activity. I have a boolean array to keep track of which items are selected from the dialog. So I want each time an item is clicked to make the corresponding place on my array true. The array is being created in the onCreateDialog before the return.
public Dialog onCreateDialog(int id) {
userlistlocal=getuserlist(username);
boolean[] usernamechecked=new boolean[userlistlocal.length/3];
Arrays.fill(usernamechecked,false);
return new AlertDialog.Builder(Newevent.this)
.setIcon(R.drawable.ic_menu_invite)
.setTitle("Add People")
.setMultiChoiceItems(userselectionlistlocal,
null,new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog, int whichButton,
boolean isChecked) {
/* User clicked on a check box do some stuff */
usernamechecked[whichButton]=isChecked;<-------HERE
}
})
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked Yes so do some stuff */
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked No so do some stuff */
}
})
.create();
}
But when I put in the onClick method my boolean array it says it has to be final(Cannot refer to a non-final variable usernamechecked inside an inner class defined in a different method). I dont know what to do
You cannot access your array if it is not declared final. But if it is declared final you have to consider that you can't modify it any more.
A method to resolve this problem is to define the OnMultiChoiceClickListener not as an anonymous inner class. For example you could define it as a inner class in the same class or even as a separate class.
you defined usernamechecked inside the onCreateDialog method, it only exists inside the scope of this method. You should define it as a member of your activity class or of the inner class. Since its size is dependent on a call to getuserlist, which i assume is a method of your activity class, i would add it as a member of your activity class although this is up to you.
Define usernamechecked as a member of your activity class as:
private boolean usernamechecked[];
I'd also move
userlistlocal=getuserlist(username);
usernamechecked=new boolean[userlistlocal.length/3];
Arrays.fill(usernamechecked,false);
to your onCreate Method (or some other initialization method) if possible as it looks like it has nothing to do with the dialog creation but this is just a style / maintainability issue.