Using runOnUiThread to change TextView text in Android - android

I've got an app that makes API calls when the user logs in, I've got two classes, one that Pushes to the API and one that Pulls from it. I've also got an asyncTask on my LogIn Activity which handles the network connection. When the network connection starts I have a view switcher to switch the view to a progress loader and a textview, the textview is used to display stuff like "Connecting", "Downloading Data", ect.
The problem is my API Push and Pull methods are stored in different classes and the LogIn AsyncTask simply calls them, it all works except for updating the TextView to let the user know the progress.
In the LogIn activity, I have this method, which changes the textview info to whichever number is passed to it.
public void updateProgress(int i) {
switch (i) {
case 0:
loadInfo.setText(R.string.log_in_thread_Connecting);
break;
case 1:
loadInfo.setText(R.string.log_in_thread_Connected);
break;
case 2:
loadInfo.setText(R.string.log_in_Thread_Sending_Data);
break;
case 3:
loadInfo.setText(R.string.log_in_thread_Response);
break;
case 4:
loadInfo.setText(R.string.log_in_web_connecting);
break;
case 5:
loadInfo.setText(R.string.log_in_web_connected);
break;
case 6:
loadInfo.setText(R.string.log_in_web_user_data_download);
break;
case 7:
loadInfo.setText(R.string.log_in_web_user_data_downloaded);
break;
case 8:
loadInfo.setText(R.string.log_in_web_device_data_upload);
break;
}
}
This works if i'm calling it from the AsyncTask from the LogIn Activity but not from the API classes.
I have found a method called .runOnUiThread so I tried to implement that.
private void publishProgress(final int i){
logInActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
logInActivity.updateProgress(i);
Log.d("UI THREAD","HIT");
}
});
}
This is what I have come up with, but it doesn't seem to be hitting, I don't even see the Log post.
I did also have an error implementing this but it was resolved when I added Looper.prepare(); to the Log in AsyncTask
AsyncTask
private class RegistrationWeb extends AsyncTask<Void,Void,Void>{
private static final String tag = "API_LogIn";
private String APIKey = null
#Override
protected void onPreExecute() {
super.onPreExecute();
viewFlipper.showNext();
APIKey = getAPIKey();
}
#Override
protected Void doInBackground(Void... voids) {
try{
Looper.prepare();
GetAPIData get = new GetAPIData();
URL url = new URL(API_Register_User+APIKey);
String response = get.GetData(url);
JSONArray jsonArray = new JSONArray(response);
JSONObject jsonObject = jsonArray.getJSONObject(0);
//If the user is accepted
if(jsonObject.getString("_Code").equals("0")){
PublishProgress(8);
PostAPIData post = new PostAPIData();
url = new URL(API_Register_Device);
response = post.PostData(url);
jsonArray = new JSONArray(response);
jsonObject = jsonArray.getJSONObject(0);
} else if(jsonObject.getString("_Code").equals("2")){
}
} catch (MalformedURLException e) {
Log.e(tag,e.toString());
} catch (JSONException e) {
Log.e(tag,e.toString());
} catch (IOException e) {
Log.e(tag,e.toString());
}
return null;
}
private void PublishProgress(final int i){
runOnUiThread(new Runnable() {
#Override
public void run() {
updateProgress(i);
}
});
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}

You can not directly access string that are present in resource, you will have to to acquire resources first to use its content. You need to call getResources() from your Activity, then you can get the string you are looking for.
YourActivity.context.getResources().getString(R.string.id_name);
Override onProgressUpdate() and then call publishProgress()
public void publishProgress(Integer v) {
Message message = new Message();
message.what = v;
YourActivity.handler.sendMessage(message);
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
publishProgress(values[0);
}
And change your AsyncTask parameter during its creation from Void to Integer
class RegistrationWeb extends AsyncTask<Integer,Integer,Integer> {
}
In your Activity where your TextView resides on which you want update, make Handler to listen the messages from outer class and in that Handler update your TextView.
Activity:
public static Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
//update your text view on the basis of msg.what
}
}
};
Note : Make your TextView loadInfo as static

Related

Showing a progressDialog from an OptionsMenu

