What i am doing : I am trying to play an mp3 file from an url in android. and control its position through progressbar.
what is happening:
FOR the strings.xml below code is working correctly song is playing and i am able to position the progress using the progressbar
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Android mp3 player</string>
<string name="testsong_20_sec">http://users.skynet.be/fa046054/home/P22/track06.mp3</string>
FOR the strings.xml below code the code is not working properly, i mean song is playing but i cannot control the position using the progress bar. only difference with this url is that this mp3 file is in google drive.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Android mp3 player</string>
<string name="testsong_20_sec">https://286898c83aa5e6a4f7b29cdbef3b2f54430b4e71.googledrive.com/host/0B6a-NfRKFX8HQVZRSzFON1ExZEE/Chadh%20Gayi%20Maa%20Tere%20Naam%20Ki%20Sherewali%20Ka%20Sancha.mp3</string>
</resources>
What i am looking for: how to make sure my code plays proper music and i could toggle using progress bar in the second url properly
StreamingMp3Player.java
public class StreamingMp3Player extends Activity implements OnClickListener, OnTouchListener, OnCompletionListener, OnBufferingUpdateListener{
private ImageButton buttonPlayPause;
private SeekBar seekBarProgress;
public EditText editTextSongURL;
private MediaPlayer mediaPlayer;
private int mediaFileLengthInMilliseconds; // this value contains the song duration in milliseconds. Look at getDuration() method in MediaPlayer class
private final Handler handler = new Handler();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();
}
/** This method initialise all the views in project*/
private void initView() {
buttonPlayPause = (ImageButton)findViewById(R.id.ButtonTestPlayPause);
buttonPlayPause.setOnClickListener(this);
seekBarProgress = (SeekBar)findViewById(R.id.SeekBarTestPlay);
seekBarProgress.setMax(99); // It means 100% .0-99
seekBarProgress.setOnTouchListener(this);
editTextSongURL = (EditText)findViewById(R.id.EditTextSongURL);
editTextSongURL.setText(R.string.testsong_20_sec);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
}
/** Method which updates the SeekBar primary progress by current song playing position*/
private void primarySeekBarProgressUpdater() {
seekBarProgress.setProgress((int)(((float)mediaPlayer.getCurrentPosition()/mediaFileLengthInMilliseconds)*100)); // This math construction give a percentage of "was playing"/"song length"
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
primarySeekBarProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.ButtonTestPlayPause){
/** ImageButton onClick event handler. Method which start/pause mediaplayer playing */
try {
mediaPlayer.setDataSource(editTextSongURL.getText().toString()); // setup song from http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3 URL to mediaplayer data source
mediaPlayer.prepare(); // you must call this method after setup the datasource in setDataSource method. After calling prepare() the instance of MediaPlayer starts load data from URL to internal buffer.
} catch (Exception e) {
e.printStackTrace();
}
mediaFileLengthInMilliseconds = mediaPlayer.getDuration(); // gets the song length in milliseconds from URL
if(!mediaPlayer.isPlaying()){
mediaPlayer.start();
buttonPlayPause.setImageResource(R.drawable.button_pause);
}else {
mediaPlayer.pause();
buttonPlayPause.setImageResource(R.drawable.button_play);
}
primarySeekBarProgressUpdater();
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(v.getId() == R.id.SeekBarTestPlay){
/** Seekbar onTouch event handler. Method which seeks MediaPlayer to seekBar primary progress position*/
if(mediaPlayer.isPlaying()){
SeekBar sb = (SeekBar)v;
int playPositionInMillisecconds = (mediaFileLengthInMilliseconds / 100) * sb.getProgress();
mediaPlayer.seekTo(playPositionInMillisecconds);
}
}
return false;
}
#Override
public void onCompletion(MediaPlayer mp) {
/** MediaPlayer onCompletion event handler. Method which calls then song playing is complete*/
buttonPlayPause.setImageResource(R.drawable.button_play);
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
/** Method which updates the SeekBar secondary progress by current song loading from URL position*/
seekBarProgress.setSecondaryProgress(percent);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/widget31"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<EditText
android:id="#+id/EditTextSongURL"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:ems="10"
android:height="100dp"
android:lines="3"
android:maxLines="3"
android:minLines="1" >
<requestFocus />
<requestFocus />
</EditText>
<ImageButton
android:id="#+id/ButtonTestPlayPause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/EditTextSongURL"
android:layout_centerHorizontal="true"
android:contentDescription="TestPlayPause"
android:onClick="onClick"
android:src="#drawable/button_play" />
<SeekBar
android:id="#+id/SeekBarTestPlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/ButtonTestPlayPause" />
</RelativeLayout>
This happens because google drive HTTP server does not return proper length of the file.
$ wget -S https://286898c83aa5e6a4f7b29cdbef3b2f54430b4e71.googledrive.com/host/0B6a-NfRKFX8HQVZRSzFON1ExZEE/Chadh%20Gayi%20Maa%20Tere%20Naam%20Ki%20Sherewali%20Ka%20Sancha.mp3
...
Length: unspecified [audio/mpeg]
You have no total stream length, and therefore you don't have position relative to total length. Bad luck.
Related
I'm using Android Studio and trying to show some chosen Street View paths in VR. I already have Street View running well and now I'm trying to show it in VR.
I have put the com.google.vr.sdk.widgets.pano.VrPanoramaView in the layout and, inside onCreate in my class, referenced it to a VrPanoramaView variable through findViewById. Now I'm trying to show an image calling a method which I've defined in this class, loadPanoImage. This method loads an image from the storage and shows it through loadImageFromBitmap.
The problem is that it isn't able to show anything, even though I've followed a guide and I've done everything as showed. I've even tryed calling it in different parts of the code (before doing any other action, on clicking a button, before and after showing streetview) but I can't understand why it isn't working and how will I be able to use it to show images taken from StreetView (I don't know if I will be able to do it dinamically or I should download them and put them in the storage).
I'm putting part of the code for reference:
public class VrExperience extends FragmentActivity {
Button buttonCitta;
Button buttonMare;
Button buttonMontagna;
TextView titleTextView;
// George St, Sydney
private static final LatLng SYDNEY = new LatLng(-33.87365, 151.20689);
// LatLng with no panorama
private static final LatLng INVALID = new LatLng(-45.125783, 151.276417);
//VrPanoramaView is inserted in the layout
private VrPanoramaView panoWidgetView;
//StreetViewPanorama is another class in my project which shows Street View
private StreetViewPanorama mStreetViewPanorama;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vrexperiences);
panoWidgetView = (VrPanoramaView) findViewById(R.id.pano_view);
panoWidgetView.setEventListener(new VrPanoramaEventListener());
//download image and show it, but it doesn't show anything
loadPanoImage();
titleTextView = (TextView) findViewById(R.id.titleTextView);
buttonCitta = (Button) findViewById(R.id.buttonCitta);
buttonCitta.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!checkReady()) {
return;
}
titleTextView.setVisibility(View.GONE);
buttonCitta.setVisibility(View.GONE);
buttonMare.setVisibility(View.GONE);
buttonMontagna.setVisibility(View.GONE);
loadPanoImage(); //it doesn't show anything
mStreetViewPanorama.setPosition(SYDNEY);
loadPanoImage(); //it doesn't show anything
}
}};
//code for buttonMontagna and buttonMare as well, it's identical
SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
(SupportStreetViewPanoramaFragment)
getSupportFragmentManager().findFragmentById(R.id.streetviewpanorama);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(
new OnStreetViewPanoramaReadyCallback() {
#Override
public void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
mStreetViewPanorama = panorama;
// Only set the panorama to INVALID on startup (when no panoramas have been
// loaded which is when the savedInstanceState is null).
if (savedInstanceState == null) {
mStreetViewPanorama.setPosition(INVALID);
}
}
});
}
/**
* When the panorama is not ready the PanoramaView cannot be used. This should be called on
* all entry points that call methods on the Panorama API.
*/
private boolean checkReady() {
if (mStreetViewPanorama == null)
return false;
return true;
}
/**
* Called when the Animate To Invalid button is clicked.
*/
public void onGoToInvalid(View view) {
if (!checkReady()) {
return;
}
mStreetViewPanorama.setPosition(INVALID);
}
//retrieves image from the assets folder and loads it into the VrPanoramaView
private void loadPanoImage() {
VrPanoramaView.Options options = new VrPanoramaView.Options();
InputStream inputStream = null;
AssetManager assetManager = getAssets();
try {
inputStream = assetManager.open("demo2.jpg");
options.inputType = VrPanoramaView.Options.TYPE_MONO;
panoWidgetView.loadImageFromBitmap(
BitmapFactory.decodeStream(inputStream), options
);
inputStream.close();
} catch (IOException e) {
Log.e("Fail", "Exception in loadPanoImage" + e.getMessage());
}
}
#Override
protected void onPause() {
panoWidgetView.pauseRendering();
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
panoWidgetView.resumeRendering();
}
#Override
protected void onDestroy() {
panoWidgetView.shutdown();
super.onDestroy();
}
}
This is my layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/vrExperienceActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.vr.sdk.widgets.pano.VrPanoramaView
android:id="#+id/pano_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_weight="5"
android:scrollbars="none" />
<TextView
android:id="#+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:text="VR Experience"
android:textAlignment="center"
android:textAppearance="#android:style/TextAppearance.Large"
android:textColor="#0000F0"
android:visibility="visible" />
<Button
android:id="#+id/buttonCitta"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Città " />
<fragment
class="com.google.android.gms.maps.SupportStreetViewPanoramaFragment"
android:id="#+id/streetviewpanorama"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
EDIT: #LucioB
a) those are the places I've tried to call loadPanoImage, but neither of them showed anything. It acts as nothing happens calling that method, the program keeps going to the other tasks. I'd like for images to be shown directly in VR when a button is clicked, or if that isn't possible to add the classic cardboard button in Street View mode to pass to VR view.
b) I mean the code isn't doing what I expected it to do. I thought that once I created VrPanoramaView in the layout and used it to show an image through .loadImageFromBitmap it would have shown the image I loaded from asset (I have an image saved on the virtual SD), and that once I was able to do that for a single image I would have found a way to do it for a whole path.
The code doesn't give any exception, I think I'm making a logic mistake or I didn't understand how VR api work.
EDIT: I've found that the java code is working, the problem was in the layout which didn't permit to see VrPanoramaView because it was obscured by StreetViewPanorama
I'm new to android programming. I was trying to make a splashscreen and i have two different images...one for the background and other is for the logo.....both the images are in separate imageviews. The size of the images would be around 23kb and 3kb respectively. However when i run the app. It shows an error that processor maybe doing additional work. Skipping 88 frames. This completely skips the splashscreen and directly goes to main activity. Please can anyone help me with the solution.
set background image in parent and give logo image as a child...
like this :-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/backgroundImage"
tools:context="xyz.xyz.com.xyz.activity.SplashActivity">
<ImageView
android:id="#+id/logoImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:src="#drawable/logoImage" />
</RelativeLayout>
In java code use this :-
public class SplashActivity extends AppCompatActivity {
private long ms = 0;
private long splashTime = 2000;
private boolean splashActive = true;
private boolean paused = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Thread mythread = new Thread() {
public void run() {
try {
while (splashActive && ms < splashTime) {
if (!paused)
ms = ms + 100;
sleep(100);
}
} catch (Exception e) {
}
finally
{
System.out.println("reached");
Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
System.out.println("reached1");
startActivity(intent);
System.out.println("reached2");
finish();
System.out.println("reached3");
}
}
};
mythread.start();
}
Imagine a number 10, then after user clicks a button it changes to 100. But how to make an efficient transition
10 -> 100,
that will display values like
12, 15, 18, ..., 97, 100 over 1 second.
I've seen something like that in "Cookie clicker" but couldn't find anything about that kind of transition in the source code.
I had an idea of a loop (for number1 < number2, do number1++), it will work fine for small numbers, but if 10 changes to 1 billion, then the loop will probably freeze the whole app.
Second idea is to get added value (100-10=90) and divide by 30 or 60 frames, and add this value with each frame. But what will happen if frame is dropped? - Probably value will not be added. What if user makes double click or the system adds values automatically?
Hope it gives an idea of what kind of number transition I need.
Maybe I overlooked and there is a simple approach? Any help is appreciated.
Hope this little demo using a ValueAnimator will inspire you to find an appropriate solution.
You can specify the duration of the animation (see code) and even adjust the frame-rate by saying mAnimator.setFrameDelay(frameDelay);.
By using animator.isRunning() or animator.isStarted() you can prevent double-click malfunction or other unwanted behaviour while the current animation is runnning.
The Main Activity:
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
tv.setText(String.format("%04d", value));
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animator) {
super.onAnimationEnd(animator);
final int endValue = Integer.parseInt((String) tv.getText());
mAnimator.setIntValues(endValue, endValue + 100);
}
});
}
/** Button callback */
public void onClick(final View view) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
mAnimator.start();
}
}
}
Simple demo layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100"
android:onClick="onClick">
</Button>
Here's another demo (hope this answers your 2. question), which implements different behaviour dependent on single click or double-click on the button. Just experiment with it, you now have the basic building blocks to construct own behavour ...
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
TextView mTv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
mTv.setText(String.format("%04d", value));
}
});
final Button button = (Button) findViewById(R.id.button);
final GestureDetector gestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
performAnimation(100);
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
performAnimation(0);
return true;
}
});
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
}
/** starts animation */
private void performAnimation(final int offset) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
final int endValue = Integer.parseInt((String) mTv.getText());
mAnimator.setIntValues(endValue + offset, endValue + 100 + offset);
mAnimator.start();
}
}
}
Don't forget to replace your layout file, since the click-attribute of the button has been removed:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100" >
</Button>
</LinearLayout>
I guess you can do it by using different threads. Only main thread works with UI so you can divide the interval into small intervals and make a transitions in different threads.After send them to main thread and print. Hope it will help.
I create simple Android app (https://www.linux.com/learn/docs/683628-android-programming-for-beginners-part-1) with latest Android Studio. Code:
public class test_act extends Activity {
private static final int MILLIS_PER_SECOND = 1000;
private static final int SECONDS_TO_COUNTDOWN = 30;
private android.widget.TextView countdownDisplay;
private android.os.CountDownTimer timer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.full_act);
countdownDisplay = (android.widget.TextView) findViewById(R.id.time_display_box);
android.widget.Button startButton = (android.widget.Button) findViewById(R.id.startbutton);
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
try {
showTimer(SECONDS_TO_COUNTDOWN * MILLIS_PER_SECOND);
} catch (NumberFormatException e) {
// method ignores invalid (non-integer) input and waits
// for something it can use
}
}
});
}
private void showTimer(int countdownMillis) {
if(timer != null) { timer.cancel(); }
timer = new android.os.CountDownTimer(countdownMillis, MILLIS_PER_SECOND) {
#Override
public void onTick(long millisUntilFinished) {
countdownDisplay.setText("counting down: " +
millisUntilFinished / MILLIS_PER_SECOND);
}
#Override
public void onFinish() {
countdownDisplay.setText("KABOOM!");
}
}.start();
}
}
My XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/time_display_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:text="#string/_00_30"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<Button
android:id="#+id/startbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/time_display_box"
android:layout_centerHorizontal="true"
android:layout_marginTop="41dp"
android:text="#string/start" />
</RelativeLayout>
In emulator it's good working. But on my Galaxy S2 with CyanogenMod10.1(Android 4.2.2) app wrong updating TextView. Screenshot:
How I can resolve this problem?
upd: after screen rotate TextView is updating once.
You might want to try invalidating your layout every time it is updated. I am guessing with how often the text is being updated the phone is not having enough time to redraw the layout. This would also explain why it works when you rotate your phone, because then the layout is forced to update.
countdownDisplay.invalidate();
Let me know if that does not work.
It commonly happens when you put UI updates inside try blocks, try to avoid it or wrap with runOnUiThread.
EDIT:
Another reason - you update it to fast - you code does 1000 updates per second i dont think it can handle it.
I uploaded my app yesterday to Google Play and this morning I've wanted to make just a layout tweak as some of the text was overlapping buttons on smaller screens, basically I just want to move the buttons further down the screen. I thought this would be as easy as using eclipse's graphical editor... Nope.
I have no idea why but the small edit I've done to the position of the buttons on my "view_fact" layout has registered the buttons with the wrong OnClick listeners, there's only two buttons on the view and they're using eachothers event listeners and I have no idea why. I didn't touch the event listener code that was working perfectly on the old layout.
Here is my view_fact layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/viewFactTitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="18dp"
android:text="#string/factTitleText"
android:textSize="22dp"
tools:context=".MainActivity" />
<ImageView
android:id="#+id/randomFactImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/viewFactTitleText"
android:layout_centerHorizontal="true"
android:layout_marginTop="18dp"
android:contentDescription="Fact Image"
android:src="#drawable/canadaflag" />
<TextView
android:id="#+id/factData"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_below="#+id/randomFactImage"
android:layout_centerHorizontal="true"
android:layout_marginTop="14dp"
android:text="TextView" />
<Button
android:id="#+id/anotherFactButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/backToHomeButton"
android:layout_alignLeft="#+id/backToHomeButton"
android:layout_alignRight="#+id/backToHomeButton"
android:text="#string/anotherFactButtonText" />
<Button
android:id="#+id/backToHomeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/factData"
android:layout_alignParentBottom="true"
android:layout_alignRight="#+id/factData"
android:text="#string/backToHomeButtonText" />
</RelativeLayout>
Listener and startup code:
public class MainActivity extends Activity {
/* Declaration of global variables */
private boolean debugMode = true; // Whether debugging is enabled or not
private static String logtag = "CanadianFacts"; // For use as the tag when logging
private TextView factData;
private int totalFacts = 72;
private String[][] facts = new String[totalFacts][5];
private int lastFact = 0;
/* Buttons */
/* Home page */
private Button randomFactButton;
/* View Fact page */
private Button anotherRandomFactButton;
private Button backToHomeButton;
/* About page */
private Button backToHomeFromAboutButton;
/* Image Views */
private ImageView randomFactImage;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/* Home Page Objects */
randomFactButton = (Button)findViewById(R.id.randomFactButton);
randomFactButton.setOnClickListener(randomFactListener); // Register the onClick listener with the implementation above
/* View Fact Page Objects */
/* Build Up Fact Array */
buildFactArray();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_about:
loadAboutPage(); // Call the loadAboutPage method
return true;
}
return false;
}
public void loadAboutPage() {
setContentView(R.layout.about);
/* Set up home page button listener */
backToHomeFromAboutButton = (Button)findViewById(R.id.backToHomeFromAboutButton);
backToHomeFromAboutButton.setOnClickListener(backToHomeListener); // We can reuse the backToHomeListener
}
/* Home Page Listeners */
//Create an anonymous implementation of OnClickListener, this needs to be done for each button, a new listener is created with an onClick method
private OnClickListener randomFactListener = new OnClickListener() {
public void onClick(View v) {
if (debugMode) {
Log.d(logtag,"onClick() called - randomFact button");
Toast.makeText(MainActivity.this, "The random fact button was clicked.", Toast.LENGTH_LONG).show();
}
setContentView(R.layout.view_fact); // Load the view fact page
/* We're now on the View Fact page, so elements on the page are now in our scope, instantiate them */
/* Another Random Fact Button */
anotherRandomFactButton = (Button)findViewById(R.id.anotherFactButton);
anotherRandomFactButton.setOnClickListener(anotherRandomFactListener); // Register the onClick listener with the implementation above
/* Back to Home Button */
backToHomeButton = (Button)findViewById(R.id.backToHomeButton);
backToHomeButton.setOnClickListener(backToHomeListener); // Register the onClick listener with the implementation above
// Get a random fact
String[] fact = getRandomFact();
if (fact[2] == null) { // If this fact doesn't have an image associated with it
fact[2] = getRandomImage();
}
int imageID = getDrawable(MainActivity.this, fact[2]);
/* See if this fact has an image available, if it doesn't select a random generic image */
randomFactImage = (ImageView) findViewById(R.id.randomFactImage);
randomFactImage.setImageResource(imageID);
factData = (TextView) findViewById(R.id.factData);
factData.setText(fact[1]);
if (debugMode) {
Log.d(logtag,"onClick() ended - randomFact button");
}
}
};
/* View Fact Page Listeners */
private OnClickListener anotherRandomFactListener = new OnClickListener() {
public void onClick(View v) {
if (debugMode) {
Log.d(logtag,"onClick() called - anotherRandomFact button");
Toast.makeText(MainActivity.this, "The another random fact button was clicked.", Toast.LENGTH_LONG).show();
}
// Get a random fact
String[] fact = getRandomFact();
if (fact[2] == null) { // If this fact doesn't have an image associated with it
fact[2] = getRandomImage();
}
int imageID = getDrawable(MainActivity.this, fact[2]); // Get the ID of the image
/* See if this fact has an image available, if it doesn't select a random generic image */
randomFactImage = (ImageView) findViewById(R.id.randomFactImage);
randomFactImage.setImageResource(imageID);
factData = (TextView) findViewById(R.id.factData);
factData.setText(fact[1]);
if (debugMode) {
Log.d(logtag,"onClick() ended - anotherRandomFact button");
}
}
};
private OnClickListener backToHomeListener = new OnClickListener() {
public void onClick(View v) {
if (debugMode) {
Log.d(logtag,"onClick() called - backToHome button");
Toast.makeText(MainActivity.this, "The back to home button was clicked.", Toast.LENGTH_LONG).show();
}
// Set content view back to the home page
setContentView(R.layout.main); // Load the home page
/* Reinstantiate home page buttons and listeners */
randomFactButton = (Button)findViewById(R.id.randomFactButton);
randomFactButton.setOnClickListener(randomFactListener); // Register the onClick listener with the implementation above
if (debugMode) {
Log.d(logtag,"onClick() ended - backToHome button");
}
}
};
Thank you.
I've managed to fix this, by moving the buttons around, changing the IDs a few times and then changing them back. And removing all of the align settings and resetting it's position.
A very strange problem, probably due to eclipse's graphical editor.