I have a problem with a progressbar spinner:
ProgressBarSpinner spinner = new ProgressBarSpinner();
spinner.execute(Spin);
Login LoginUser = new Login();
if(LoginUser.LoginUser(UserNameValue.getText().toString(), PasswordValue.getText().toString())) {
MessageBox("Login information", "You've been successfully logged in, press OK to continue.");
Document XMLInfo = null;
Passphrase = PasswordValue.getText().toString();
try {
XMLInfo = XMLfromString(LoginUser.ProfileXML);
XML_ProfileParser(XMLInfo);
TickerString = FillProfileSlider(XMLInfo);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Spin.setVisibility(ProgressBar.GONE);
setContentView(R.layout.profile);
TextView ProfileTicker = (TextView)findViewById(R.id.ProfileTicker);
TextView UserInformation = (TextView)findViewById(R.id.NameInfo);
TextView MoneyLabel = (TextView)findViewById(R.id.MoneyInfo);
UserInformation.setText(ProfileInfo.get("FirstName") + " " + ProfileInfo.get("LastName"));
MoneyLabel.setText(ProfileInfo.get("Money") + " Kr");
if(Integer.parseInt(ProfileInfo.get("Messages")) >= 1) {
ImageView MessageImage = (ImageView)findViewById(R.id.MailImage);
MessageImage.setOnClickListener(ImageListener);
MessageImage.setVisibility(ImageView.VISIBLE);
}
ProfileTicker.setText(Html.fromHtml(TickerString));
}
else {
Spin.setVisibility(ProgressBar.GONE);
MessageBox("Login information", "The submitted login information seems to be invalid.");
}
This gets executed when users click login. Spin is a global progressbar variable. Below is the Async class that is used to handle the spinner.
private class ProgressBarSpinner extends AsyncTask<ProgressBar, Integer, ProgressBar>
{
protected ProgressBar doInBackground(ProgressBar...Spinner) {
return Spinner[0];
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(ProgressBar Spinner) {
Spinner.setVisibility(ProgressBar.VISIBLE);
Spinner.showContextMenu();
}
}
To the problem: If I try to write
Spin.setVisibility(ProgressBar.GONE);
after the logins authorization the spinner does not get displayed at all. But if I remove the ProgressBar.Gone part the spinner is displayed.
But if that part is present is seems that the application "hangs" before it continues (either logging the user in or displaying an error message telling that the username or password is wrong).
What can the problem be?
I know for sure that the login is not done so fast that the spinner does not get time to be displayed before it is set to GONE.
You need to set your spinner to visible before creating your AsyncTask and hide it in onPostExecute, something like:
mySpinner.setVisibility(View.VISIBLE);
myAsyncTask.Execute(); // etc, etc
myAsyncTask:
protected void onPostExecute(ProgressBar Spinner) {
Spinner.setVisibility(View.GONE);
}
Related
I have an activity that list authorized users, and I'm using getIntent() in my activity's onCreate() method to check if the activity should display a pre-filled add user dialog when it loads. Here is my code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sms_auth_manager);
try{ //check if the activity was launched with a prefill intent
Intent intent = getIntent();
int id = (intent.getIntExtra("notification_id",0));
NotificationUtils notificationUtils = new NotificationUtils();
notificationUtils.hideNotification(this,id);
if (intent.getBooleanExtra("isPrefill",false)){
String preFill = intent.getStringExtra("sender");
showAddUserDialog(preFill);
}
}catch (Exception ignore){} //exception swallowed means no dialog
refreshList(); //loads the list of users into the main listview of the activity
}
My problem is that the call to refreshList() is not resulting in the list being refreshed. I tried putting it before the try block as well, and either way it won't work. I tested with the try block commented out though, and that does work, but then I lose the functionality.
Here is the code of the refreshList() method, in case it's necessary:
private void refreshList(){
SharedPreferences sharedPrefs = getSharedPreferences("users",0);
LinearLayout ll = findViewById(R.id.ll);
ll.removeAllViews();
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
);
for (String sender : sharedPrefs.getAll().keySet()) {
CheckBox checkBox = new CheckBox(this);
checkBox.setText(getContactDisplayName(sender));
checkBox.setTag(sender);
try{
checkBox.setChecked(sharedPrefs.getBoolean(sender,false));
}catch (Exception e){
checkBox.setChecked(false);
}
checkBox.setLayoutParams(layoutParams);
checkBox.setOnClickListener(v -> {
try {
sharedPrefs.edit().putBoolean(sender, checkBox.isChecked()).apply();
}catch (Exception e){
Toast.makeText(this, "Preference not updated.\n"+e.getMessage(),
Toast.LENGTH_SHORT).show();
}
});
checkBox.setOnLongClickListener(v -> {
showPopupMenu(v);
return false;
});
ll.addView(checkBox);
}
}
Why does the try block prevent the UI from refreshing, and how can I acheive the functionality I am looking for?
If you intend to run the refreshList method regardless if there is an exception or not you can try using the finally block which would run the code regardless of the exception.
public String newUser = "false";
public double lat = 0.0, lon = 0.0;
I have the following function in my android app (called when a Button is clicked) which starts a thread:
public void SignUpFunction(View view) {
assignValues();
String filledAll = checkIfFilled();
if (filledAll.equals("true")) {
Log.d("LIFECYCLE", "calling thread..");
//my thread
new validateThread().start();
Log.d("After thread start","This log call does not occur");
if (newUser.equals("true")) {
Toast.makeText(this, "Please wait as we obtain your location", Toast.LENGTH_SHORT).show();
getMyLocationFunction();
} else {
return;
}
}
}
validateThread:
class validateThread extends Thread {
public void run() {
Log.d("LIFECYCLE", "validateThread entered...");
try {
newUser = "true";
Log.d("validateThread", "Validated and found new user");
} catch (Exception e) {
Log.d("validateThread", "Exception in validateThread: " + e.getMessage());
}
}
}
The thread runs correctly...but after the last line, it does not go back to its point of start. I don't understand why this is happening because I've used threads before and they all work correctly.
I know I can just give the getMyLocation function inside the thread but I really need it this way.
I've searched for similar questions but none helped.. What am I doing wrong here?
Thanks in advance.
It's a race. SignUpFunction should wait until validateThread decides whether or not to set newUser = "true". Even with the race your code may work sometimes, but that is by accident.
I have this query located in my ParseQueryBuilder object:
public ParseQuery<Event> eventsTypes() {
ParseQuery<Event> query = Event.getQuery();
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_ELSE_NETWORK);
query.setMaxCacheAge(TimeUnit.DAYS.toMillis(1));
query.whereEqualTo(Event.owner, parse.getParseUser());
query.orderByDescending(Event.timesUsed);
return query;
}
I use it to populate a ParseQueryAdapter
and at some point I would like to add an Event and immediately show it:
#OnClick(R.id.add)
public void add(Button button) {
final Event new_type = new Event();
new_type.setOwner(parse.getParseUser());
new_type.setName("atest");
new_type.saveEventually(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
// on successfull save, clear cache
parseQueryBuilder.eventsTypes().clearCachedResult();
// and show newly added object
mAdapter.loadObjects();
Toast.makeText(getActivity(), new_type.getName(), Toast.LENGTH_SHORT).show();
}
}
});
}
I expected clearing the cache would result in a new network query, revealing the newly added item but no matter what I try, it seems it will only show the initially cached result.
Even if I try to restart my app, it shows the result from the first cache.
Ever get those moments where you stare at a piece of code for an hour and still can't come up with an answer? Yeah that's me now.
I'm working on a final project for class and I can't get this one piece of code to work. It is absolutely crucial that it works, or else it defeats the purpose of the program. I even asked my professor for help... and he doesn't know how to help me solve the issue. I posted a similar problem a day ago but I want to re-ask in a different way to see if it helps (Sorry if its a re-post, I have no other source for help :/).
My problem is that I need to access array elements on my MainActivity after its populated inside an AsyncTask class. The array is defined globally but as soon as I try to access it's element or size, it crashes. I need to be able to call this array outside of AsyncTask.
I've searched for hours and tried "returning" the array from AsyncTask but it crashes as well.
Here is my code (I've included comments as to where it crashes):
public class PostsActivity extends Activity {
public static GlobalRates[] gr;
TextView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_posts);
view = (TextView) findViewById(R.id.textView1);
BitRateFetcher br = new BitRateFetcher();
br.execute();
// !!! Line below crashes !!!
Log.i("BitRateFetcher", "Size from onCreate: " + gr.length);
}
private class BitRateFetcher extends AsyncTask<Void, Void, GlobalRates[]> {
private static final String TAG = "BitRateFetcher";
public String BIT_PAY_SERVER = "https://bitpay.com/api/rates";
private ProgressDialog dialog;
GlobalRates[] test;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(PostsActivity.this);
dialog.setMessage("Please Wait... Downloading Information");
dialog.show();
}
#Override
protected GlobalRates[] doInBackground(Void... params) {
try {
// Create an HTTP client
HttpClient client = new DefaultHttpClient();
HttpGet getBitRates = new HttpGet(BIT_PAY_SERVER);
// Perform the request and check the status code
HttpResponse bitRatesResponse = client.execute(getBitRates);
StatusLine bitRatesStatus = bitRatesResponse.getStatusLine();
if (bitRatesStatus.getStatusCode() == 200) {
HttpEntity entity = bitRatesResponse.getEntity();
InputStream content = entity.getContent();
try {
// Read the server response and attempt to parse it as
// JSON
Reader reader = new InputStreamReader(content);
Gson gson = new Gson();
test = gson.fromJson(reader, GlobalRates[].class);
content.close();
entity.consumeContent();
} catch (Exception ex) {
Log.e(TAG, "Failed to parse JSON due to: " + ex);
failedLoadingPosts();
}
} else {
Log.e(TAG, "Server responded with status code: "
+ bitRatesStatus.getStatusCode());
failedLoadingPosts();
}
} catch (Exception ex) {
Log.e(TAG, "Failed to send HTTP POST request due to: " + ex);
failedLoadingPosts();
}
return test;
}
#Override
protected void onPostExecute(GlobalRates[] test) {
Log.i(TAG, "Test Size: " + test.length); // Returns 158
gr = test;
Log.i(TAG, "Gr Size: " + gr.length); // Returns 158
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.posts, menu);
return true;
}
private void failedLoadingPosts() {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(PostsActivity.this,
"Failed to load Posts. Have a look at LogCat.",
Toast.LENGTH_SHORT).show();
}
});
}
}
Here is the error Log:
04-21 20:30:01.954: E/AndroidRuntime(32595): FATAL EXCEPTION: main
04-21 20:30:01.954: E/AndroidRuntime(32595): Process: com.example.postsactivity, PID: 32595
04-21 20:30:01.954: E/AndroidRuntime(32595): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.postsactivity/com.example.postsactivity.PostsActivity}: java.lang.NullPointerException
My class partner and I are unsure as to how we can call the global array (gr) properly. I understand that onCreate is not going to wait for AsyncTask to finish. What can we do to get this to work? Thanks for the help and understanding. You guys can prove more useful than my professor...
the problem is that you are accessing array of globalrates before it was initialized in your postExecute(). There are a lot of way to do this one of which is creating an interface or creating callbacks that waits for globalrate to be initialized after ur background thread is done.
Create a Interface
public interface SampleInterface {
void globalResultBackground(GlobalRates[] gr);
}
implements the interface to ur activity
public class PostsActivity extends Activity implements SampleInterface
pass the interface to your asynctask
//in the activity
BitRateFetcher br = new BitRateFetcher(this);
br.execute();
//in the asynctask class
SampleInterface si;
public BitRateFetcher(SampleInterface si){
this.si = si;
}
pass the result of the background thread to ur interface method
#Override
protected void onPostExecute(GlobalRates[] test) {
si.globalResultBackground(test);
Log.i(TAG, "Test Size: " + test.length); // Returns 158
gr = test;
Log.i(TAG, "Gr Size: " + gr.length); // Returns 158
if (dialog.isShowing()) {
dialog.dismiss();
}
}
in the activity where the you implemented the interface and generated the globalResultBackground method
#Override
public void globalResultBackground(GlobalRates[] gr) {
//you can freely access the globalrates here because this is called when the
//background thread is done
Log.i("BitRateFetcher", "Size from onCreate: " + gr.length);
}
Pass in your activity to the AsyncTask and directly access its gr in your onPostExecute
Sample code:
private class BitRateFetcher extends AsyncTask {
PostsActivity activity;
...
public BitRateFetcher(PostsActivity activity){
this.activity= activity;
}
...
#Override
protected void onPostExecute(GlobalRates[] test) {
activity.gr = ...
}
}
In PostsActivity,
BitRateFetcher br = new BitRateFetcher(this);
Take care to attach and reAttach the activity to handle scenarios such as device rotations.
EDIT: Just noticed you've got a static, so you don't even need to pass in the activity. The same principle applies though.
GlobalRates[] gr is public and static, so you dont really new GlobalRates[] test
simply replace every instance of test with gr:
test = gson.fromJson(reader, GlobalRates[].class);
to
gr = gson.fromJson(reader, GlobalRates[].class);
if you need to access gr in Oncreate then move that logic to postExecute
Log.i("BitRateFetcher", "Size from onCreate: " + gr.length);
I am trying to show dialog boxes with contents from the database .The fetched data from the database may contain more than 1 data.So I have to show dialog in for loop.But the dialog shows only for the first row in the database.Here is the code
cursor = sqldb.query(Database_Handler.dbdectab, null,"((" + Database_Handler.gendtime + "<='" + after_1hr + "' and " + Database_Handler.gendtime + ">='" + before_1hr + "') and ("
+ Database_Handler.calused + "='Gregorian' or " + Database_Handler.calused + "='both')) ", null, null, null, null);
notif_count = cursor.getCount();
//dec_name_ctr_builder = new StringBuilder("");
if(notif_count>0)
{
dialog1 = new Dialog(this);
cursor.moveToFirst();
do
{
dec_name =cursor.getString(cursor.getColumnIndex(Database_Handler.decname));
dialog1.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog1.setContentView(R.layout.custom_dialog_alert);
TextView tv_alert = (TextView)dialog1.findViewById(R.id.txt_alert);
tv_alert.setText( dec_name );
Button yes = (Button) dialog1.findViewById(R.id.btn_yes);
Button no = (Button) dialog1.findViewById(R.id.btn_no);
yes.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(donateurl));
startActivity(intent);
dialog1.dismiss();
cursor.close();
sqldb.close();
finish();
}
});
no.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
dialog1.dismiss();
cursor.close();
sqldb.close();
finish();
}
});
dialog1.show();
}while(cursor.moveToNext());
Android dialog boxes are not modal (which is to say, they don't block the background processes).Hence your work is done asycnhronuosly and according to :
Romain guy
We've designed Android to prevent developers from writing synchronous dialogs so you don't really have much of a choice.
SO you can not block the while loop execution in between using Dialog.
Karan_Rana is right. The simplest solution for your answer would be storing the results somewhere else and displaying a new dialog each time some data is left and user clicks on a previous dialogs button.
I know this is a bit late, but I had a similar problem once. I used recursion to loop a dialog box. My situation was unique as I needed to detect an internet connection during app startup. So, this approach may not work for you. But I was able to implement the solution without for loops and blocking the main UI thread. Because I was on a splash screen, there was no other UI I needed to contend so I would simple call the dialog box again until the user chooses to "Quit".
I had a splash screen that would only continue to the landing activity of the app if a network connection was detected.
Sample code below to demonstrate the concept. Note that there are custom methods, but you should get the idea to call the prompt again from within onClick method.
protected void onCreate(Bundle savedInstanceState) {
if (isNetworkAvailable()) {
launchApp();
} else {
retryPrompt();
}
}
private void retryPrompt() {
if (isNetworkAvailable()) {
launchApp();
} else {
final ConfirmDialog dialog = new ConfirmDialog.CustomAlertBuilder(this,
"Internet Connection",
"Internet Connection not detected. Please check your connection.",
"Retry").
setNegBtnLabel("Quit").
setCustomCallback(new CustomDialogCallback() {
#Override
public void onClickPositiveBtn(DialogInterface dialogInterface, int which) {
// go around again.
retryPrompt(); // <<== Call method recursively
}
#Override
public void onClickNegativeBtn(DialogInterface dialogInterface, int which) {
// abort app.
finish();
}
}).build();
dialog.show();
}
}