I know the following is probably not the best practice and not recommended to do.
I have an AsyncTask that sends data to server. The whole process that i need to do includes 4 web calls using this AsyncTask in quick succession.
I understand that with AsyncTask you must start and stop the ProgressDialog in OnPreExecute and OnPostExecute. I do normally do this.
The problem is that i call 4 AsyncTask in a row one after another, so i don't want 4 Progress dialogs repeating one after another.
I use AsyncTask.execute().get(), so they are called sequentially.
I call these AsyncTasks in a loop from the optionsMenu. What i am trying to do is set up a global ProgressDialog that i can start in the optionsMenu before the loop and cancel it after the loop.
The problem is that it doesn't show. I thought it may be because it needs to run on the UI thread so i placed it inside a Handler, but still no luck.
How can I show the progressdialog from the optionsMenu?
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menuclientassessment, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.sendclientassessment:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
progressDialog2 = new ProgressDialog(ClientAssessmentActivity.this);
progressDialog2.setTitle("Connecting to Server");
progressDialog2.setMessage("Sending the assessment to server...");
progressDialog2.setIndeterminate(true);
try {
progressDialog2.show();
} catch(Exception e){
//ignore
}
}
});
for(int i = 0; i < arr.size(); i++) {
String [] params = new String[6];
AssessmentScore as = null;
as = arr.get(i);
params[0] = clientID;
params[1] = carerID;
params[2] = comments.getText().toString();
DateTime now = new DateTime();
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd'T'H:mm");
String formattedNowTime = df.print(now);
params[3] = formattedNowTime;
params[4] = as.getElementID();
params[5] = as.getValue();
AsyncSendAssessment asa = null;
asa = new AsyncSendAssessment();
try {
asa.execute(params).get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//end of loop
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
try {
progressDialog2.dismiss();
} catch(Exception e) {
//ignore
}
}
});
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Have the progress dialog be a class variable, then instantiate it when you create the activity. That way you can access it anywhere in the application.
Create your dialog to be a class extending the class Dialog. For eg. - TestDialog. Then create a Util class with common functions using the dialog.
public class TestDialog extends Dialog {
}
Util:
public class TestDialogUtil {
public static TestDialog processingDialog;
public static void createProcessingDialog();
public static void dismissProcessingDialog();
}
Then in any of your Activities call TestDialogUtil.createProcessingDialog or TestDialogUtil.dismissProcessingDialog. You won't get extra dialogs getting created. Create a new Dialog only when processingDialog is not null.

Android program stops at doInBackground and doesn't come to onPostExecute

