I'm making my first android game, and I have the general things I wanted implemented with knowledge on making simple games in java and C#. For this I have the main class which extends Activity, then I have that create an object of a GameView class which extends SurfaceView, and setContentView to that class.
Here's some of that code:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
gameView = new GameView(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(gameView);
In my GameView class I have all the usual parts of a simple game, with a loop, and Sprite objects etc. This is all working great, until it comes to opening an AlertDialog to take text input from a user for saving the game. This is the part where i'm worried I've 'missed the point' of programming in android, because I've tried implementing solutions to this shown
here:
Android AlertDialog inside AsyncTask
and here:
How do I display an alert dialog on Android?
and here:
http://www.androidsnippets.com/prompt-user-input-with-an-alertdialog
I get the error 'Can't create handler inside thread that has not called Looper.prepare()' the few times I've attempted these. I've gotten almost close to finishing this project and now I think I've missed fundamental android programming structure. The problem is I don't really know where I should be creating and showing the AlertDialog, should it be inside the main Activity, or the GameView SurfaceView. And if it is in the main activity, how do I exit out of the GameView back into the activity, and return some data for the next (view?) to use in an AlertDialog.
I'm sorry if this seems too vague, its just since I've tried to create an AlertDialog, its thrown off my understanding and I feel like I'm missing something.
So my question is, whats wrong with my structure, and more specifically, where do I put the AlertDialog; can I run it in some method or class that is called from my GameView class, or do I need to exit/end out of that class back into the main activity, and run it inside that?
private class myAsyncTask extends AsyncTask<String, Void, String> {
AlertDialog alertDialog;
protected void onPreExecute()
{
super.onPreExecute();
alertDialog = new AlertDialog.Builder(this);
}
#Override
protected String doInBackground(String... params)
{
return null;
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
alertDialog.setTitle("The Process");
//alertDialog.setIcon(R.drawable.success);
alertDialog.setCanceledOnTouchOutside(false);
alertDialog.setMessage("All done!");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
}
});
alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener()
{
#Override
public void onDismiss(DialogInterface dialog)
{
}
});
alertDialog.show();
}
}
You have to show the Alert dailog inside onPostExecute method then only you can show. You can display Alert Dailog inside background running method.
Prefer below link:
Android AlertDialog inside AsyncTask
Updated
Instead of AlertDialog alertDialog use
AlertDialog.Builder alertDialogBuilder
Then After that create the Dialog
final AlertDialog alertDailog = alertDialogBuilder.create();
And at the end :
alertDailog.show();
Related
I have successfully implemented a custom Dialog box that appears when the user tries to leave an activity via a back button or by using onBackPressed(). They can simply cancel the dialog box or continue, and leave the activity. This function has been implemented in multiple activities, however its making my code a lot longer than it needs to be. I wanted to know how to create a util that can be referenced in different activities, without the need for the chunk of code to copy pasted multiple times. Please note that I am retrieving the dialog title and description from string.xml
This is my code:
Dialog customDialog;
Button button_one, button_two;
TextView dialog_title, dialog_description;
customDialog = new Dialog(this);
//Back button will close app
#Override
public void onBackPressed() {
customDialog.setContentView(R.layout.custom_dialog_box);
dialog_title = customDialog.findViewById(R.id.dialog_title);
dialog_title.setText(getString(R.string.leaving_activity_warning_title));
dialog_description = customDialog.findViewById(R.id.dialog_description); dialog_description.setText(getString(R.string.leaving_activity_warning_description));
button_one = customDialog.findViewById(R.id.button_one);
button_one.setText(getString(R.string.cancel));
button_two = customDialog.findViewById(R.id.button_two);
button_two.setText(getString(R.string.leave_anyway));
button_one.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
customDialog.dismiss();
}
});
button_two.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
customDialog.dismiss();
finish();
overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);
}
});
Objects.requireNonNull(customDialog.getWindow()).setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
customDialog.show();
}
UPDATE
Created a Java file called "DialogBoxMessage"
DialogBoxMessage Code:
class DialogBoxMessage {
private Dialog customDialog;
private TextView dialog_title, dialog_description;
private Button button_one, button_two;
//Custom Dialog Box Initialization
DialogBoxMessage(Button myButtonOne, TextView myDialogTitle, TextView myDialogDescription, Dialog myCustomDialog) {
customDialog = myCustomDialog;
button_one = myButtonOne;
button_two = myButtonOne;
dialog_title = myDialogTitle;
dialog_description = myDialogDescription;
}
void leaveActivity() {
customDialog.setContentView(R.layout.custom_dialog_box);
dialog_title = customDialog.findViewById(R.id.dialog_title);
dialog_title.setText(Resources.getSystem().getString(R.string.leaving_activity_warning_title));
dialog_description = customDialog.findViewById(R.id.dialog_description);
dialog_description.setText(Resources.getSystem().getString(R.string.leaving_activity_warning_description));
button_one = customDialog.findViewById(R.id.button_one);
button_one.setText(Resources.getSystem().getString(R.string.cancel));
button_two = customDialog.findViewById(R.id.button_two);
button_two.setText(Resources.getSystem().getString(R.string.leave_anyway));
button_one.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
customDialog.dismiss();
}
});
button_two.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
customDialog.dismiss();
}
});
Objects.requireNonNull(customDialog.getWindow()).setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
customDialog.show();
}
}
I input the following code in another activity
Other activity code:
//Reusable exit dialog message
DialogBoxMessage dialogBoxMessage;
//Back button will close app
#Override
public void onBackPressed() {
dialogBoxMessage.leaveActivity();
finish();
}
But it doesn't seem to work, I think there are a lot of issues... please help :(
I assume customDialog is a seperate class you wrote - therefore i would suggest you put main information like contentview, title, message or type in the constructor when you initialize ur Dialog.
For your onClick Method I suggest you create an Interface to handle Button Clicks in your
customDialog class.
This could be implemented as a static method in a utilities class. The method would require 'this' as a parameter, which contains the activity context. The method should return the result of the button press. The activity can use this response to determine if finish() should be called or not.
UPDATE
I had suggested a simple static method, but you've gone down the object-oriented route. That's fine.
However, your constructor requires passing in several views, which wouldn't appear to achieve the code efficiency you are after.
Your constructor should just require the Activity context; everything else is encapsulated in your new class.
In each Activity's onBackPressed method you will need to create the object with
dialogBoxMessage = new DialogBoxMessage(this);
before you can call any of that object's methods.
I have an Android application with an AsyncTask which is responsible for downloading a file from the internet. This AsyncTask is executed when clicking on an item in a Listview. So I have a custom adapter and in the OnItemClickListener of the Listview, I start the download and execute the AsyncTask.
Now, my adapter contains the following code to start the AsyncTask named FileDownloader:
#Override
public void onClick(View view) {
try {
FileDownloader fd = new FileDownloader(activity);
// some irrelevant code here
String filepath = fd.execute("http://myurl.com/img.png", PDFFileName, GameHistoryAdapter.this.gameInfo.toString()).get();
}
catch(Exception e) { e.printStackTrace(); }
}
Activity is a private field that is passed to the adapter in the constructor of the adapter:
public GameHistoryAdapter(Activity a, int selectedIndex) {
this.activity = a;
}
The FileDownloader class contains an OnPreExecute method where I want to show the progress dialog on the activity:
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(activity);
dialog.setMessage("Downloading...");
dialog.setIndeterminate(true);
dialog.setCancelable(true);
dialog.show();
}
But whatever I try, the dialog does not appear. When I create an alert dialog in the OnPostExecute method of the AsyncTask, the dialog will show.
#Override
protected void onPostExecute(String res)
{
super.onPostExecute(res);
dialog.hide();
new AlertDialog.Builder(activity)
.setTitle(activity.getString(R.string.save_pdf_title_text))
.setMessage(activity.getString(R.string.save_pdf_text) + PDFFileName)
.setPositiveButton(activity.getString(R.string.close_text), null)
.setIcon(android.R.drawable.ic_dialog_info)
.show();
}
Does anyone know why the dialog is not appearing on my activity?
Does anyone know why the dialog is not appearing on my activity?
Yes, the following line of code...
String filepath = fd.execute("http://myurl.com/img.png", PDFFileName, GameHistoryAdapter.this.gameInfo.toString()).get();
Don't EVER use the get() method of AsyncTask. It will block the main / UI thread and makes the whole point of an AsyncTask redundant. In other words get() turns it into a synchronous process instead of an asynchronous one.
The fact you can show a dialog in onPostExecute(...) is simply because it will be called after the blocking call to get() has returned. This means the main / UI thread will no longer be frozen (blocked) and UI updates can be made once again.
Remove get() from your call to execute(...) and instead just use...
fd.execute("http://myurl.com/img.png", PDFFileName, GameHistoryAdapter.this.gameInfo.toString());
...then in your onPostExecute(...) method set you filepath variable to what it should be.
I don't know who added the get() method to AsyncTask but if I ever find them I'll have some serious words to say. It has little or no use and causes a lot of people a lot of confusion.
I am developing an Android app which has 2 classes. Game, which extends Activity, and GameView, which extends View.
When the game is loaded, it sets the content view to GameView, which is just a drawing class that uses a canvas to display the game.
I am trying to create a ProgressDialog in the Game class which will show a spinner after a certain action has been done, as this takes a long time to complete. So far I have the following:
setContentView(R.layout.activity_game);
ProgressDialog pd = new ProgressDialog(this);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setMessage("Calculating hint");
pd.show();
AsyncTask<String[][], Void, SudokuSquare> nextSquareThread = new GetNextSquare().execute(puzzleNumbers);
next = nextSquareThread.get();
pd.dismiss();
setContentView(gameView);
And my AsyncTask class looks like this:
private class GetNextSquare extends AsyncTask<String[][], Void, SudokuSquare> {
private ProgressDialog dialog = new ProgressDialog(Game.this);
#Override
protected void onPreExecute() {
this.dialog.setMessage("Finding next number");
this.dialog.show();
}
#Override
protected SudokuSquare doInBackground(final String[][]... args) {
try {
SudokuAdvancedSolver solver = new SudokuSolver(args[0]);
return solver.getOneValue();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
protected void onPostExecute(final SudokuSquare result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
At the moment I have two ProgressDialogs, one inside the AsyncTask and one outside. Which one is correct? Also, the spinner is not being displayed at all. What am I overlooking which is causing this to be the case?
only the one outside is correct. because you are trying the main thread (the UI thread of your activity) by another thread (your asychronic task). you should use a handler in place of this :
1/ you show the progress bar
2/ you load the game in a thread
3/ when the game is loaded you send a message to the handler which will stop the progress bar.
See this exemple . you should dismiss your dialog in the handler (when the handler receives the message from the thread) .
If you don't implement a listener on Asynctask, i could suggest you to dismiss your progress dialog onPostExecute
private ProgressDialog dialog;
public void setProgressDialog(ProgressDialog dialog){
this.dialog = dialog;
}
#Override
protected void onPostExecute(final SudokuSquare result) {
dialog.dismiss();
}
and before you executing Asynctask add this code
nextSquareThread.setProgressDialog(pd);
This is for study and I just want to make sure my answers are 100% right. The question gives me skeleton code and I'm required to fill it in. Here is the code.
public class WebFragment extends WebViewFragment {
private WebView mWebView;
#Override
public void onActivityCreated(Bundle.savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Fill in here
}
public void refreshPage(View view) {
// Fill in here
}
}
Now I am asked three questions. I have put my answers below each question.
a. Instantiate the WebView property in the class
b. When the activity has started, make the WebView component load the url "http://www.google.com/"
#Override
public void onActivityCreated(Bundle.savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mWebView = (WebView) findViewById(R.id.webview); // question a
mWebView.getSettings().setJavaScriptEnabled(true); // question a
mWebView.loadUrl("http://www.google.com"); // question b
}
c. Assuming a button is available in the activity layout and runs refreshPage when pressed, make the function reload the WebView page and show a Toast with the message "Page has been refreshed!"
public void refreshPage(View view) {
mWebView.reload();
Toast toast = Toast.makeText(getApplicationContext(), "Page has been refreshed!"), Toast.LENGTH_SHORT().show();
}
Any feedback is appreciated.
answer a seems ok, for the toast you don't need the variable, unless you don't want to do something other than showing the toast
mWebView.reload();
Toast.makeText(getApllicationContext(),"foo",Toast.LENGTH_SHORT).show();
or pass a custom time in milliseconds
Toast.makeText(getApllicationContext(),"foo",2000).show();
you can also initialize a Toast variable and than call show on it, it works, it's just a useless variable if you're not going to do anything with it but it's not wrong
Toast toast = Toast.makeText(getApplicationContext(),"foo",1000);
toast.show();
oh, I don't know if it's required, but like this refreshPage method is not callable by anybody, maybe you want to set an OnClickListener to the button (that we assume is in the layout) so that refreshPage can be called
((Button)findViewById(R.id.buttonId)).setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v){
refreshPage(v);
}
});
I would like to show loadingActivity while "activity1" is executing some code (working), after that, show again activity1. However, if I do not want to start activity1 again, only switch its layouts when doSomeStuff ends. Thank you.
activity1
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent myIntent = new Intent(getApplicationContext(), loadingActivity.class);
startActivityForResult(myIntent, 0);
//Do some stuff while loadingActivity is showed
doSomeStuff()
//here I want to show again this activity and hide loading one
loadingActivity
public class loadingActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
setContentView(R.layout.loading);
}
For this you should use a ProgressDialog, this will allow you to easily show a loading indicator and once the work is done you can easily remove it. The code below should work of you.
Show Dialog:
ProgressDialog dialog = new ProgressDialog(YourActivityClass.this);
dialog.setMessage("Loading Activity...");
dialog.show();
//Do your long running work here
Dismiss dialog:
dialog.dismiss();
You can set the dialog as a class level variable if you want to show and dismiss it in different methods.
Also from looking at your code you might be blocking the activity from ever loading if your long running work is not happening on a background thread. You cannot do long running work inside of onCreate without offloading the work to a background thread. For easy threading in Android you should use the AsyncTask class.