I am trying to implement a radio player (using shoutcast streams) for android. What I want to do is, while the radio stream loads in the player, the UI displays a spinning wheel animation. On successful loading (as soon as the song starts playing) the animation disappears.
Here is the code that I am using.
PlayStopStreamingButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread initializer = new Thread(new Runnable() {
#Override
public void run() {
Looper.myLooper();
Looper.prepare();
progressDialog = ProgressDialog.show(RadioPlayerActivity.this, "", "Selecting Radio Station",
true);
JukefoxApplication.getHandler().post(new Runnable() {
#Override
public void run() {
radioPlayerEventListener.onPlayStopStreamingButtonClicked();
progressDialog.dismiss();
}
});
}
});
initializer.start();
}
});
I don't get any spinning animation. I am almost certain that my mistake lies in incorrect handling of threads. If someone could out the correct way, I would be grateful.
EDIT, this seems to work:
PlayStopStreamingButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
progressDialog = ProgressDialog.show(RadioPlayerActivity.this, "", "Selecting Radio Station", true);
Thread initializer = new Thread(new Runnable() {
#Override
public void run() {
radioPlayerEventListener.onPlayStopStreamingButtonClicked();
progressDialog.dismiss();
}
});
initializer.start();
}
});
You need to show progress dialog on UI thread, see below:
PlayStopStreamingButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread initializer = new Thread(new Runnable() {
#Override
public void run() {
Looper.myLooper();
Looper.prepare();
RadioPlayerActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progressDialog = ProgressDialog.show(RadioPlayerActivity.this,
"", "Selecting Radio Station", true);
}
});
JukefoxApplication.getHandler().post(new Runnable() {
#Override
public void run() {
radioPlayerEventListener.onPlayStopStreamingButtonClicked();
RadioPlayerActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
}
});
}
});
initializer.start();
}
});
Related
In my fragment, I have an AlertDialog and a Bluetooth connection manager. I want to update the AlertDialog with the new states of the Bluetooth connection process, so I used the runOnUiThread(...) method:
getActivity().runOnUiThread(new Runnable() {
#Override
void run() {
interactor = new BluetoothInteractor(getActivity(), new OnBluetoothStatusChangedListener() {
#Override
public void OnConnectionStopped() {
alertDialog.setMessage("Disconnected.");
}
#Override
public void OnConnectionStopping() {
alertDialog.setMessage("Stopping connection...");
}
#Override
public void OnConnectionStarting() {
alertDialog.setMessage("Connecting to device...");
}
#Override
public void OnConnectionStarted() {
alertDialog.setMessage("Streaming data...");
}
});
}
});
The first time I update the AlertDialog message (OnConnectionStarting event) everything works fine, but the second time I got android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
What could be happening here?
Replace with
interactor = new BluetoothInteractor(getActivity(), new OnBluetoothStatusChangedListener() {
#Override
public void OnConnectionStopped() {
getActivity().runOnUiThread(new Runnable() {
#Override
void run() {
alertDialog.setMessage("Disconnected.");
}
});
}
#Override
public void OnConnectionStopping() {
getActivity().runOnUiThread(new Runnable() {
#Override
void run() {
alertDialog.setMessage("Stopping connection...");
}
});
}
#Override
public void OnConnectionStarting() {
getActivity().runOnUiThread(new Runnable() {
#Override
void run() {
alertDialog.setMessage("Connecting to device...");
}
});
}
#Override
public void OnConnectionStarted() {
getActivity().runOnUiThread(new Runnable() {
#Override
void run() {
alertDialog.setMessage("Streaming data...");
}
});
}
});
I know that is easy to do it, but I've tried to take some examples from here and is not showing the progressDialog. That I want to do is show a ProgressDialog when click the button and finish when the task is finished:
Thanks in advance!
buttonStartOCR.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
progress = ProgressDialog.show(SimpleAndroidORCActivity.this, "Processing", "Please wait...", true);
new Thread(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
onPhotoTaken();
}
});
};
}).start();
progress.dismiss();
}
});
Your ProgressDialog is showing but its dismissed right after the show. Put your dismiss inside the run method of your runnable.
This way:
buttonStartOCR.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
progress = ProgressDialog.show(SimpleAndroidORCActivity.this, "Processing", "Please wait...", true);
new Thread(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
onPhotoTaken();
progress.dismiss();
}
});
};
}).start();
}
});
a thread is an independent process which runs in background your progress bar is showing and dismissing immediately, call progress.dismiss(); in your run() after your onPhotoTaken()
in below code you dismiss the dialog as it start also running thread so dismissing dialog can't wait for task which is inside thread.
buttonStartOCR.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
progress = ProgressDialog.show(SimpleAndroidORCActivity.this, "Processing", "Please wait...", true);
new Thread(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
onPhotoTaken();
progress.dismiss();
}
});
};
}).start();
}
});
onPhotoTaken() :- should return any value so that we can dismiss dialog.
and dismiss dialog in main thraed
i created running app and i trying to create stopper that starting when user press start button.
but when i using thread the application return black screen
,this is my onCreate method i added thread
Thread t = new Thread() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
SetTextOnView();
}
});
}
};
t.start();
the SetTextOnView method contain
public void SetTextOnView()
{
TextView timedisp = (TextView) findViewById(R.id.stopperdisplay);
while(true)
{
timedisp.setText(String.valueOf(total));
}
}
the problem start when i add the while statment
why is that?
Do the loop in your thread to not block the ui thread + add some delay to not block the ui thread :
Thread t = new Thread() {
public void run() {
while (true) {
runOnUiThread(new Runnable() {
#Override
public void run() {
SetTextOnView();
}
});
Thread.sleep(1000);
}
}
};
And your SetTextOnView :
public void SetTextOnView()
{
TextView timedisp = (TextView) findViewById(R.id.stopperdisplay);
timedisp.setText(String.valueOf(total));
}
I am trying to execute the method doSomeWork(); after the ProgressDialog dismisses in my method printing();which seems to be overlapped by the other method and the dialog is not showed up. If I comment method doSomeWork(); the dialog is displayed correctly until the thread is finished.
Here is my method printing();
public void printing()
{
final ProgressDialog printingDialog = ProgressDialog.show(this, "Printing...", "Please wait", true, false);
new Thread(new Runnable() {
#Override
public void run()
{
//something big executing here
}
}).start();
}
He is my method doSomework():
public void doSomeWork(){
Thread receiptPrint = new Thread(new Runnable() {
#Override
public void run() {
//something here
runOnUiThread(new Runnable() {
#Override
public void run() {
//another dialog here
}
});
}
});
}
Here you can see the how I am calling those two methods:
private OnClickListener onClickPrint = new OnClickListener() {
public void onClick(final View v) {
Log.d("Button","Clicked on Print Order Button");
printing();
doSomeWork();
Does anyone know how could I execute doSomeWork() only when printing(); will be completely finished?
This is one of the purposes of an AsyncTask. It would look similar to this:
public void onClick(final View v) {
new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
//Show your progress dialog in here
super.onPreExecute();
}
#Override
protected Void doInBackground( Void... params ) {
printing();
return null;
}
#Override
protected void onPostExecute( Void result ) {
//Dismiss your progress dialog here
doSomeWork();
}
}.execute();
}
Instead of using thread you can use asynchronous task. Show the progress dialog in the preexecute method call the printing method inside the background method after completing printing operation call the doSomeWork() inside the postexecute method.
You can use Handler for that in android. for example consider the following piece of code. you can dismiss the dialogs inside handlers. may it work for you.
private void printing(){
Thread receiptPrint = new Thread(new Runnable() {
#Override
public void run() {
retrieveEmails();
runOnUiThread(new Runnable() {
#Override
public void run() {
try{
//here your code executes
//after code executes do following:
uiHandler.sendEmptyMessage(0);
}catch(Exception ex){
errorHandler.sendEmptyMessage(0);
}
}
});
}
});
receiptPrint.start();
}
final Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
//here execute doSomeWork()
}
};
final Handler errorHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
//do other stuff
}
};
I hit my head against the wall, trying to solve this problem for some time. I'm not an experienced Android guy, so its solution might be really simple. That being said, I have the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.adminusers);
super.onCreate(savedInstanceState);
// set user_type for Viewall
mUserType = 0;
lv_adminusersListContent.addFooterView(footerView);
mUsersAdapter = new AdminUsersAdapter(mUsersList, AdminUsers.this);
lv_adminusersListContent.setAdapter(mUsersAdapter);
getUsersList();
}
private void getUsersList() {
if (UsefulFcts.isOnline(AdminUsers.this)) {
if (mThread != null && mThread.isAlive()) {
mThread.interrupt();
}
mThread = new Thread() {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
pDialog = new ProgressDialog(AdminUsers.this);
pDialog.setMessage("Loading.. Please wait!");
pDialog.setCancelable(false);
pDialog.show();
}
});
mUsersList.clear();
mUsersList.addAll(mServiceManager.getUsersList(mUserType,
0 + "", AdminServiceManager.sHowManyToLoad));
mArrayLength = mUsersList.size();
Log.d("arrayLength", String.valueOf(mArrayLength));
Log.d("total_results",
String.valueOf(ParserJSON.total_results));
mHandler.post(new Runnable() {
#Override
public void run() {
// refresh listview
mUsersAdapter.notifyDataSetChanged();
if (mArrayLength < ParserJSON.total_results) {
lv_adminusersListContent
.addFooterView(footerView);
} else if (mArrayLength >= ParserJSON.total_results) {
lv_adminusersListContent
.removeFooterView(footerView);
}
if (0 == mArrayLength) {
Toast.makeText(AdminUsers.this,
"No username found!",
Toast.LENGTH_SHORT).show();
}
pDialog.dismiss();
}
});
}
};
mThread.start();
} else {
Toast.makeText(AdminUsers.this, "Internet connection required!",
Toast.LENGTH_LONG).show();
}
}
#Override
protected void linkUI() {
// begin load_more view
footerView = AdminUsers.this.getLayoutInflater().inflate(
R.layout.loadmore, null);
btn_loadmore = (Button) footerView.findViewById(R.id.btn_loadmore);
// end load_more view
btn_adminusersViewall = (Button) findViewById(R.id.btn_adminusersViewall);
btn_adminusersAdmins = (Button) findViewById(R.id.btn_adminusersAdmins);
btn_adminusersClients = (Button) findViewById(R.id.btn_adminusersClients);
btn_adminusersDevs = (Button) findViewById(R.id.btn_adminusersDevs);
btn_adminAdd = (ImageButton) findViewById(R.id.btn_adminAdd);
lv_adminusersListContent = (ListView) findViewById(R.id.lv_adminusersListContent);
}
#Override
protected void setAction() {
// begin Buttons UnderHeader
btn_adminusersViewall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UsefulFcts.setButtonClicked(btn_adminusersViewall,
btn_adminusersClients, btn_adminusersAdmins,
btn_adminusersDevs);
mUserType = 0;
mArrayLength = -1;
lv_adminusersListContent.removeFooterView(footerView);
getUsersList();
}
});
btn_adminusersClients.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UsefulFcts.setButtonClicked(btn_adminusersClients,
btn_adminusersDevs, btn_adminusersAdmins,
btn_adminusersViewall);
mUserType = 1;
mArrayLength = -1;
// view.setVisibility(View.GONE);
getUsersList();
}
});
btn_adminusersDevs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UsefulFcts.setButtonClicked(btn_adminusersDevs,
btn_adminusersClients, btn_adminusersAdmins,
btn_adminusersViewall);
mUserType = 2;
mArrayLength = -1;
lv_adminusersListContent.removeFooterView(footerView);
getUsersList();
}
});
btn_adminusersAdmins.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mUserType = 3;
mArrayLength = -1;
lv_adminusersListContent.removeFooterView(footerView);
getUsersList();
}
});
// end Buttons UnderHeader
btn_loadmore.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mThread2 = new Thread() {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
progressBar = new ProgressDialog(
AdminUsers.this);
progressBar
.setMessage("Loading more projects.. ");
progressBar.setCancelable(true);
progressBar.show();
}
});
mUsersList.addAll(mServiceManager.getUsersList(
mUserType, String.valueOf(mArrayLength),
AdminServiceManager.sHowManyToLoad));
mArrayLength = mUsersList.size();
mHandler.post(new Runnable() {
#Override
public void run() {
mUsersAdapter.notifyDataSetChanged();
if (mArrayLength >= ParserJSON.total_results) {
lv_adminusersListContent.removeFooterView(footerView);
}
progressBar.dismiss();
}
});
};
};
mThread2.start();
}
});
Note: I basically have a listview which content is requested from a server depending on which button (looking like a tab) I'm pressing (mUserType = 0/1/2/3). I also use a Load More button (footerView = simple layout with a button).
Everything seems to work just fine, but after "playing" with the buttons a few times (random number!) it crashes, with the following exception thrown:
02-21 11:00:49.252: E/AndroidRuntime(11728): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131296461, class android.widget.ListView) with Adapter(class android.widget.HeaderViewListAdapter)]
So, I looked back at the code, but couldn't see any "not on UI thread" listview notification.
1. What could the problem be?
2. Is it necessary to use 2 threads (mThread and mThread2), or could I use the same one, as one's work should start when the other ends (or isn't it ?) and should I declare them static or not ?
Also pointing me to any "Good practices" tricks I could use in the future, or "Wrong practices" that I did would be much appreciated!
PS. linkUI() and setAction() are called in super().onCreate().
The error message seems understandable : you are modifying the adapter from mThread:
mUsersList.clear();
mUsersList.addAll(mServiceManager.getUsersList(mUserType,
0 + "", AdminServiceManager.sHowManyToLoad));
You can try something like this:
final List newUserList = mServiceManager.getUsersList(mUserType,
0 + "", AdminServiceManager.sHowManyToLoad);
mArrayLength = newUserList.size();
Log.d("arrayLength", String.valueOf(mArrayLength));
Log.d("total_results",
String.valueOf(ParserJSON.total_results));
mHandler.post(new Runnable() {
#Override
public void run() {
mUsersList.clear();
mUsersList.addAll(newUserList);
// refresh listview
mUsersAdapter.notifyDataSetChanged();