My program crashs after doInBackground and doesn't come to onPostExecute.
My activity code's related parts are like this:
public static class News {
private String title;
private String content;
private Bitmap image;
public News(String nTitle, String nContent, Bitmap nImage){
title = nTitle;
content = nContent;
image = nImage;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_news);
final AsyncTask task = new DatabaseConnection(this, Method.GET_ALL_NEWS).execute();
try {
task.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public final void fillListView(List<News> news){
recentNews = news;
if(recentNews != null && !recentNews.isEmpty()){
((ListView)findViewById(R.id.lvNews)).setOnItemClickListener(this);
final int size = recentNews.size();
final String newsTitles[] = new String[size];
for(int i=0; i<size; ++i)
newsTitles[i] = recentNews.get(i).title;
((ListView)findViewById(R.id.lvNews)).setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, newsTitles));
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final News selectedNews = recentNews.get(position);
startActivity(new Intent(this, ANewsActivity.class)
.putExtra("title", selectedNews.title)
.putExtra("content", selectedNews.content)
.putExtra("image", BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)));
}
My AsyncTask code's related parts are like this:
public DatabaseConnection(Context nContext, Method nMethod){
method = nMethod;
context = nContext;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(context);
progressDialog.setMessage(context.getString(R.string.database_connection_wait_message));
progressDialog.setTitle(R.string.database_connection_wait_title);
progressDialog.show();
}
#SuppressWarnings("incomplete-switch")
#Override
protected Void doInBackground(String... params) {
if(method != Method.NONE){
open();
try{
switch(method){
case GET_ALL_NEWS:
final ResultSet rs = conn.createStatement().executeQuery("select baslik, metin, resim from haberler");
news = new ArrayList<News>();
while(rs.next())
news.add(new News(rs.getString(1), rs.getString(2), BitmapFactory.decodeStream(rs.getBlob(3).getBinaryStream())));
break;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
}
return null;
}
#SuppressWarnings("incomplete-switch")
#Override
protected void onPostExecute(Void temp) {
if (progressDialog.isShowing()){
progressDialog.dismiss();
switch(method){
case GET_ALL_NEWS:
((NewsActivity)context).fillListView(news);
break;
}
method = Method.NONE;
}
}
I want UI thread waits until database operations finishes.
By the way there is no initialization problem at variables etc and database returns proper infos and my "news" variable is filled normally.
By the way again I realized it is WORKING on PHONE, STUCKS on EMULATOR interestingly (if I remove wait() method and its try-catch block on main thread code).
It's difficult to say what is crashing without the logcat output, but it would most likely be the main thread of the app because of the .wait() method you are calling in onCreate(). Your onCreate() cannot wait - it must initialize and exit, otherwise you are blocking the main thread of your app and defeating the purpose of the AsyncTask.

AsyncTask displaying progress bar

I am very new to android. I got two activities A, B . Activity A parse the data from the sever and iterate through the levels. and calls the activity B through intent. Activity B takes some time to display the data so I am trying to display the progress bar. Here is my code.
public class Display extends Activity {
ProgressDialog dialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.attributequestions);
new asynctask().execute();
}
class asynctask extends AsyncTask<Context,Void,Void>{
Survey[] surveyque=null;
// i hace created seperated class forsurvey that has info about data
String list[];
private ProgressDialog Dialog;
#Override
protected void onPreExecute()
{
Dialog=ProgressDialog.show(Display.this, "Parsing Data", "Please wait..........");
}
#Override
protected void onPostExecute(Void unused)
{
try
{
if(Dialog.isShowing())
{
Dialog.dismiss();
}
Intent intent=getIntent();
}
catch(Exception e)
{
Log.d("Onsitev4", "error");
}
}
#Override
protected Void doInBackground(Context... params) {
try {
LinearLayout layout1 = (LinearLayout) findViewById(R.id.linearLayout1);
//getting exception here. I dont understant why
// I have declared layout params and displaying activities in another class
ButtonView c = new ButtonView();
c.layout=layout1;
c.context =getBaseContext();
DbCoreSqlSurveys surveys=new DbCoreSqlSurveys(getBaseContext());
Document doc =surveys.getSurveySet();
surveyquestions= GetSurveyLevels(doc,c );
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
}
return null;
}
}
public SurveyObject[] GetSurveyLevels(Document doc, ButtonView c) {
NodeList nlQuestions = doc.getElementsByTagName("Survey");
SurveyObject[] allsurveys = new SurveyObject[nlQuestions.getLength()];
for (int i = 0; i < nlQuestions.getLength(); i++){
Node survey = nlQuestions.item(i);
String f =survey.getNodeName();
Log.d("OnsiteV4", "survey " + f);
NodeList surveyChildNodes = survey.getChildNodes();
SurveyObject s=new SurveyObject();
for (int j = 0; j < surveyChildNodes.getLength(); j++){
Node surveyChild = surveyChildNodes.item(j);
String h =surveyChild.getNodeName();
Log.d("OnsiteV4", "survey child node = " + h);
if (h !="#text"){
Surveys t = Surveys.valueOf(h);
switch(t){
case KeySurvey:
s.KeySurvey=surveyChild.getTextContent();
displaySurveyLink(s.SurveyDescription,"",c,0,s.SurveyDescription,"","","","");
break;
case SurveyDescription:
s.SurveyDescription=surveyChild.getTextContent();
displaySurveyLink(s.SurveyDescription,"",c,0,s.SurveyDescription,"","","","");
break;
case SurveyUserCode:
s.SurveyUserCode=surveyChild.getTextContent();
break;
case Level1:
if(surveyChild.hasChildNodes()){
s.Level1= processLevel1Nodes(surveyChild,c,s.SurveyDescription);
}
break;
default:
break;
}
}
allsurveys[i]=s;
}
}
return allsurveys;
}
// methods iterating through levels that is not showed
private void displaySurveyLink(final String description, String tag, ButtonView c, int indentation, final String surveyDescription, final String level1description, final String level2description, final String level3description, final String level4description)
{
if (description == null || tag == null){
return;
}
final TextView tv = c.addButton(description,tag,indentation);
tv.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
final Intent intent = new Intent();
intent.setClass(v.getContext(),ActivityB.class);
intent.putExtra("KeyLevel",tv.getTag().toString());
intent.putExtra("SurveyDescription",surveyDescription);
intent.putExtra("level1description",level1description);
intent.putExtra("level2description",level2description);
intent.putExtra("level3description",level3description);
intent.putExtra("level4description",level4description);
intent.putExtra("Description",description);
if (tv.getTag() != null){
if (tv.getTag().toString() != ""){
startActivity(intent);
}
}
}
});
}
}
I am getting exception in doinbackground. I am confused . please help me..
You are getting an exception because you are accessing UI elements on a non-UI thread. The main thread that the application creates is the UI thread, and that's where all of your visual elements are created and therefore the only thread in which you should access them.
To appropriately use AsyncTask, you run your long-running operations in doInBackground, and you use onPreExecute, onPostExecute and onProgressUpdated to work with the UI (show/hide progress dialogs, update views, etc). Whenever I use an AsyncTask and I want to show progress, I override onProgressUpdated giving it parameter type Integer and I call publishProgress from doInBackground. This would require a change of the base class signature from AsyncTask<Context,Void,Void> to AsyncTask<Context,Integer,Void>. You can use other object types for this as well...I just use Integer as an example if you want to show the percentage of the task that is complete, for example.
It's becoz your code should throwing exception as you are doing UI stuff in the doinbackgound of asyc task. Please remove all the UI related work from doingbackgound method.

