I know there are already a lot of questions like this but I don't see what I'm doing wrong. The app crashes without anything shown. Also, the error doesn't occur on my device or emulator. Just on some devices (say 30-40%?).
Can't create handler inside thread that has not called Looper.prepare()
MainActivity.java
public class MainActivity extends Activity implements Runnable {
Gebruiker gebruiker = new Gebruiker();
private DatabaseHelper db;
Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
if(isOnline()){
downloadData();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("Deze app vereist een actieve verbinding met het internet!")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
android.os.Process.killProcess(android.os.Process.myPid());
}
});
AlertDialog alert = builder.create();
alert.show();
}
db = new DatabaseHelper(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private ProgressDialog pDialog;
public void downloadData() {
pDialog = ProgressDialog.show(this,
"Controleren op bestaande gebruiker..", "Even geduld", true,
false);
Thread thread = new Thread(this);
thread.start();
}
public void run() {
// add downloading code here
HttpReader httpReader = new HttpReader();
String url = "*****";
url += Secure.getString(getApplicationContext().getContentResolver(),
Secure.ANDROID_ID);
JsonHelper jsonHelper = new JsonHelper();
gebruiker = jsonHelper.getGebruiker((httpReader.getTextFromUrl(url)
.trim()));
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
pDialog.dismiss();
if (gebruiker == null) {
// ga naar aanmaken gebruiker
Intent intent = new Intent(MainActivity.this,
AanmakenUser.class);
startActivity(intent);
} else {
// ga naar hoofdmenu
db.droppen();
db.insertGebruiker(gebruiker);
Intent intent = new Intent(MainActivity.this, Hoofdmenu.class);
startActivity(intent);
// ga naar menu
}
}
};
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
LogCat
01-10 16:12:16.444: E/AndroidRuntime(6090): FATAL EXCEPTION: Thread-10
01-10 16:12:16.444: E/AndroidRuntime(6090): java.lang.ExceptionInInitializerError
01-10 16:12:16.444: E/AndroidRuntime(6090): at db.jochen.quizapp.MainActivity.run(MainActivity.java:68)
01-10 16:12:16.444: E/AndroidRuntime(6090): at java.lang.Thread.run(Thread.java:1019)
01-10 16:12:16.444: E/AndroidRuntime(6090): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
01-10 16:12:16.444: E/AndroidRuntime(6090): at android.os.Handler.<init>(Handler.java:121)
01-10 16:12:16.444: E/AndroidRuntime(6090): at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
01-10 16:12:16.444: E/AndroidRuntime(6090): at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
01-10 16:12:16.444: E/AndroidRuntime(6090): at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
01-10 16:12:16.444: E/AndroidRuntime(6090): ... 2 more
01-10 16:12:16.454: D/dalvikvm(6090): GC_CONCURRENT freed 79K, 48% free 2843K/5379K, external 3695K/4614K, paused 2ms+5ms
01-10 16:12:16.454: W/ActivityManager(278): Force finishing activity db.jochen.quizapp/.MainActivity
01-10 16:12:16.544: E/SkLayout_wtle(6090): ellipsis failed line number does not match 1 0
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: finish the match exclude list procedure, but can not match any one
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: GoDormant? 0
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Locked in fdm_main_loop
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Unlocked in fdm_main_loop
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: finish the match exclude list procedure, but can not match any one
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: GoDormant? 0
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Locked in fdm_main_loop
01-10 16:12:16.624: D/fast-dormancy(165): [FDM]: Threads Status Mutex Unlocked in fdm_main_loop
01-10 16:12:16.624: I/ActivityManager(278): No longer want com.sonyericsson.tvlauncher (pid 4961): hidden #16
01-10 16:12:16.664: E/WindowManager(6090): Activity db.jochen.quizapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@2afd4aa0 that was originally added here
01-10 16:12:16.664: E/WindowManager(6090): android.view.WindowLeaked: Activity db.jochen.quizapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@2afd4aa0 that was originally added here
01-10 16:12:16.664: E/WindowManager(6090): at android.view.ViewRoot.<init>(ViewRoot.java:269)
01-10 16:12:16.664: E/WindowManager(6090): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
01-10 16:12:16.664: E/WindowManager(6090): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
01-10 16:12:16.664: E/WindowManager(6090): at android.view.Window$LocalWindowManager.addView(Window.java:424)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.Dialog.show(Dialog.java:241)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.ProgressDialog.show(ProgressDialog.java:109)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.ProgressDialog.show(ProgressDialog.java:97)
01-10 16:12:16.664: E/WindowManager(6090): at db.jochen.quizapp.MainActivity.downloadData(MainActivity.java:59)
01-10 16:12:16.664: E/WindowManager(6090): at db.jochen.quizapp.MainActivity.onCreate(MainActivity.java:33)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1623)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1675)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.ActivityThread.access$1500(ActivityThread.java:121)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:943)
01-10 16:12:16.664: E/WindowManager(6090): at android.os.Handler.dispatchMessage(Handler.java:99)
01-10 16:12:16.664: E/WindowManager(6090): at android.os.Looper.loop(Looper.java:138)
01-10 16:12:16.664: E/WindowManager(6090): at android.app.ActivityThread.main(ActivityThread.java:3701)
01-10 16:12:16.664: E/WindowManager(6090): at java.lang.reflect.Method.invokeNative(Native Method)
01-10 16:12:16.664: E/WindowManager(6090): at java.lang.reflect.Method.invoke(Method.java:507)
01-10 16:12:16.664: E/WindowManager(6090): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
01-10 16:12:16.664: E/WindowManager(6090): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
01-10 16:12:16.664: E/WindowManager(6090): at dalvik.system.NativeStart.main(Native Method)
Your approach to perform action in the background is really odd (i.e.
Activity implements Runnable
). I guess, the problem lays in the way you calldownloadData()
method, perhaps, from other background threads. (By the way, how do you call it, i.e. where do you store the reference to the MainActivity?)Your task is easily solved by
Loaders
, which perfectly match Activity's lifecycle and requires much less code.You handler may be created in another thread, not main which does not have looper. To avoid this you should create handler in thread with looper (ex: in main thread, in onCreate), or provide looper to a handler:
How can you manage the request sent to a handler if your thread is not listening on a looper?
Doc says: public Handler ()
Added in API level 1 Default constructor associates this handler with the Looper for the current thread. If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
If you want a secondary thread to be able to manage a Handler you must call Looper.prepare()
Example: