Android programming many toggle button using in for loop - android

My problem is when I click a toggle button, mp3player is playing and when I click off it is stopping. So when I try to run first time it works. But when I click second time it gives IllegalStateException and "E/MediaPlayer(1009): attachNewPlayer called in state 32" error. How can I fix this problem? Thanks .
My code is here:
public class MyButtons extends Activity {
private static final int[] idBtns = { R.id.btn1, R.id.btn2, R.id.btn3,
R.id.btn4, R.id.btn5, R.id.btn6, R.id.btn7, R.id.btn8, R.id.btn9 };
String[] mpUrls = new String[idBtns.length];
ToggleButton[] mbuttons = new ToggleButton[idBtns.length];
MediaPlayer mp3player = new MediaPlayer();
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.mybuttons);
mp3player.setAudioStreamType(AudioManager.STREAM_MUSIC);
for (int i = 0; i < idBtns.length; i++) {
final int k = i;
mbuttons[k] = (ToggleButton) findViewById(idBtns[k]);
mpUrls[k] = "http://www.testsite.com/def-music-"+ (k + 1) + ".mp3";
}
for (int i = 0; i < idBtns.length; i++) {
final int k = i;
mbuttons[k].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
boolean on = ((ToggleButton) view).isChecked();
if (on) {
try {
mp3player.setDataSource(mpUrls[k]);
mp3player.prepare();
mp3player.start();
mp3player.setLooping(true);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.toString(),Toast.LENGTH_LONG).show();
}
} else {
if (mp3player.isPlaying()) {
mp3player.pause();
mp3player.seekTo(0);
}
}// if(on)-else statement's end
}// onClick's end
});
}// for loop's end
}
}
enter image description here

setDataSource have to be called in Idle state. If you click toggle button second time, it's state must not be idle. So you should manage the state in you app using media player listenr and you should make it work accordingly. Anternatively, you can reset mediaplyer every time you start to play. But it propably provides bad user environment.
You can refer document about Valid and invalid states.
https://developer.android.com/reference/android/media/MediaPlayer.html

Related

Android UI omits some updates

