How to open dialog box in android as soon as game ends from surfaceview class - multithreading

I have made a SurfaceView subclass in MainActivity which runs some animation/game/thread via canvas draw and I want a dialog box to appear as soon as game ends. I have made a function called openNewGameDialog where I call new AlertDialog.Builder(MainActivity.this) however since I am calling this from a thread it gives error. Please help!! Following is the code:
public class MainActivity extends Activity implements OnTouchListener{
GameSurface dSurface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dSurface=new GameSurface(this);
dSurface.setOnTouchListener(this);
initialize();
setContentView(dSurface);
}
private void initialize(){
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
dSurface.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
dSurface.resume();
}
private void openNewGameDialog(){
new AlertDialog.Builder(MainActivity.this)
.setTitle("hhhhhh")
.setItems(R.array.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
})
.show();
}
public class GameSurface extends SurfaceView implements Runnable{
SurfaceHolder gameHolder;
Thread gameThread = null;
public GameSurface(Context context) {
super(context);
// TODO Auto-generated constructor stub
gameHolder = getHolder();
}
public void pause(){
isRunning = false;
while(true)
{
try {
gameThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
gameThread=null;
}
public void resume(){
isRunning = true;
gameThread = new Thread(this);
gameThread.start();
}
#Override
public void run() {
// TODO Auto-generated method stub
while(isRunning){
if(!gameHolder.getSurface().isValid())
continue;
Canvas canvas = gameHolder.lockCanvas();
canvas.draw something
if game==ends
openNewGameDialog();
gameHolder.unlockCanvasAndPost(canvas);
}
}
}
}

You must put the contents of openNewGameDialog() in a Runnable instead of a method and then call the runOnUiThread(Runnable r) method of the Activity class using that Runnable.
Any kind of UI manipulation can only be done by the UI thread. TherunOnUiThread(Runnable r) method queues the Runnable to the UI thread event queue.

Related

Android studio pause and resume countdown timer for progress bar

I am using a countdown timer which updates my progress bar which decreases from 100 (full) to 0(empty) but when the app is paused would like to pause the timer and then restart it upon resuming the app. I implement the count down timer like so:
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
int progress = (int) (millisUntilFinished / 100);
progressBar.setProgress(progress);
}
#Override
public void onFinish() {
progressBar.setProgress(0);
Intent intent = new Intent(getApplicationContext(), GameOver.class);
startActivity(intent);
finish();
}
}
And in my on create:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_screen);
progressBar = (ProgressBar)findViewById(R.id.timerBar);
progressBar.setProgress(100);
myCountDownTimer = new MyCountDownTimer(10000, 10);
myCountDownTimer.start();
}
You can add a boolean in your MyCountDownTimer class that will change in the onPause and onResume methods of your Activity. Check the // ADDED comments to see the changes you have to make to make this work.
public class MyActivity extends Activity {
MyCountDownTimer myCountDownTimer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_screen);
progressBar = (ProgressBar)findViewById(R.id.timerBar);
progressBar.setProgress(100);
myCountDownTimer = new MyCountDownTimer(10000, 10);
myCountDownTimer.start();
}
// ADDED
#Override
public void onPause() {
super.onPause(); // Always call the superclass method first
myCountDownTimer.pause();
}
// ADDED
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
myCountDownTimer.resume();
}
}
public class MyCountDownTimer extends CountDownTimer {
// ADDED
private boolean pause;
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
// ADDED
public void pause() {
pause = true;
}
// ADDED
public void resume() {
pause = false;
}
#Override
public void onTick(long millisUntilFinished) {
int progress = (int) (millisUntilFinished / 100);
// ADDED
if (!pause) {
progressBar.setProgress(progress);
}
}
#Override
public void onFinish() {
// ADDED
isRunning = false;
progressBar.setProgress(0);
Intent intent = new Intent(getApplicationContext(), GameOver.class);
startActivity(intent);
finish();
}
}

java.lang.IllegalStateException: Not on FX application thread Calling Function

