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.
Related
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
I'm trying to do a simple HTTP request in Android. It has to be in separate theread. But how can I operate on the view controls inside the thread?
Here's what I have now:
public void saveData(final View v)
{
Button btn = (Button) v.findViewById(R.id.button);
btn.setText("Saving...");
new Thread() {
public void run()
{
HttpURLConnection connection = null;
try {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
final String fResponse = IOUtils.toString(inputStream);
}
catch (MalformedURLException ex) {
Log.e("aaa", "Invalid URL", ex);
}
catch (IOException ex) {
Log.e("aaa", "IO Exception", ex);
}
finally {
if (connection != null) {
connection.disconnect();
}
}
// How can I access v and btn here?
// btn.getText("Saved, thanks.");
// btn.setText("Saved, thanks.");
}
}.start();
}
To elaborate what I'm trying to achieve:
I have a text box and a button. Once the button is clicked, I want to get the text from text box, use in the URL, wich returns a value, then update the button text with this value.
Here's an example on how you could do it.
public class YourClass extends Activity {
private Button myButton;
//create an handler
private final Handler myHandler = new Handler();
final Runnable updateRunnable = new Runnable() {
public void run() {
//call the activity method that updates the UI
updateUI();
}
};
private void updateUI()
{
// ... update the UI
}
private void doSomeHardWork()
{
//update the UI using the handler and the runnable
myHandler.post(updateRunnable);
}
private OnClickListener buttonListener = new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
doSomeHardWork();
}).start();
}
};
}
As you can see, you need to update the UI with yet another Runnable object. This is one way of doing it.
Another option is via the runOnUiThread function
runOnUiThread(new Runnable()
{
#Override
public void run() {
updateActivity();
}
});
If you try to access your Views directly from another thread like that, you will get an exception because all UI operations must be performed on the main thread.
One method that the Android SDK provides for performing background tasks that need to update the UI is the AsyncTask.
The onPostExecute() method of an AsyncTask is called after doInBackground() returns, and is run on the UI thread.
Your AsyncTask might look something like this:
public class MyBackgroundTask extends AsyncTask<URL, Void, String> {
protected String doInBackground(URL... urls) {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
return IOUtils.toString(inputStream);
}
protected void onPostExecute(String result) {
// Call back to your Activity with the result here
}
}
I would like to update spinner object after I get a google calendar name in a different thread. When I execute this, it crashes. I am not sure if I need to make it work with a different approach or if there is something wrong with it.
private void updateGoogleCalendar() {
try {
Thread.sleep(4000);
List<String> list = new ArrayList<String>();
list.add("Sample Calendar");
updatedCalendarNames = list.toArray(new String[0]);
progressBar.dismiss();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void initializeWidgets() {
final Spinner spinner = (Spinner) layout.findViewById(R.id.googleCalendarSelection);
final Button refreshCalendarBtn = (Button) layout.findViewById(R.id.refreshCalendarBtn);
refreshCalendarBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
progressBar = ProgressDialog.show(getContext(), "", "Loading...");
new Thread(new Runnable() {
#Override
public void run() {
updateGoogleCalendar();
final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(), android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
while (updatedCalendarNames == null) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (String calendarName : updatedCalendarNames) {
CharSequence charSequence = calendarName + "";
adapter.add(charSequence);
}
}
}).start();
}
});
}
you need to add your ui update code into event thread only, and to notify UI/Event Thread you need to implement Handler or AsyncTask, for example you can update by handler as follows:
public void initializeWidgets() {
final Spinner spinner = (Spinner) layout.findViewById(R.id.googleCalendarSelection);
final Button refreshCalendarBtn = (Button) layout.findViewById(R.id.refreshCalendarBtn);
refreshCalendarBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
progressBar = ProgressDialog.show(getContext(), "", "Loading...");
new Thread(new Runnable() {
#Override
public void run() {
updateGoogleCalendar();
final ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(), android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
while (updatedCalendarNames == null) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (String calendarName : updatedCalendarNames) {
Message msg=handler.obtainMessage();
msg.obj = calendarName + "";
handler.sendMessage(msg);
}
}
}).start();
}
});
}
Handler handler=new Handler()
{
public void handleMessage(Message msg)
{
String str=(String)msg.obj;
adapter.add(charSequence);
}
};
You don't say where it crashes or how, but I imagine it might be due to you trying to update the UI from a non-UI thread. Take a look at the AsyncTask (see here) for information.
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.
I never got this working in a straightforward manner. Sorry if I'm being a little vague. I'll try to elaborate on what I'm trying to do. I am trying to build a listview that grabs its data from a webservice. Once I initialize a listview, I want to keep polling the webserver periodically and update the contents of the listview. For this I am doing something like this:
public class SampleAutoUpdateList extends Activity {
//Autoupdate handler
private Handler handler = new Handler();
private Runnable updater = new Runnable() {
public void run() {
/*
* Update the list
*/
try {
Log.i("UPDATE", "Handler called");
searchAdapter = getFeed(URL);
searchAdapter.notifyDataSetChanged();
handler.postDelayed(this, Configuration.REFRESH_INTERVAL);
} catch(Exception e) {
Log.e("UPDATE ERROR", e.getMessage());
}
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.linearmode);
this.context = this;
searchAdapter = getFeed(URL);
LinearLayout l2 = (LinearLayout) findViewById(R.id.secondaryLayout);
ListView list = new ListView(context);
l2.addView(list);
// display UI
UpdateDisplay(list);
updater.run();
}
private SearchAdapter getFeed(String URL) {
try
{
SearchHandler handler = new SearchHandler();
URL url = new URL(URL);
String data = convertStreamToString(url.openStream());
data = data.substring(data.indexOf('['), data.length()-1);
handler.parseJSON(data);
return handler.getFeed();
}
catch (Exception ee)
{
// if we have a problem, simply return null
Log.e("getFeed", ee.getMessage());
return null;
}
}
private void UpdateDisplay(View searchView) {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
searchList = (ListView) searchView;
myProgressDialog = ProgressDialog.show(this,
"Please wait...", "Loading search....", true);
new Thread() {
public void run() {
try{
Thread.sleep(2000);
} catch (Exception e) { }
runOnUiThread(new Runnable() {
#Override
public void run() {
if (searchAdapter == null)
{
Log.e("ERROR", "No Feed Available");
return;
}
searchAdapter.setContext(context);
searchList.setAdapter(searchAdapter);
searchList.setSelection(0);
}
});
// Dismiss the Dialog
myProgressDialog.dismiss();
}
}.start();
}
}
And the SearchHandler class is simple:
public class SearchHandler extends DefaultHandler {
SearchAdapter _adapter;
SearchItem _item;
public SearchHandler()
{
}
public SearchAdapter getFeed()
{
return _adapter;
}
public void parseJSON(String data) {
// TODO Auto-generated method stub
_adapter = new SearchAdapter();
JSONArray parseArray;
try {
parseArray = new JSONArray(data);
for (int i=0; i < parseArray.length(); i++) {
SearchItem item = new SearchItem();
JSONObject jsonUser = parseArray.getJSONObject(i);
item.set_from(jsonUser.getString ("from"));
item.set_msg(jsonUser.getString("msg"));
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
No matter what I do, the handler gets called and the new items are fetched, but the list is never refreshed... Any ideas on what could be going wrong?
Well, it is a little bit difficult to follow your code, since you only have a fragment of it, and few of the really relevant bits. For example, based on your available code, your list should be forever empty, since you never associate the searchAdapter with a ListView...at least in the code you have shown.
That being said, the following lines seem particularly odd:
searchAdapter = getFeed(URL);
searchAdapter.notifyDataSetChanged();
I am going to assume that getFeed() (not shown) creates a new ListAdapter of some sort. If getFeed() is creating a new ListAdapter, there is no need to call notifyDataSetChanged() on it, as its data set hasn't changed -- it's brand new. Moreover, unless you are associating this new ListAdapter to your ListView, the new ListAdapter will have no effect.
If I'm barking up the wrong tree, consider adding lines to your sample showing the implementation of getFeed() and where you are using searchAdapter.