I am dealing with the android UI and I am facing what looks a very common problem here. By using an AsyncTask, I want to:
1- Show a ProgressDialog meanwhile some stuff gets ready
2- Show a countdown to let the user get ready for the real action
3- Play a sound afterwards the countdown to notify the sample will be taken
4- Show another ProgressDialog representing the 10s sample taking
5- Play a sound afterwards the sample is taken
Well, this is my outcome:
1- Works fine
2- MISSING, THE UI IS NOT UPDATED BUT THE BACKGROUND PROCESS IS RUNNING
3- Works fine
4- Works fine
5- Works fine
The funniest is, when I remove the code to handle the first part that handles the first progress dialog, the other parts are executed/displayed as expected. I understand there is something blocking the UI at some point but I am quite newbie with android to realize what's blocking it.
Thanks in advance for your help.
public class SnapshotActivity extends AppCompatActivity {
private int COUNTDOWN_TIME = 5;
private Button startStop;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_snapshot);
startStop = (Button) findViewById(R.id.btnStartStop);
startStop.setText("START");
}
public void startSnapshot(View view) {
startStop.setClickable(false);
new Async(SnapshotActivity.this).execute();
}
class Async extends AsyncTask<Void, Void, Void>{
TextView tv = (TextView) findViewById(R.id.tvCountDown);
ProgressDialog progressDialog ;
ProgressDialog preparing;
Context context;
int flag = 0;
int counter = COUNTDOWN_TIME;
public Async(Context context) {
this.context = context;
progressDialog = new ProgressDialog(context);
preparing = new ProgressDialog(context);
}
#Override
protected void onPreExecute(){
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
//PROGRESS DIALOG
flag = 4;
publishProgress();
try {
//SIMULATE SOME WORKLOAD
Thread.sleep(2000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
flag = 5;
publishProgress();
//HANDLE THE COUNTDOWN
for(counter = COUNTDOWN_TIME; counter>=1; counter--){
publishProgress();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
//PLAY THE SOUND
new Thread(new Runnable() {
#Override
public void run() {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
}
}).start();
//PROGRESS DIALOG
flag = 1;
publishProgress();
//10s SAMPLE
flag = 2;
for(int j = 0; j <= 10; j++ ){
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
publishProgress();
}
//PLAY THE SOUND
new Thread(new Runnable() {
#Override
public void run() {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
}
}).start();
flag = 3;
publishProgress();
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
switch (flag) {
case 0:
tv.setText(String.valueOf(counter));
break;
case 1:
tv.setText("");
progressDialog.setTitle("TAIKING SAMPLE");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMax(10);
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.show();
break;
case 2:
progressDialog.incrementProgressBy(1);
break;
case 3:
progressDialog.dismiss();
break;
case 4:
preparing.setMessage("Starting the device...");
preparing.setCanceledOnTouchOutside(false);
preparing.show();
break;
case 5:
preparing.dismiss();
break;
default:
break;
}
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
startStop.setClickable(true);
}
}
}
There are two issues:
You are not informing onProgressUpdate() of the countdown value
There is a race condition
doInBackground() and onProgressUpdate() methods are executed in two different threads and both methods/threads are accessing the flag field in a unsafe way. Instead of setting a value in flag in doInBackground() to be read in onProgressUpdate(), you can inform this value directly in the publishProgress() call. So I advise you to do the following:
public class SnapshotActivity extends AppCompatActivity {
// ...
// Change the Progress generic type to Integer.
class Async extends AsyncTask<Void, Integer, Void> {
// Remove the flag field.
// int flag = 0;
#Override
protected Void doInBackground(Void... params) {
//PROGRESS DIALOG
// Pass the flag argument in publishProgress() instead.
// flag = 4;
publishProgress(4);
// ...
// flag = 5;
publishProgress(5);
//HANDLE THE COUNTDOWN
for (counter = COUNTDOWN_TIME; counter>=1; counter--){
// The countdown progress has two parameters:
// a flag indicating countdown and
// the countdown value.
publishProgress(6, counter);
// ...
}
//PLAY THE SOUND
// ...
//PROGRESS DIALOG
// flag = 1;
publishProgress(1);
//10s SAMPLE
// flag = 2;
for(int j = 0; j <= 10; j++ ){
// ...
publishProgress(2);
}
//PLAY THE SOUND
// ...
// flag = 3;
publishProgress(3);
return null;
}
// This signature changes.
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Redeclare flag here.
int flag = values[0];
switch (flag) {
// ...
case 6:
tv.setText(Integer.toString(values[1]));
break;
// ...
}
}
}
}

How to stop a currently executing command

int count = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button start = (Button) findViewById(R.id.start);
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
String[] cmd = new String[] { "logcat", "-f",Environment.getExternalStorageDirectory()+"/log.txt", "-v", "time" };
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thread.start();
}
});
Button stop = (Button) findViewById(R.id.stop);
stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
Runtime.getRuntime().exec("logcat -d");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Button addLog = (Button) findViewById(R.id.addLog);
addLog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("logTag", Integer.toString(count));
count ++ ;
}
});
}
I want to start saving my app's log using start button and stop it using stop.
The addLog button is used to see if more lines are being added to log.txt file.
The start button works properly but the problem is it never ends with stop.
Even after pressing stop, when I press addLog button and check the log.txt
file, I see last lines have been added.
What is my fault ?
I need to start the stream, close this activity and take a tour in other activities then come back and shut the logging machine down.
Yes you can achieve that by saving the Process in a variable that is returned by the Runtime's exec() method and call destroy() on that variable.
public abstract void destroy ()
Terminates this process and closes any associated
streams.
Let's record the Process as a global variable;
private Process p;
and when executing it
p = Runtime.getRuntime().exec(cmd);
and this how it's stopped.
void stopProcess() {
if (p != null) {
p.destroy();
} else {
Log.d(TAG, "stopProcess: p==null");
}
}
Just use #hegazy method and save reference to process in your Application class. Don't forget to register it in your manifest. Hope you've got my idea.
Something like that:
((App)getApplicationContext).process = Runtime.getRuntime().exec(cmd);
and than take this when you need it:
((App)getApplicationContext).process.exec("logcat -d");

android app scanning before press start