AsynTask - onPostExecute is called before doInBackground

i got a problem getting my AsyncTask to work correct. My App offers the possibility to connect with your Google Account and add and receive tasks by using the Tasks API. When the users wants to synchronize with his account, the doInBackground() method is started. Right before that, a ProgressDialog is displayed in the onPreExecute() method of the AsyncTask class.
If the synchronisation has been successfully executed, the onPostExecute() method 'should' be called fading out the ProgressDialog.
But there is problem: the onPostExecute() ethod is called before the work in the doInBackground() is finished.
In doInBackground() I receive the token used for the authorization:
token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
That's all. But right before that, the onPostExecute() is called and the ProgressDialog disappears while the token is still retrieving. The wired thing is that when I start the app and synchronizes for the first time, it works like it should. But after that the onPostExecute() method finishes before the work is completed. Does this have to do that there are requests to a server while executing
future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
How can I tell the onPostExecute() method that there is still work to do?
private class SynchronizeGoogle extends AsyncTask<Void, Integer, Void>
{
private final ProgressDialog dialog = new ProgressDialog(RememberMe.this);
protected void onPreExecute()
{
this.dialog.setMessage("Listen werden geladen...");
this.dialog.show();
}
#Override
protected Void doInBackground(Void... arg0)
{
try
{
switch(startSynchronize())
{
case 0:
publishProgress(0);
return null;
case 1:
publishProgress(1);
return null;
case 2:
publishProgress(2);
return null;
}
}
catch (IOException e)
{
e.printStackTrace();
}
synchronize();
return null;
}
protected void onProgressUpdate(Integer... type)
{
int typeCase = type[0];
switch(typeCase)
{
case 0:
showDialog(DIALOG_INTERNET_ACCESS);
break;
case 1:
showDialog(DIALOG_CREATE_ACCOUNT);
break;
case 2:
showDialog(DIALOG_ACCOUNTS);
break;
}
}
protected void onPostExecute(final Void unused)
{
if (this.dialog.isShowing())
{
this.dialog.dismiss();
}
}
}
And here my startSynchronize() and synchronize() methods:
private int startSynchronize() throws IOException
{
googleAccountManager = new GoogleAccountManager(RememberMe.this);
Account[] accounts = googleAccountManager.getAccounts();
if(checkAccess.internetAccess() == false)
{
return 0;
}
if(accounts.length == 0)
{
return 1;
}
else
{
if(accounts.length == 1)
{
account = accounts[0];
}
else
{
return 2;
}
}
return -1;
}
private void synchronize()
{
myPrefs = this.getSharedPreferences("myPrefs", MODE_PRIVATE);
String oldToken = myPrefs.getString(MY_TOKEN, "");
if(oldToken.length() > 0)
{
// invalidate old token to be able to receive a new one
googleAccountManager.invalidateAuthToken(oldToken);
}
googleAccountManager.manager.getAuthToken(account, AUTH_TOKEN_TYPE, true, new AccountManagerCallback<Bundle>()
{
public void run(AccountManagerFuture<Bundle> future)
{
try
{
token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
prefsEditor.putString(MY_TOKEN, token);
prefsEditor.commit();
useTasksAPI(token);
}
catch (OperationCanceledException e)
{
//...
}
catch (Exception e)
{
//...
}
}
}, null);
}
In the Optionsmenu i start it like this
new SynchronizeGoogle().execute();
Thanks everybody for your help
If I do not misunderstand your question, you're wrong with getResult() method usage.
When getResult() called by anywhere in your code, AsyncTask does not wait until finish. So you need to do your process in onPostExecute method.
I recommend you this question&answer. I hope, it's gonna help you.

