I'm new to asking questions here so any advice about that will be appreciated...but to my problem:enter code here
I am Trying To show Process Dialague While Waiting for Data From Server..I am Using Retrofit Call For Get Data From Server And Using MVP Pattern In Our Project..
But Showing Black Screen While Call Goes To Server.. And Load Content Directly After Gettting Response
I Am Stuck This Point From Few Days..
public class ReceiptRegisterActivity extends AppCompatActivity implements ReceiptRegisterPresenter.ReceiptRegisterPresenterListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_receipt_register);
progressBar = new ProgressDialog(ReceiptRegisterActivity.this);
progressBar.setCancelable(true);
progressBar.setMessage("Fetching Data...");
progressBar.setProgress(20);
progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressBar.show();
progressBarStatus = 0;
spinner = (SearchableSpinner)findViewById(R.id.spinner);
editsearch = (android.widget.SearchView) findViewById(R.id.search);
editsearch.setOnQueryTextListener(this);
expandButton =(Button)findViewById(R.id.expandButton);
byDate =(Button)findViewById(R.id.byDate);
byCustomer=(Button)findViewById(R.id.byCustomer);
byDate.setFocusable(false);
allEventLIstener();
dbHelperObj=new DBHelper(this);
try{
dbHelperObj.createDB();
}catch (Exception e){
throw new Error(e);
}
try{
dbHelperObj.openDataBase();
}catch (SQLiteException e){
e.printStackTrace();
}
//srActivity = this;
// progressBar = new ProgressBar(this);
// progressBar.setVisibility(View.VISIBLE);
receptRegisterPresenterObj = new ReceiptRegisterPresenter(this,this);
receptRegisterPresenterObj.getReceiptRegisterData();
}
public void receiptRegisterDataReady(Object obj) {
/// Getting Response In This Block Doing Some Manupilation And Dismiss progressBar...
progressBar.dismiss();
}`
Thanks for any help
You are doing too much work in the OnCreate main Thread. This is why it freezes your Android Application.
Do your Progress UI in the Main thread like so:
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_receipt_register);
progressBar = new ProgressDialog(this, "title", "loading");
heavywork();
}
public void heavywork()
{
//start a new thread to process job
new Thread(new Runnable() {
#Override
public void run() {
// Do all the Data From Server code here !
}
}).start();
}
This might help you:
ProgressDialog in a separate thread
Related
i'm developing an android App.
The user registration process calls a service that sends an email so it takes several seconds, like 5 or 6 seconds,that's why I execute that task within a thread. The problem is, the Dialog is never dismissing. It stays rolling and the user can do nothing. Here's my code:
try
{
final ProgressDialog progDailog = new ProgressDialog(ActividadAltaUsuario.this);
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
URL url = new URL("slowWS");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
InputStream in = new BufferedInputStream(conn.getInputStream());
String response = IOUtils.toString(in, "UTF-8");
final JSONObject jsonPrincipal = new JSONObject(response);
Boolean success = jsonPrincipal.get("status").toString() == "true";
if (success)
{
ActividadAltaUsuario.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progDailog.show(ActividadAltaUsuario.this, "Sendind email");
}
});
final String idUsuario = jsonPrincipal.get("idUsuario").toString();
URL url2 = new URL("anotherSlowWS");
HttpURLConnection conn2 = (HttpURLConnection) url2.openConnection();
conn2.setRequestMethod("POST");
InputStream in2 = new BufferedInputStream(conn2.getInputStream());
String response2 = IOUtils.toString(in2, "UTF-8");
JSONObject jsonRtaMail = new JSONObject(response2);
//finish();
}
else
{
//finish();
showToast(jsonPrincipal.get("message").toString());
}
ActividadAltaUsuario.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progDailog.dismiss();
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
}).start();
}
catch(Exception e)
{
Log.e("log_tag", "Error in http connection" + e.toString());
}
Can anybody help me?
Thanks!
AsyncTask would be a better approach instead of thread, Replace your network call from thread to use AsyncTask. You can use something like this
private class LongOperation extends AsyncTask<Void, Void, Void> {
#Override
protected String doInBackground(Void... params) {
//Main stuff that needs to be done in background
}
#Override
protected void onPostExecute(Void result) {
//Post Execution this method will be called, handle result accordingly
//You can dismiss your dialog here
}
#Override
protected void onPreExecute() {
//Do initialization relative stuff here
// Initialize your dialog here.
}
}
As both onPostExecute() and onPreExecute() work on main thread you can show and dismiss your dialog in this methods.
The UI controls have to be accessed only from the UI thread.
Usually I do this in class that extends AsyncTask
Something like:
public class MyTask extends AsyncTask {
protected void onPreExecute() {
//create and display your alert here
progDialog = ProgressDialog.show(MyActivity.this,"Please wait...", "Logging ...", true);
}
protected Void doInBackground(Void... unused) {
// here is the thread's work ( what is on your method run()
...
// if we want to show some progress in UI, then call
publishProgress(item)
}
protected void onProgressUpdate(Item... item) {
// theoretically you can show the progress here
}
protected void onPostExecute(Void unused) {
//dismiss dialog here where the thread has finished his work
progDialog.dismiss();
}
}
LE:
More detalis about AsyncTask https://developer.android.com/reference/android/os/AsyncTask
check especially the Protected Methods
Could you help me to change piece of code to show progresDialog or some information during database creation. I have tried to do this with Thread with no success. When I put most of code to thread I get error, when only db.createDataBase() "text" is set before database is created.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myCalendar = new MyCalendar();
menu = (TextView) findViewById(R.id.poleMenu);
text = (TextView) findViewById(R.id.glownePoleTekstowe);
menu.setText(kalendarz.setCurrentDateOnView());
value = menu.getText().toString();
db = new DatabaseHandler(this);
try {
// separate class to load database
// MOST IMPORTANT
db.createDataBase();
} catch (IOException ioe) {
throw new Error("nie można utworzyć bazy danych");
}
dane = db.getDataFromDate(value);
db.close();
try {
log = dane.getTekst();
}catch(Exception e) {System.out.println(e);}
text.setText(log);
}
Update, with thread and handler:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
kalendarz = new Kalendarz();
menu = (TextView) findViewById(R.id.poleMenu);
text = (TextView) findViewById(R.id.glownePoleTekstowe);
menu.setText(kalendarz.setCurrentDateOnView());
value = menu.getText().toString();
db = new DatabaseHandler(this);
// thread
ladujDane();
dane = db.getDaneFromDate(value);
db.close();
try {
log = dane.getTekst();
}catch(Exception e) {System.out.println(e);}
text.setText(log);
}
//------------------------------------------
public void ladujDane() {
mLoadDBHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
progressDialog.dismiss();
}
};
progressDialog = ProgressDialog.show(
this,
"Ładowanie danych", "Proszę chwilkę poczekać",
true,
false);
Thread t = new Thread(new LoadDBThread());
t.start();
}
//----------------------------------------
private class LoadDBThread implements Runnable
{
public void run()
{
try {
db.createDataBase();
} catch (IOException ioe) {
throw new Error("nie można utworzyć bazy danych");
}
mLoadDBHandler.sendEmptyMessage(0);
}
}
Your problem is that you are trying to do UI operations on another thread than the main thread.
You could use a handler for that. First declare a handler:
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do UI stuff
}
};
Then from your thread that creates DB you call: handler.sendEmptyMessage(0);
Just use AsyncTask you can safetly mage progress bar from it's onProgress.
You can't change UI elements from thread other than UI thread, on the other hand you can't do long lasting operations in UI thread. AsyncTask is your answer.
In my app I performing loading data from web and then displaying it to user. Before loading data app shows progress dialog. I have problem if user locks phone in the middle of loading operation, or server is overloaded and can't respond in time my application freezes, because it doesn't dismiss progress dialog, or in some cases it crashes because lack on needed data.
If some error happened while loading data I want show some dialog to user to let him know about error and ask him should application repeat last request. I tried to use AlertDialog for it, but I haven't succeed.
Here is code of one activity (There is no progress dialog here, but it demonstrates how I loading data):
#EActivity(R.layout.layout_splash)
#RoboGuice
public class SplashScreenActivity extends Activity {
#Inject
private AvtopoiskParserImpl parser;
#Bean
BrandsAndRegionsHolder brandsAndRegionsHolder;
#ViewById(R.id.splash_progress)
ProgressBar progressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
}
#Background
protected void loadData() {
publishProgress(10);
LinkedHashMap<String, Integer> brands = null;
try {
brands = parser.getBrands();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(50);
LinkedHashMap<String, Integer> regions = null;
try {
regions = parser.getRegions();
} catch (IOException e) {
Log.e(e.getMessage());
}
publishProgress(70);
populateData(brands, regions);
}
#UiThread
protected void populateData(LinkedHashMap<String, Integer> brands, LinkedHashMap<String, Integer> regions) {
Intent intent = new Intent(SplashScreenActivity.this, SearchActivity_.class);
brandsAndRegionsHolder.brandsMap = brands;
brandsAndRegionsHolder.regionsMap = regions;
publishProgress(100);
startActivity(intent);
finish();
}
#UiThread
void publishProgress(int progress) {
progressBar.setProgress(progress);
}
}
parser.getBrands() and parser.getRegions() are loading data from the web.
I want to do something like this:
boolean repeatRequest = true;
while (repeatRequest) {
try {
brands = parser.getBrands();
repeatRequest = false;
} catch (IOException e) {
Log.e(e.getMessage());
repeatRequest = showErrorDialog();
}
}
But I didn't manage to do so because this code executes in background thread, but dialog should be shown in UI thread.
I believe that it should be standard approach of doing so, but didn't manage to find it.
Any ides how can I implement this?
The best way is to use AsyncTask.
private class LoadDataTask extends AsyncTask<Void, Integer, Object> {
private ProgressDialog mProgress;
protected Object doInBackground(Void... params) {
// This method runs in background
Object result = null;
try {
result = parser.parse();
} catch (Exception e) {
result = e.getMessage();
}
return result;
}
protected void onProgressUpdate(Integer... progress) {
// This method runs in UI thread
mProgress.setProgress(progress[0]);
}
protected void onPreExecute() {
// This method runs in UI thread
mProgress = new ProgressDialog(context);
mProgress.show();
}
protected void onPostExecute(Object result) {
// This method runs in UI thread
mProgress.dismiss();
if (result instance of String) {
// Here you can launch AlertDialog with error message and proposal to retry
showErrorDialog((String) result);
} else {
populateData(result);
}
}
}
So my code seems to run just fine until it hits this line
adapter.notifyDataSetChanged();
The error that pops up in the logcat is CalledFromWrongThreadException. The debug also shows the handler being run in the Background thread. How do I get the handler to bind to the main thread, and not the background one? I thought I just had to create the handler in the main thread, but I guess I am wrong, quite possible I am new to andriod. How do I fix this?
//Imports are included
public class DirectoryActivity extends ListActivity {
private ProgressDialog ProgressDialog = null;
private ArrayList<DirectoryListing> listing = null;
private DirectoryAdapter adapter;
private Runnable viewOrders;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.directory);
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (listing != null && listing.size() > 0) {
adapter.notifyDataSetChanged();
for (int i = 0; i < listing.size(); i++)
adapter.add(listing.get(i));
Log.e("log_tag", "\nStill running\n");
}
ProgressDialog.dismiss();
adapter.notifyDataSetChanged();
}
};
listing = new ArrayList<DirectoryListing>();
adapter = new DirectoryAdapter(this, R.layout.rows, listing);
setListAdapter(adapter);
ProgressDialog = ProgressDialog.show(DirectoryActivity.this, "Please wait...", "Retrieving data ...", true);
viewOrders = new Runnable() {
#Override
public void run() {
listing = PreparePage.getArrayList();
handler.handleMessage(null);
}
};
Thread thread = new Thread(null, viewOrders, "Background");
thread.start();
}
private static class PreparePage {
protected static ArrayList<DirectoryListing> getArrayList() {
ArrayList<DirectoryListing> listings = new ArrayList<DirectoryListing>();
JSONObject information = GetPageData.getJSONFromURL(url);
Iterator key = information.keys();
while (key.hasNext()) {
String id = (String) key.next();
JSONObject info = null;
try {
info = information.getJSONObject(id);
} catch (JSONException e) {
e.printStackTrace();
}
String name = "", title = "", photo = "";
try {
name = info.get("firstName") + " " + info.get("lastName");
title = info.getJSONObject("position").getString("name");
photo = info.optString("photoPath", "none");
} catch (JSONException e) {
e.printStackTrace();
}
listings.add(new DirectoryListing(name, title, photo));
}
return listings;
}
}
}
Try calling handler.sendEmptyMessage(0); instead of handler.handleMessage(null);
I don't know why this would cause the errors you are seeing, but this is how I have it set up when I use handler and thread instead of AsyncTask. And I have have never seen that error doing it this way.
#Nguyen is right though AsyncTask is the preferred way to handle these types of things now. And it actually makes it much easier to do.
AsyncTask docs
AsyncTask Example
In my experience, you should create your own class that extends AsyncTask class to do something at background. This is a simpler and more effectively than using thread + handler.
Am building application for company events , i got the events from database and fill it in the adapter for ListView, i need to display ProgressDialog during the retrieving data from database , this is my code
`
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.listlayout);
adapter = new MyArrayAdapter(this);
listView = (ListView) findViewById(R.id.list);
progressDialog = ProgressDialog.show(this, "Please wait....",
"Here your message");
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(2000);
//this is call the webservice to got filled adapter
adapter = new EventWebservice().getAdapter(this);
listView.setAdapter(adapter);
progressDialog.dismiss();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
adapter.notifyDataSetChanged();
adapter.notifyDataSetInvalidated();
`
What i say is make use of AsyncTask().. show ypur dialog in preExecute() and dismiss in postexecute();.. and the data fetching code u put in backGround task.. i mean like below.. this is a sample code i ve used in my project
class Backgrountask extends AsyncTask
{
#Override
protected void onPostExecute(Object result) {
dialog.dismiss();
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(Mwfa.this, "",
"Loading. Please wait...", true);
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... arg0) {
//your code
}
return null;
}
}
}
I would us a AsyncTask. Here is the structure of what should happen.
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(context, "", "Loading. Please wait...",
true);
}
#Override
protected EventWebservice doInBackground(Void... params) {
//call the webservice and return it
}
#Override
protected void onPostExecute(EventWebservice webservice) {
adapter = webservice.getAdapter(this);;
listView.setAdapter(adapter);
dialog.dismiss();
}
You need to read on unsynchronized ws calls and how to fill up data in a listview dynamically. Here is the code snippet below that works and will ensure that no mattter how much time the WS CAll takes there is no interruption on the GUI and the flow is smooth:
String wsResponse[];
public void sampleFunction()
{
progressDialog = ProgressDialog.show(this, "", "Getting backup list...");
new Thread() {
public void run() {
try {
//do the ws call and store the ws response in a string array
wsResponse=wsCall();
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
messageHandler.sendEmptyMessage(0);
// messageHandler.sendEmptyMessage(0);
}
}.start();
}
}
//inside the handler set the string array retrieved from the WS in sampleFunction to the adapter
private Handler messageHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
//here write the code to assign the string array to the adapter
}
};
Move your
listView.setAdapter(adapter);
progressDialog.dismiss();
adapter.notifyDataSetChanged();
into a Handler and call the method sendEmptyMessage() of Handler from the Thread.run() after you got the Adapter.
Consider this post for more information
Edit:
Your code should be look like something this.
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(2000);
//this is call the webservice to got filled adapter
adapter = new EventWebservice().getAdapter(this);
handler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Where your Handler will update the list. But devA's answer is best way to do such jobs.