I have also posted in android Enthusiasts, not sure if its the correct place..
We have created an app to scan for wifi hotspots / AP so we can read the SSID and RSSI. We have some test phones with hotspot turned on and hard coded the SSID into the app. When the APP launches for the first time all works OK, we click the AP (checkbox) and hit start (button).When we close the app and launch it again, as soon as we click the AP (checkbox) it start scanning even though we haven't click the start button. we need to reinstall the app on the phone every time. Can anyone help us with this BUG/ unwanted feature as its slowing us up.
here is the code for the main Activity.
your help is greatly appreciated.
public class RssiMyActivity extends Activity{
// Declare global variables
private WifiManager mainWifiObj;
private WifiScanReceiver wifiReciever;
private ListView list;
private ArrayAdapter<String> adapter;
private List<String> ap_details = new ArrayList<String>();
private static String ssid;
private int testCount;
private CheckBox a1, a2, a3, a4, a5, a6;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rssi_my);
list = (ListView) findViewById(R.id.listView1);
mainWifiObj = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifiReciever = new WifiScanReceiver();
// Get make a connection to database to get test count
ReceiveFromDB receiver = new ReceiveFromDB();
receiver.execute();
// Update the test count
testCount = ReceiveFromDB.getCount();
testCount += 1;
// Check to see what value testCount is
Log.e("Values for testCount", String.valueOf(testCount));
Button start;
start = (Button) findViewById(R.id.start);
start.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// Timer added to get new scan result once every 2 seconds
Timer myTimer = new Timer();
myTimer.schedule(new TimerTask()
{
#Override
public void run()
{
TimerMethod();
}
}, 0, 4000);
}
});
Button pause;
pause = (Button) findViewById(R.id.pause);
pause.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
onPause();
}
});
Button resume;
resume = (Button) findViewById(R.id.resume);
resume.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
onResume();
}
});
a1 = (CheckBox) findViewById(R.id.AP1);
a2 = (CheckBox) findViewById(R.id.AP2);
a3 = (CheckBox) findViewById(R.id.AP3);
a4 = (CheckBox) findViewById(R.id.AP4);
a5 = (CheckBox) findViewById(R.id.AP5);
a6 = (CheckBox) findViewById(R.id.AP6);
}
protected void onPause()
{
unregisterReceiver(wifiReciever);
super.onPause();
}
protected void onResume()
{
registerReceiver(wifiReciever, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
super.onResume();
}
// Timer method to run at the same time as the main activity
private void TimerMethod()
{
this.runOnUiThread(Timer_Tick);
}
/*
* Runnable method add code to here to refresh at specified time
*/
private Runnable Timer_Tick = new Runnable()
{
#Override
public void run()
{
try
{
// start a scan of ap's
mainWifiObj.startScan();
}
catch (Exception e)
{
e.getStackTrace();
}
}
};
class WifiScanReceiver extends BroadcastReceiver
{
#SuppressLint("UseValueOf")
public void onReceive(Context c, Intent intent)
{
// Clear details to refresh the screen for each new scan
if (ap_details.size() > 0)
{
try
{
ap_details.clear();
adapter.clear();
adapter.notifyDataSetChanged();
}
catch (Exception e)
{
e.printStackTrace();
}
}
try
{
// Get all Objects from the scan
List<ScanResult> wifiScanList = mainWifiObj.getScanResults();
List<ScanResult> temp = new ArrayList<ScanResult>();
// Run through each signal and retrieve the mac ssid rssi
for (ScanResult aWifiScanList : wifiScanList)
{
StringBuilder sb = new StringBuilder();
// Pull out the info we need
ssid = aWifiScanList.SSID;
// Check which ap's are selected
if (checkDisplay())
{
// Add info to StringBuilder
sb.append(aWifiScanList.SSID).append("\n");
sb.append(String.valueOf(aWifiScanList.level)).append("\n");
sb.append("Test: ").append(String.valueOf(testCount)).append("\n");
// Add to List that will be displayed to user
ap_details.add(sb.toString());
// Also add to a temporary ScanResult List to use later
temp.add(aWifiScanList);
}
}
// Create an String Array twice the size of the temporary
// ScanResult
// this will be the Array to use as the parameters for sending
// to the database
String[] items = new String[temp.size() + temp.size() + 1];
int num1 = 0;
int num2 = 1;
// Add the ssid and rssi of each object to the Array
for (ScanResult aTemp : temp)
{
items[num1] = aTemp.SSID;
items[num2] = String.valueOf(aTemp.level);
num1 += 2;
num2 += 2;
}
// Add the test value
items[num1] = String.valueOf(testCount);
// Pass Array to the Async method use executeOnExecutor this
// allows for the use
// of the Looper.prepare() method to stop app from crashing
new ConnectToDB().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, items);
// Display the list of all the signals on the device
adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, ap_details);
list.setAdapter(adapter);
}
catch (Exception e)
{
e.getStackTrace();
}
}
}
/*
* Method to check which AP's are been used
*/
public boolean checkDisplay()
{
if (a1.isChecked())
{
if (ssid.equalsIgnoreCase("TestPhone1"))
{
return true;
}
}
if (a2.isChecked())
{
if (ssid.equalsIgnoreCase("TestPhone2"))
{
return true;
}
}
if (a3.isChecked())
{
if (ssid.equalsIgnoreCase("TestPhone3"))
{
return true;
}
}
if (a4.isChecked())
{
if (ssid.equalsIgnoreCase("TestPhone4"))
{
return true;
}
}
if (a5.isChecked())
{
if (ssid.equalsIgnoreCase("TestPhone5"))
{
return true;
}
}
if (a6.isChecked())
{
if (ssid.equalsIgnoreCase("TestPhone6"))
{
return true;
}
}
return false;
}
You never call cancel() on your timer task to remove it from the Timer scheduler. Try inserting that in a button you use to stop it from scanning.
If that doesn't work, try calling cancel() on the timer itself.
ok got it working, not sure if its the right way but its working ok. I just unregister the reciecer and register it again by calling the two methods "onPause() and onResume()" one after the other and just before the startScan() method. see code:
private Runnable Timer_Tick = new Runnable()
{
#Override
public void run()
{
try
{
// unRegister Receiver wifiReciever
onPause();
// register Receiver wifiReciever
onResume();
// start a scan of ap's
mainWifiObj.startScan();
}
catch (Exception e)
{
e.getStackTrace();
}
}
};
would love to know if this is correct way to do it.