AsyncTask return value

My android app connects to my website to retrieve and upload information so I use an AsyncTask thread.
In one instance, I need my thread to return a true or a false value to my main thread.
Is there a way to get this return value from an AsyncTask execute function?
When I do the following:
Toast.makeText(Locate.this, "Testing : "+locationUpdate.execute(location), Toast.LENGTH_LONG).show();
I just get alot of gibberish.
I think what I need is a means to pause the main thread until the second thread completes. The second thread calls a function in the main thread to set my return value.
So when the second thread completes, the main thread can unpause and access the return value as set by the second thread
If this logic is sound, please offer suggestions ... thanks!
You can use AsyncTask get() method for this. It waits if necessary for the computation to complete, and then retrieves its result:
Toast.makeText(Locate.this, "Testing : " + locationUpdate.execute(location).get(), Toast.LENGTH_LONG).show();
But be sure to not block the main thread for a long period of time, as this will lead to unresponsive UI and ANR.
UPDATE
I missed the point that question was about async web download/upload. Web/network operation should considered as a long one and thus the approach "pause UI thread and wait till download finishes" is always a wrong one. Use usual result publishing approach intstead (e.g.: AsyncTask.onPostExecute, Service + sendBroadcast, libraries like Volley, RoboSpice, DataDroid etc).
Handler is the best way to do this
in onPostExcecute() method simply do
#Override
protected void onPostExecute(Boolean bool) {
super.onPostExecute(bool);
Message msg=new Message();
msg.obj=bool;
mHandler.sendMessage(msg);
}
}
and your message handler will be
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
bool i=(String)msg.obj;
}
};
public class RunWebScript {
String mString;
public RunWebScript(String url){
try {
URL updateURL = new URL(url);
URLConnection conn = updateURL.openConnection();
// now read the items returned...
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while((current = bis.read()) != -1){
baf.append((byte)current);
}
String s = new String(baf.toByteArray());
mString = s;
} catch (Exception e) {
Log.e("ANDRO_ASYNC", "exception in callWebPage",e);
mString = "error";
}
}
public String getVal(){
return mString;
}
}
this is executed as... (showing teh end of a method in teh calling class
asyncWebCall (url1,CONSTANT);
}
private void asyncWebCall(String url,int actionPostExecute){
new WebCall().execute(url,String.format("%d",actionPostExecute));
}
The Async part of the business is ... Note the case statement in onPostExecute this is the key to getting the returned value ito your program again. Note that the call new WebCall().execute(url,String.format("%d",actionPostExecute)); is the last thing done in a thread, no further statements can be executed, control returns through the onPostExecute.
class WebCall extends AsyncTask<String, String, String>{
int chooser = -1;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
try {
chooser = Integer.parseInt(params[1]);
} catch(NumberFormatException nfe) {
Log.d("ANDRO_ASYNC",String.format("asyncReturn() mString numberformatexception = %s",params[1]));
chooser = 0;
}
return(new RunWebScript(params[0])).getVal();
}
protected void onProgressUpdate(String... progress) {
}
#Override
protected void onPostExecute(String gotFromDoInBkgnd) {
Log.d("ANDRO_ASYNC",String.format("chooser = %s",chooser));
switch (chooser){
case CONSTANT:
printStringx(gotFromDoInBkgnd);
asyncWebCall(url2,5);
break;
case 0:
Log.d("ANDRO_ASYNC",String.format("case 0 = %s",gotFromDoInBkgnd));
break;
case 5:
Log.d("ANDRO_ASYNC",String.format("case 5 = %s",gotFromDoInBkgnd));
asyncWebCall(url3,7);
break;
default:
Log.d("ANDRO_ASYNC",String.format("man we got problems = %s",gotFromDoInBkgnd));
break;
}
}
} // end of class
Here is a complete example of the issue of returning values from an async task. It may occur that there are many tasks to be done one after the other asynchronously.
Basics.
1. get a return value from a class.
public class Snippet {
int computVal;
public Snippet(){
computVal = 17*32;
}
public int getVal(){
return computVal;
}
}
this is called as...
int hooray = (new Snippet()).getVal();

Categories

Resources