Something strange is happening.. Untill 10 minutes ago I had no problem with this code. But now I have a problem updating JUST my VBOX from an external thread.
These are my three classes:
Controller Class:
public class Controller implements Initializable{
#FXML
private VBox slaveVbox;
private ButtonBar newNode = new ButtonBar();
private Circle c= new Circle();
private Button b= new Button();
private Label lname = new Label();
private Label lIMEI = new Label();
private Label lroot = new Label();
#Override
public void initialize(URL location, ResourceBundle resources) {
}
public void create(String imei, String permission,boolean isOnline) throws IOException{
if(!alreadyExist(imei)){
newNode = new ButtonBar();
b = setButtonSpec(imei + "btnHavefun");
c = setCircleSpec(imei + "statuOnline", isOnline);
lname= setLNameSpec(imei + "name");
lIMEI = setLIMEISpec(imei + "Imei");
lroot = setLrootSpec(imei + "root", permission);
newNode.getButtons().addAll(lname,lIMEI,lroot,b,c);
slaveVbox.getChildren().addAll(newNode);
}
}
}
Main Class:
public class MainApp extends Application {
FXMLLoader loader2;
private Stage primaryStage;
private BorderPane rootLayout;
#Override
public void start(Stage primaryStage) throws IOException {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Thypheon Application");
initRootLayout();
Controller controller2 = initDesign();
Connection con = new Connection(controller2);
Thread t = new Thread(con);
t.start();
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent e) {
Platform.exit();
System.exit(0);
}
});
}
public static void main(String[] args) {
launch(args);
}
public void initRootLayout(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Controller initDesign(){
try {
FXMLLoader loader2= new FXMLLoader(getClass().getResource("Design.fxml"));
AnchorPane anchor = (AnchorPane) loader2.load();
rootLayout.setCenter(anchor);
Controller controller = loader2.getController();
return controller;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public Stage getPrimaryStage(){
return primaryStage;
}
}
Connection THREAD:
public class Connection implements Runnable {
String result;
Controller controller;
public Connection(Controller controller) {
this.controller = controller;
}
#Override
public void run() {
try {
controller.create("jhgjhgjh", "dssf", true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Debugging the Application Everything works perfectly untill I reach slaveVbox.getChildren().addAll(newNode); Here comes the exception..
After some attempt to solve the problem I figured out that if I create a ButtonBar and I insert it in the slaveVbox from Main (inside start()) it works fine.. So I ve tied to add controller2.create("FIRST", "FIRST", true); in my start() function like this:
#Override
public void start(Stage primaryStage) throws IOException {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Thypheon Application");
initRootLayout();
Controller controller2 = initDesign();
controller2.create("FIRST", "FIRST", true);
Connection con = new Connection(controller2);
Thread t = new Thread(con);
t.start();
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent e) {
Platform.exit();
System.exit(0);
}
});
}
But obviously my application shows two ButtonBars... One created in the start() function and one created inside the Connection Thread.. How Can I avoid this?? Why I can't directly add item inside my VBox directly from my Connecton thread??
You cannot update the UI from a thread other than the FX Application Thread. See, for example, the "Threading" section in the Application documentation.
It's not at all clear why you are using a background thread at all here: there doesn't seem to be any long-running code in the method you are calling. In general, if you have long-running code to call, you can call it in a background thread and then update the UI by wrapping UI update in a Platform.runLater(...).
public class Connection implements Runnable {
String result;
Controller controller;
public Connection(Controller controller) {
this.controller = controller;
}
#Override
public void run() {
try {
// execute long-running code here...
// perform any updates to the UI on the FX Application Thread:
Platform.runLater(() -> {
// code that updates UI
});
// more long-running code can go here...
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

How autocall method in JavaFX?

I have scene with label which shows what part of hardware are being checked at the moment, so i need invoke "checkMethod" automatically after scene has been drawn, how can i do it in JavaFX?
Here is how to do something when the Scene is shown:
stage.setOnShown(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent arg0) {
// TODO Auto-generated method stub
checkMethod();
}
});
You also have this other methods: setOnCloseRequest, setOnHidden, setOnHiding, setOnShowing.
The option proposed in comments Its the followin:
scene.windowProperty().addListener(new ChangeListener<Window>() {
#Override
public void changed(ObservableValue<? extends Window> arg0,
Window oldVal, Window newVal) {
if(oldVal != null){
oldVal.setOnShown(null);
}
if(newVal != null){
newVal.setOnShown(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent arg0) {
// TODO Auto-generated method stub
checkMethod();
}
});
}
}
});

mapview and cameraupdate in api v2

Why the CameraUpdateFactory class is not working in my project?
The app crashes if it executes the following command:
CameraUpdate pino= CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude()));
If i remove that line (and of course the next one), the code successfully starts and shows the map.
I need the mapView and i need to use the new api v2.
I declare the mapView in layout in this way:
<com.google.android.gms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/mappa"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="#+id/buttonBar"
map:uiZoomControls="false"
/>
then in mainActivity.java i wrote this:
public class MainActivity extends FragmentActivity implements LocationListener, LocationSource {
public static boolean locatingMe=true;
public GoogleMap mappa;
public MapView mapView;
private OnLocationChangedListener onLocationChangedListener;
private LocationManager locationManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mappa);
mapView.onCreate(savedInstanceState);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
//You may want to pass a different provider in as the first arg here
//depending on the location accuracy that you desire
//see LocationManager.getBestProvider()
Criteria locationCriteria = new Criteria();
locationCriteria.setAccuracy(Criteria.NO_REQUIREMENT);
locationManager.requestLocationUpdates(locationManager.getBestProvider(locationCriteria, true), 1L, 2F, this);
if (mappa == null) {
mappa=mapView.getMap();
//This is how you register the LocationSource
mappa.setLocationSource(this);
mappa.getUiSettings().setMyLocationButtonEnabled(false);
mappa.setMyLocationEnabled(true);
}
}
#Override
public void onPause()
{
if(locationManager != null)
{
locationManager.removeUpdates(this);
}
mapView.onPause();
super.onPause();
}
#Override
public void onResume()
{
checkGooglePlayServicesAvailability();
checkGps();
mapView.onResume();
super.onResume();
}
#Override
protected void onDestroy() {
mapView.onDestroy();
super.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
#Override
public void activate(OnLocationChangedListener listener)
{
onLocationChangedListener = listener;
}
#Override
public void deactivate()
{
onLocationChangedListener = null;
}
#Override
public void onLocationChanged(Location location)
{
if( onLocationChangedListener != null )
{
onLocationChangedListener.onLocationChanged( location );
//Move the camera to the user's location once it's available!
//only if locatingMe is true
if (locatingMe) {
if (mappa!=null){
CameraUpdate pino= CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude()));
mappa.animateCamera(pino);
}
}
}
}
#Override
public void onProviderDisabled(String provider)
{
// TODO Auto-generated method stub
Toast.makeText(this, "provider disabled", Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderEnabled(String provider)
{
// TODO Auto-generated method stub
Toast.makeText(this, "provider enabled", Toast.LENGTH_SHORT).show();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
// TODO Auto-generated method stub
Toast.makeText(this, "status changed", Toast.LENGTH_SHORT).show();
}
The error in the LogCat is the following:
Caused by: java.lang.NullPointerException: CameraUpdateFactory is not initialized.
I solved the problem by adding on the "onCreate" the following lines:
try {
MapsInitializer.initialize(this);
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
the reason is that the CameraUpdateFactory needs to be initilized (even if from documentation it seems that using mapview it shoud be automatically initialized)
I even replaced "public class MainActivity extends FragmentActivity" with "public class MainActivity extends Activity". But i think that this last thing it was not needed..
if i use:
try {
MapsInitializer.initialize(this);
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
The exception give me this error:
Unreachable catch block for GooglePlayServicesNotAvailableException.
This exception is never thrown from the try statement body".
I have use only:
MapsInitializer.initialize(this);
:)

Android MediaPlayer seek bar current position thread issues

Hi I am new to android and I am learning by example. I am trying to make an activity that has a list view of all songs in my raw folder with media player controls at the bottom. I have everything working so far but I can't seem to get the SeekBar to stop force closing.
Here is the code:
public class music extends ListActivity implements Runnable {
private ArrayList<sound> mSounds = null;
private soundadapter mAdapter = null;
private ImageButton playbtn;
private SeekBar seekbar;
private int total;
private MediaPlayer mp = null;
private TextView selelctedFile = null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.music);
selelctedFile = (TextView) findViewById(R.id.selectedfile);
seekbar = (SeekBar) findViewById(R.id.seekbar);
seekbar.setProgress(0);
// create a simple list
mSounds = new ArrayList<sound>();
sound s = new sound();
s.setDescription("Rudolph The Red Nosed Reindeer");
s.setSoundResourceId(R.raw.rudolphtherednosereindeer);
mSounds.add(s);
s = new sound();
s.setDescription("Battery");
s.setSoundResourceId(R.raw.battery);
mSounds.add(s);
mAdapter = new soundadapter(this, R.layout.listitem, mSounds);
setListAdapter(mAdapter);
playbtn = (ImageButton) findViewById(R.id.play);
playbtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
try {
if (mp.isPlaying()) {
mp.pause();
playbtn.setImageResource(android.R.drawable.ic_media_play);
} else {
mp.start();
playbtn.setImageResource(android.R.drawable.ic_media_pause);
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
});
}
#Override
public void onListItemClick(ListView parent, View v, int position, long id) {
sound s = (sound) mSounds.get(position);
if (mp != null) {
mp.reset();
mp.release();
}
mp = MediaPlayer.create(this, s.getSoundResourceId());
selelctedFile.setText(s.getDescription());
playbtn.setImageResource(android.R.drawable.ic_media_pause);
mp.start();
total = mp.getDuration();
seekbar.setMax(total);
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekbar) {
// TODO Auto-generated method stub
}
#Override
public void onStartTrackingTouch(SeekBar seekbar) {
// TODO Auto-generated method stub
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
if (fromUser) {
mp.seekTo(progress);
seekBar.setProgress(progress);
}
}
});
Thread currentThread = new Thread(this);
currentThread.start();
}
#Override
public void run() {
// TODO Auto-generated method stub
try {
while (mp != null) {
int currentPosition = mp.getCurrentPosition();
Message msg = new Message();
msg.what = currentPosition;
threadHandler.sendMessage(msg);
Thread.sleep(100);
}
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
}
private Handler threadHandler = new Handler() {
public void handleMessage(Message msg) {
// super.handleMessage(msg);
// txt.setText(Integer.toString(msg.what));
seekbar.setProgress(msg.what);
}
};
#Override
protected void onPause() {
// TODO Auto-generated method stub
mp.stop();
mp.release();
mp = null;
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
if(mp != null) {
mp.stop();
mp.release();
mp = null;
}
}
}
and here is the error i keep getting when i click several times on different songs:
04-14 02:53:00.452: W/dalvikvm(27452): threadid=19: thread exiting with uncaught exception (group=0x40018560)
04-14 02:53:00.466: E/AndroidRuntime(27452): FATAL EXCEPTION: Thread-22
04-14 02:53:00.466: E/AndroidRuntime(27452): java.lang.IllegalStateException
04-14 02:53:00.466: E/AndroidRuntime(27452): at android.media.MediaPlayer.getCurrentPosition(Native Method)
04-14 02:53:00.466: E/AndroidRuntime(27452): at net.cybercore.collapsingfromwithin.music.run(music.java:145)
04-14 02:53:00.466: E/AndroidRuntime(27452): at java.lang.Thread.run(Thread.java:1019)
Line error 145 is :
int currentPosition = mp.getCurrentPosition();
I cannot for the life of me figure out why it works for 3 or 4 times playing and then it kills the app.
Any help is appreciated. I have already looked at several other sites for examples including http://www.androidhive.info/2012/03/android-building-audio-player-tutorial/ and http://www.androiddevblog.net/android/playing-audio-in-android
**
UPDATE
**
I think I fixed it. thanks for your help I found Thread using for seekbar on android mediaplayer so i changed it to
#Override
public void run() {
// TODO Auto-generated method stub
try {
while (mp != null) {
int currentPosition = mp.getCurrentPosition();
Message msg = new Message();
msg.what = currentPosition;
threadHandler.sendMessage(msg);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("interrupt exeption" + e);
}
}
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("My exeption" + e);
}
}
I still get the errors but they are not killing my app. I don't think this is right way to do it but its working.
You should prepare your media player when instanciating it.
A MediaPlayer object must first enter the Prepared state before playback can be started.
There are two ways (synchronous vs. asynchronous) that the Prepared state can be reached: either a call to prepare() (synchronous) which transfers the object to the Prepared state once the method call returns, or a call to prepareAsync() (asynchronous) which first transfers the object to the Preparing state after the call returns (which occurs almost right way) while the internal player engine continues working on the rest of preparation work until the preparation work completes. When the preparation completes or when prepare() call returns, the internal player engine then calls a user supplied callback method, onPrepared() of the OnPreparedListener interface, if an OnPreparedListener is registered beforehand via setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener).
Read it here
so you should call mp.prepare() after instanciating the player.
also you should make sure the media player in playing to run the run method. I'd start by adding
mp.isPlaying() to the while line.
while (mp != null && mp.isPlaying()) {
...
}
IllegalStateException means that you are on an illegal state to call that method, like for instance, if the player is stopped.
I'm not sure, but I think this will stop the run method when you pause the music. So you should try to avoid this. I create a boolean to identify that the player is playing or paused and use it on the while.

Resources