Android UI is not updating

I'm working on a countdown that shows seconds remaining to start of the game. So I put TextView into middle of layout and in for loop I am changing the text of TextView, playing the sound using MediaPlayer, then waits 1 second and repeat the proccesss.
The problem is that my text view is not updating - after finishing whole for loop it just change TextView to last text that should be displayed. But since all sounds was played, I can say that Activity is running normaly. So I'm looking for some easy way how to update my UI. I saw some examples of AsynTask, but I think that's too difficult solution for this simple problem. Also, I've tried using handle to change text, but it has got no effect.
My code:
This is in onResume() method:
//Using handler to delay countdown,
//so Activity have enough time to display view
hand.postDelayed((new Runnable(){
#Override
public void run() {
countdownToStart();
game.start();
}
}), 1000);
countdownToStart() method:
protected void countdownToStart(){
int soundSource[] = {R.raw.cntdwn_three, R.raw.cntdwn_two, R.raw.cntdwn_one, R.raw.cntdwn_go};
final String nums[] = {"3", "2", "1", "GO"};
final TextView countdownText = (TextView) findViewById(R.id.challenge_countdown_text);
Handler hand2 = new Handler();
//4 different texts = 4 cycles of for loop
for(int i = 0; i < 4; i++){
//Load sound
for(int x = 0; x < 5; x++){
countdownSound = MediaPlayer.create(getApplicationContext(), soundSource[i]);
if(countdownSound != null)
break;
}
if(countdownSound == null){
Toast.makeText(getApplicationContext(), R.string.sound_load_error, Toast.LENGTH_SHORT).show();
onBackPressed();
}
countdownSound.start();
//Set textview
countdownText.setText(nums[i]);
if(i == 3)
countdownText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 200);
//Delay between countdowns
SystemClock.sleep(1000);
//Release MediaPlayer
countdownSound.release();
}
}
}
Try RunOnUIThread by creating a new Thread
Updated
final TextView countdownText = (TextView) findViewById(R.id.challenge_countdown_text);
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try{
for(int i = 0; i < 4; i++){
//Load sound
for(int x = 0; x < 5; x++){
countdownSound = MediaPlayer.create(getApplicationContext(), soundSource[i]);
if(countdownSound != null)
break;
}
if(countdownSound == null){
Toast.makeText(getApplicationContext(), R.string.sound_load_error, Toast.LENGTH_SHORT).show();
onBackPressed();
}
countdownSound.start();
//Set textview
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
countdownText.setText(nums[i]);
if(i == 3)
countdownText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 200);
}
});
Thread.sleep(1000);
}
}
catch(Exception e){
// handle exception
}
}
}).start();
//Delay between countdowns
SystemClock.sleep(1000);
//Release MediaPlayer
countdownSound.release();
}
I'm 7 years behind schedule, but..
If you're using view binding,
And already setup binding, check if in setContentView it's R.layout.whateverlayout or binding.getRoot()

Android Handler.postDelayed interrupts sound playing

