I am developing one application in which i am getting an exception, and i know this one is the silly or small mistake which i am doing but your help may catch me out and make my day:
public class Demo extends Activity
{
Button btnDemo;
Thread t;
AlertDialog alertDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo);
btnD开发者_运维百科emo = (Button) findViewById(R.id.btnDemo);
btnDemo.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
t=new Thread() {
public void run() {
tryDemo();
}
};
t.start();
}
});
}
public void tryDemo()
{
try
{
int i = 5;
if(i == 0 || i == 1)
{
Intent intent_success = new Intent(getApplicationContext(), Main_Activity.class);
startActivity(intent_success);
}
else
{
alertDialog = new AlertDialog.Builder(getApplicationContext()).create();
alertDialog.setTitle("Demo");
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//here you can add functions
} });
alertDialog.setIcon(R.drawable.icon);
alertDialog.setMessage("Sorry!! Either Username or Password Invalid");
alertDialog.show();
}
}
catch(Exception e)
{
Log.i("Demo", "Demo - Demo Exception");
}
}
}
In above code, if i make i=0 or i=1 in tryDemo function then it is running successfully , but if i make it other than 0 or 1 then it throws an exception as "Demo - Demo Exception".
I am not sure but i think the exception raises from getApplicationContext().
Update:- 1
The exception which i am getting, as follows:
Update:- 2 If I remove the "thread" part and wrote the whole function code in the button click event and replaced the "getApplicationContext()" with v.getContext() then it is running successfully.........but i want to implement it within the THREAD.
Please help me and catch me out...
thanx
Just read your logs :D You haven't called the Looper.prepare()
If I am correct, you should wrap your AlertDialog code with Looper.prepare() and Looper.loop()
So it looks like:
Looper.prepare()
// AlertDialog code
Looper.loop()
You are probably getting a RuntimeException
. I tried calling some dialog creation in a thread not being the UI thread and got this:
09-09 00:46:37.702: ERROR/AndroidRuntime(763): Uncaught handler: thread Thread-10 exiting due to uncaught exception
09-09 00:46:37.724: ERROR/AndroidRuntime(763): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
09-09 00:46:37.724: ERROR/AndroidRuntime(763): at android.os.Handler.<init>(Handler.java:121)
09-09 00:46:37.724: ERROR/AndroidRuntime(763): at android.view.ViewRoot.<init>(ViewRoot.java:192)
09-09 00:46:37.724: ERROR/AndroidRuntime(763): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
09-09 00:46:37.724: ERROR/AndroidRuntime(763): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
09-09 00:46:37.724: ERROR/AndroidRuntime(763): at android.view.Window$LocalWindowManager.addView(Window.java:392)
09-09 00:46:37.724: ERROR/AndroidRuntime(763): at android.app.Dialog.show(Dialog.java:231)
09-09 00:46:37.724: ERROR/AndroidRuntime(763): at com.pkg.name.ToplistActivity$3.run(ToplistActivity.java:149)
Solution is to wrap your else statement like:
else {
runOnUiThread(new Runnable() {
public void run() {
...
}
});
}
Checkout comments in this post:
Using Application context everywhere?
Also if you replace getApplicationContext() with actiivtyname.getApplicationContext() what errors are you getting?
A few things wrong with this. First, you never, EVER touch any UI elements from any thread you've created.
You'll need to get aquatinted with thread Handlers: http://developer.android.com/reference/android/os/Handler.html
The way they work is, you initialize them in your normal UI thread. (the thread your onCreate() method is called.) Handlers, are thread safe objects that you extend to communicate between thread.
So, on your onCreate():
Handler pHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
Bundle bundle = msg.getData();
int msg_type = bundle.getInt("TYPE");
if (msg_type == MyThread.ERROR_MSG)
{
///SOMETHING HAPPENED
return;
}
else
{
//background task finished ok
}
}
};
Then, from your run() method you send it a message using a Bundle and Message object. http://developer.android.com/reference/android/os/Bundle.html and http://developer.android.com/reference/android/os/Message.html
The way I like to do it, to keep things clean is to extend the Thread class to add a little consistency...
class MyThead extends Thread
{
public final int ERROR_MSG = 0;
public final int OK_MSG = 1;
Handler mHandler;
MyThread(Handler pHandler)
{
mHandler = pHandler;
}
@Override
public void run()
{
//send a message back to the ui thread....
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putInt("TYPE", OK_MSG);
msg.setData(bundle);
mHandler.sendMessage(msg);
}
}
This if you want to get a bit fancy, you separate the UI code and the worker thread code completely. If your background task won't take long, you can us runonUiThread() as previous described.
You might also want to use AsyncTask, see: http://developer.android.com/reference/android/os/AsyncTask.html
Here's an example from their page, its usage is rather simple:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
Eventually though, these approaches aren't perfect if the user changes orientation when your task is running. (or if your activity is killed for any other reason.) In that case, you'll want to set up a service: http://developer.android.com/reference/android/app/Service.html
精彩评论