In my Main Activity, I have a Thread that is doing alot of stuff, including adding some records to a database. In my second activity, which inherit from the Main Activity, I want to do a query to my database. But I need to check if the first thread in the Main Activity is finished, what I've done so far is:
public class History extends Main {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!(MainThread.isAlive())) {
getFromDatabase();
}
}
}
This is my getFromDatabase() method
pd = ProgressDialog.show(this, "Please Wait",
"Getting cases from database", false);
Thread t = new Thread(this);
t.start();
which will call this run method:
#Override
public void run() {
ArrayList<Case> c = db1.getAllCases();
Message msg = handler.obtainMessage();
msg.obj = c;
handler.sendMessage(msg);
}
private Handler handler = new Handler() {
#SuppressWarnings("unchecked")
#Override
public void handleMessage(Message m) {
pd.dismiss();
list = (ArrayList<Case>) m.obj;
tempList = getCaseNumberToTempList(list);
tempCaseList = createTempList(list);
lv.setAdapter(new CustomAdapter(History.this, list));
lv.setTextFilterEnabled(true);
}
};
But if I do so, the following line of code will crash my application, it will give a NullPointerException:
if(!(MainThread.isAlive())) {
getFromDatabase();
}
How can I be sure that that the first thread is finished with all the work before I query the database from my history activity?
You can make the Thread in the getFromDatabase() method a static class level variable, write a static get method for it in your Activity, and check for isAlive() in your child Activity.
How about simply using a semaphore variable that you modify from the thread once it has reached a certain state?
Related
I try to close a ProgressDialog via Callback from Thread to fragment, but I don't know which reference I need to pass.
Some where in my Fragment I do the following:
c_thread_connectToDevice = new c_Thread_ConnectToDevice(UserSelectedDevice,
sFinalDonglePassword, getActivity());
if(UserSelectedDevice != null){
c_thread_connectToDevice.start();
mProgessDialog.setTitle(R.string.ProgressDialog_Fragmentsetpassword_Title);
mProgessDialog.setMessage(getResources().getString(R.string.ProgressDialog_Fragmentsetpassword_Message));
mProgessDialog.setIndeterminate(true);
mProgessDialog.show();
The Callback is:
public void dismissProgressDialog(){
mProgessDialog.dismiss();
if(!c_thread_connectToDevice.isbConnectionState()){
tv_Fragmentsetpassword_userhint.setTextColor(getResources().getColor(R.color.Mercedes_RED, null));
tv_Fragmentsetpassword_userhint.setText(R.string.tv_Fragmentsetpassword_ConnectionFailed);
}else {
tv_Fragmentsetpassword_userhint.setText(R.string.tv_Fragmentsetpassword_ConnectionSucces);
tv_Fragmentsetpassword_userhint.setTextColor(getResources().getColor(R.color.Mercedes_GREEN, null));
}
}
In my Thread the I use the following Code:
private WeakReference<Activity> weakReference;
...
dismissProgressDialog();
...
private void dismissProgressDialog(){
Activity activity = weakReference.get();
activity.dismissProgressDialog();
}
I know this could not work. But what is the right thing to pass?
What #Zach Bublil told me, brought me to this solution.
private Handler handler = new Handler(Looper.getMainLooper());
c_thread_connectToDevice = new c_Thread_ConnectToDevice(UserSelectedDevice, sFinalDonglePassword, c_Fragment_RoutineStartConnection_setpassword.this);
if(UserSelectedDevice != null){
c_thread_connectToDevice.start();
mProgessDialog = new ProgressDialog(getContext());
mProgessDialog.setTitle(R.string.ProgressDialog_Fragmentsetpassword_Title);
mProgessDialog.setMessage(getResources().getString(R.string.ProgressDialog_Fragmentsetpassword_Message));
mProgessDialog.setIndeterminate(true);
mProgessDialog.show();
CallBack
public void dismissProgressDialog(){
mProgessDialog.dismiss();
handler.post(new Runnable() {
#Override
public void run() {
if(!c_thread_connectToDevice.isbConnectionState()){
tv_Fragmentsetpassword_userhint.setTextColor(getResources().getColor(R.color.Mercedes_RED, null));
tv_Fragmentsetpassword_userhint.setText(R.string.tv_Fragmentsetpassword_ConnectionFailed);
}else {
tv_Fragmentsetpassword_userhint.setText(R.string.tv_Fragmentsetpassword_ConnectionSucces);
tv_Fragmentsetpassword_userhint.setTextColor(getResources().getColor(R.color.Mercedes_GREEN, null));
}
}
});
InsideFragment
private c_Thread_ConnectedToBluetoothDevice c_thread_connectedToBluetoothDevice;
public c_Thread_ConnectToDevice(BluetoothDevice device, String sFinalDonglePassword, c_Fragment_RoutineStartConnection_setpassword reference) {
this.mBluetoothDevice = device;
this.sFinalDonglePassword =sFinalDonglePassword;
this.reference = reference;
}
...
dismissProgressDialog();
...
private void dismissProgressDialog(){
reference.dismissProgressDialog();
}
What is difficult for me to understand is, why I need to run the callback Text editions on mainthread. If I don't do that there is an exception to "Only the original thread creating the view..." but this is maybe caused by
tools:context=".c_RoutineStartConnection"
which I used in the Fragment layout for better usability.
Currently I have a button that loads an activity.
That activity has a ListView in it that for whatever reason takes a fairly long time to load(not waiting for data, the data is already in memory). The problem is that while it's rendering the list, the UI is waiting where the button was clicked, and doesn't change screen until the list has fully loaded.
What I'd like, is to only display the list once the activity is loaded, so at least something happens as soon as they press the button(responsive UI is important).
Currently, my hack around solution to this, is to spawn a thread, wait for 50 milliseconds, and then set the adapter for my list(using runOnUiThread). Of course, if the activity takes longer than 50ms to load on some phones, then it'll have to load the entire list to load the activity again.
Current relevant code:
#Override
public void onPostResume() {
super.onPostResume();
new Thread(new Runnable() {
#Override
public void run() {
final AdapterData data = getData();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
myAdapter = new MyAdapter(MyActivity.this, data);
lvMyList.setAdapter(myAdapter);
}
});
}
}).start();
}
I just changed variable names in the code, but that's not relevant. This is just so you can see my general solution.
I feel like there should be some kind of callback that's called when the activity finishes creating. I thought that onPostResume waited for the activity to finish loading, but that did not work. It still hung.
you can use IdleHandler
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.xxx);
final AdapterData data = getData();
IdleHandler handler = new IdleHandler() {
#Override
public boolean queueIdle() {
myAdapter = new MyAdapter(MyActivity.this, data);
lvMyList.setAdapter(myAdapter);
return false;
}
};
Looper.myQueue().addIdleHandler(handler);
}
I am having a progress dialog for a process. But i am taking a null pointer exception in my thread. But, when i remove the progress dialog. I am no longer taking an exception.
My code is as this
public class PlayedActivity extends ListActivity {
private PullToRefreshListView listView;
final Context context = this;
public Handler handler;
Runnable sendNumbers2;
List<On> playedOn;
DatabaseHandlerOn db;
private ProgressDialog m_ProgressDialog;
private ArrayList<On> m_results = null;
private PlayedOnAdapter m_adapter;
#SuppressLint({ "HandlerLeak", "HandlerLeak" })
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_playedonnumara);
db = new DatabaseHandlerOnNumara(getApplicationContext());
m_results = new ArrayList<OnNumara>();
this.m_adapter = new PlayedOnNumaraAdapter(this, R.layout.playedrowon, m_results);
this.setListAdapter(this.m_adapter);
sendNumbers2 = new Runnable() {
#Override
public void run() {
playedOn = db.getAllContacts();
for (On on : playedOn) {
m_results.add(on);
}
Collections.reverse(m_results);
//m_ProgressDialog.dismiss();
handler.sendEmptyMessage(0);
}
};
Thread thread = new Thread(sendNumbers2,"sendNumbers2");
thread.start();
/*m_ProgressDialog = ProgressDialog.show(PlayedOnNumaraActivity.this,
"",getString(R.string.PleaseWait), true);
m_ProgressDialog.setCancelable(true);
*/
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
m_adapter.notifyDataSetChanged();
}
};
}
}
}
The code above is working and takes no exception when progress dialog codes are commented
Without your LogCat logs, I can only guess.
m_ProgressDialog is defined after you start your thread. Why? Define it before the thread is started.
Also, I would recommend an AsyncTask for this, instead. See Painless Threading for details on that.
I have spent last couple of hours searching for answers here but nothing seems to make it clear for me.
Here's my problem: I have a simple app with a main menu. One of the options retrieves a list of comments from a PHP server, updates the database and then displays a ListView.
Everything functions properly inside. Now, every time I press back and then start the activity again, a new thread is started. I managed to get to more than 50+ waiting threads. I'm using the DDMS tab from Eclipse to monitor the treads.
If I try to call Looper.getLooper().quit() or Looper.myLooper().quit() I get an error saying "main thread not allowed to quit".
What am I doing wrong and where/how should I be stopping the thread?
Here's the code:
public class RequestActivity extends Activity {
ProgressDialog pDialog;
DatabaseHelper db;
int userId;
myCursorAdapter adapter;
Thread runner = null;
ListView list;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
userId = myApplication.getInstance().getSession().getUserId();
setContentView(R.layout.request_list);
db = new myProvider.DatabaseHelper(this);
Cursor cursor = db.getRequests(userId);
startManagingCursor(cursor);
adapter = new myCursorAdapter(RequestActivity.this, cursor);
list = (ListView) findViewById(R.id.list);
list.setVisibility(View.INVISIBLE);
list.setAdapter(adapter);
pDialog = ProgressDialog.show(RequestActivity.this, "", "Loading ...", true, false);
runner = new Thread() {
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
adapter.getCursor().requery();
}
};
public void run() {
Looper.prepare();
// ... setup HttpGet
try {
// ... get HTTP GET response
if (response != null) {
// ... update database
handler.sendEmptyMessage(0);
}
} catch(Exception e) {
// .. log exception
}
Looper.loop();
}
};
runner.start();
}
private static class ViewHolder {
// .. view objects
}
private class myCursorAdapter extends CursorAdapter {
private LayoutInflater inflater;
public myCursorAdapter(Context context, Cursor c) {
super(context, c);
inflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// .. bind data
if (cursor.isLast()) {
pDialog.dismiss();
list.setVisibility(View.VISIBLE);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = inflater.inflate(R.layout.request_list_item, parent, false);
ViewHolder holder = new ViewHolder();
// .. set holder View objects
view.setTag(holder);
return view;
}
}
}
You're calling quit() on your main thread's Looper. Not the thread's Looper.
You can try this. Create a separate private inner-class that extends Thread. In the run() method, do a call to Looper.myLooper() to save the thread's Looper instance in the class. Then have a quitting method that calls quit on that looper.
Example:
private class LooperThread extends Thread{
private Looper threadLooper;
#Override
public void run(){
Looper.prepare();
threadLooper = Looper.myLooper();
Looper.loop();
}
public void stopLooper(){
if(threadLooper != null)
threadLooper.quit();
}
}
On your onDestroy method do you make any calls to stop the thread?
public void onDestroy()
{
Thread moribund = runner;
runner = null
moribund.interrupt();
}
You are calling the Looper.quit() method within your main (UI) thread, which is not allowed. Try posting a Runnable to the handler inside your thread that calls Looper.quit(). This will cause the Looper within the thread context to quit.
I am want to pass data back from a Thread to Activity (which created the thread).
So I am doing like described on Android documentation:
public class MyActivity extends Activity {
[ . . . ]
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[ . . . ]
}
protected void startLongRunningOperation() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
mResults = doSomethingExpensive();
mHandler.post(mUpdateResults);
}
};
t.start();
}
private void updateResultsInUi() {
// Back in the UI thread -- update our UI elements based on the data in mResults
[ . . . ]
}
}
Only one thing I am missing here - where and how should be defined mResults so I could access it from both Activity and Thread, and also would be able to modify as needed? If I define it as final in MyActivity, I can't change it anymore in Thread - as it is shown in example...
Thanks!
If you define mResults in the class and not the method, you can change it from either location. For example:
protected Object mResults = null;
(Use protected because it's faster)