I am using this code to play a sound
final MediaPlayer mp = MediaPlayer.create(this, R.raw.sound);
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
It works fine on its own, however there was a problem after I added an animation that extends ImageView, which refreshes(by calling handler.postDelayed) the image resource at an interval about 30ms to create animation. The problem is that when the animation starts, it terminates the the playing of the sound. Here is the code for the Runnable that refreshes the ImageView.
private Runnable runnable = new Runnable () {
public void run() {
String name = "frame_" + frameCount;
frameCount ++;
int resId = mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
imageView.setImageResource(resId);
if(frameCount < totalFrameCount) {
mHandler.postDelayed(runnable, interval);
}
}
};
I also tried to use a thread that calls the anmiationView.postInvalidate to do the animation, however it has the same problem. Please help. Thanks
Edit:
It looks like the problem is due to WHEN the animation is called. Previously I called it in the onActivityResult of the activity. Looks like this is not the right place to call. Now I put the animation view in a popupWindow and play it there, it works properly. Not sure exactly why.
in handler's comments :
"A Handler allows you to send and process {#link Message} and Runnable
objects associated with a thread's {#link MessageQueue}. Each Handler
instance is associated with a single thread and that thread's message
queue. When you create a new Handler, it is bound to the thread /
message queue of the thread that is creating it -- from that point on,
it will deliver messages and runnables to that message queue and execute
them as they come out of the message queue."
so, the problem may be caused by both of animation and media playing operations are in
the same message queue own by which thread create the handler (let's say the main thread).
if the animation loops for ever, then the media player will hardly get any chance to run.
you could take it a try with HandlerThread, the thread will contain a new looper for the
handler created from it, all the runnables added to that handler will be running in another
individual thread.
the animation thread and the media play thread should be running in the different threads not
scheduling in the same one.
hope, it helps.
the HandlerThread usage and some discuss looks like this :
How to create a Looper thread, then send it a message immediately?
maybe it is caused by your miss arranged codes, i take it a try on my nexus 4 with android version 4.4.2, even no any cache tech, the animation and music works like a charm...
here is the major codes :
public class MainActivity extends Activity implements View.OnClickListener {
protected static final String TAG = "test002" ;
protected static final int UPDATE_ANI = 0x0701;
protected static final int UPDATE_END = 0x0702;
protected static final int[] ANI_IMG_IDS = {R.raw.img1, R.raw.img2, R.raw.img3, R.raw.img4,
R.raw.img5, R.raw.img6, R.raw.img7};
protected static final int[] BTN_IDS = {R.id.btnStart, R.id.btnStop};
protected android.os.Handler aniHandler = null; // async update
protected boolean isAniRunning = false ;
protected int aniImgIndex = 0 ;
protected ImageView aniImgView = null ;
protected MediaPlayer mediaPly = null ;
// animation timer
class AniUpdateRunnable implements Runnable {
public void run() {
Message msg = null ;
while (!Thread.currentThread().isInterrupted() && isAniRunning) {
msg = new Message();
msg.what = UPDATE_ANI;
aniHandler.sendMessage(msg);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break ;
}
}
msg = new Message() ;
msg.what = UPDATE_END ;
aniHandler.sendMessage(msg) ;
}
}
protected void prepareMediaPlayer(MediaPlayer mp, int resource_id) {
AssetFileDescriptor afd = getResources().openRawResourceFd(resource_id);
try {
mp.reset();
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
afd.close();
mp.prepare();
} catch (IllegalArgumentException e) {
Log.d(TAG, "IlleagalArgumentException happened - " + e.toString()) ;
} catch(IllegalStateException e) {
Log.d(TAG, "IllegalStateException happened - " + e.toString()) ;
} catch(IOException e) {
Log.d(TAG, "IOException happened - " + e.toString()) ;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// init : buttons onclick callback
{
Button btn;
int i;
for (i = 0; i < BTN_IDS.length; i++) {
btn = (Button) findViewById(BTN_IDS[i]);
btn.setOnClickListener(this);
}
}
// init : update animation handler callback
{
aniHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_ANI:
updateAniImages();
break ;
case UPDATE_END:
updateAniEnd();
break ;
default:
break;
}
}
};
}
// init : prepare image view
{
aniImgView = (ImageView)findViewById(R.id.imgAni) ;
mediaPly = MediaPlayer.create(this, R.raw.happyny) ;
mediaPly.setLooping(true);
}
}
protected void updateAniImages() {
if(aniImgIndex >= ANI_IMG_IDS.length) {
aniImgIndex = 0 ;
}
InputStream is = getResources().openRawResource(ANI_IMG_IDS[aniImgIndex]) ;
Bitmap bmp = (Bitmap) BitmapFactory.decodeStream(is) ;
aniImgView.setImageBitmap(bmp);
aniImgIndex++ ;
}
protected void updateAniEnd() {
aniImgIndex = 0 ;
aniImgView.setImageBitmap(null);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
isAniRunning = true ;
// no re-enter protectiion, should not be used in real project
new Thread(new AniUpdateRunnable()).start();
mediaPly.start();
break;
case R.id.btnStop:
isAniRunning = false ;
mediaPly.stop();
prepareMediaPlayer(mediaPly, R.raw.happyny);
break;
default:
break;
}
}
}
the major project codes and test apk should be find here :
apk installer
source code

Categories

Resources