How to use UnHandledExceptionHandler on android? - android

recently when I disconnect camera on my device. occur nullpointerException
so , I think use UnhandledExceptionHandler
I try this, first not occur nullpointerException
but app not start.
I want without camera device, app execute well.
MainActivity.class
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String nameOfFrontFacingDevice = VideoCapturerAndroid.getNameOfFrontFacingDevice();
VideoCapturerAndroid capturer = VideoCapturerAndroid.create(nameOfFrontFacingDevice);
if (capturer == null || capturer.equals("") == true) {
Thread.setDefaultUncaughtExceptionHandler(new UnhandledExceptionHandler(this));
throw new NullPointerException();
}
UnhandledExceptionHandler.class
public class UnhandledExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "UnUnHandler";
private final Activity activity;
public UnhandledExceptionHandler(final Activity activity) {
this.activity = activity;
}
public void uncaughtException(Thread unusedThread, final Throwable e) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
String title = "Fatal error: " + getTopLevelCauseMessage(e);
String msg = getRecursiveStackTrace(e);
TextView errorView = new TextView(UnhandledExceptionHandler.this.activity);
errorView.setText(msg);
errorView.setTextSize(2, 8.0F);
ScrollView scrollingContainer = new ScrollView(UnhandledExceptionHandler.this.activity);
scrollingContainer.addView(errorView);
OnClickListener listner = new OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
System.exit(1);
}
};
Builder builder = new Builder(UnhandledExceptionHandler.this.activity);
builder.setTitle(title).setView(scrollingContainer).setPositiveButton("Exit", listner).show();
}
});
}
private static String getTopLevelCauseMessage(Throwable t) {
Throwable topLevelCause = t;
while (topLevelCause.getCause() != null) {
topLevelCause = topLevelCause.getCause();
}
return topLevelCause.getMessage();
}
private static String getRecursiveStackTrace(Throwable t) {
StringWriter writer = new StringWriter();
t.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
}
this not showing dialog.
how to use UnhandledExceptionHandler?

Uncaught exception handler is supposed to be used only in the worst case scenario when every other mechanism fails. To handle NullPointerException, you should put that in a try catch block.
I suggest you look into Exception Handling in Java first.
UncaughtException handler- means some unexpected error occured and not allowing the app to crash can lead to unstable results.
Use it only to report or log unexpected exceptions, not as a defense against exceptions. That shows a flaw in the App design.
If you still plan to use UncaughtExceptionHandler, since you are not very aware of how Java works, I suggest you to use another 3rd party service to do this for you..
Eg---> Crashlytics (It has an in built default exception handler and reports crashes when they happen) or ACRA etc....

Related

How to prevent android app from being Crash [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I want to stop my app from being crashed due to uncaught exception. I want exception to be store in log and prevent application from getting crashed. How do i achieve this ?. Thanks in advance.
For this your just need two classes Just copy paste them .
This class is called when any exception occur within your application.
public class CrashHandler implements
java.lang.Thread.UncaughtExceptionHandler {
private final Context myContext;
private final String LINE_SEPARATOR = "\n";
public CrashHandler(Context context) {
myContext = context;
}
public void uncaughtException(Thread thread, Throwable exception) {
StringWriter stackTrace = new StringWriter();
exception.printStackTrace(new PrintWriter(stackTrace));
StringBuilder errorReport = new StringBuilder();
errorReport.append("************ CAUSE OF ERROR ************\n\n");
errorReport.append(stackTrace.toString());
errorReport.append("\n************ DEVICE INFORMATION ***********\n");
errorReport.append("Brand: ");
errorReport.append(Build.BRAND);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Device: ");
errorReport.append(Build.DEVICE);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Model: ");
errorReport.append(Build.MODEL);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Id: ");
errorReport.append(Build.ID);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Product: ");
errorReport.append(Build.PRODUCT);
errorReport.append(LINE_SEPARATOR);
errorReport.append("\n************ FIRMWARE ************\n");
errorReport.append("SDK: ");
errorReport.append(Build.VERSION.SDK);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Release: ");
errorReport.append(Build.VERSION.RELEASE);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Incremental: ");
errorReport.append(Build.VERSION.INCREMENTAL);
errorReport.append(LINE_SEPARATOR);
Intent intent = new Intent(myContext, ExceptionDisplay.class);
intent.putExtra("error", errorReport.toString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
myContext.startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
}
}
Now make an Activity that displayed the error :-
public class ExceptionDisplay extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.exception_display_layout);
TextView exception_text = (TextView) findViewById(R.id.exception_text);
Button btnBack = (Button) findViewById(R.id.btnBack);
exception_text.setText(getIntent().getExtras().getString("error"));
btnBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
intentData();
}
});
}
#Override
public void onBackPressed() {
intentData();
}
public void intentData() {
Log.d("CDA", "onBackPressed Called");
Intent setIntent = new Intent(ExceptionDisplay.this, AppDataSourceSelection.class);
setIntent.addCategory(Intent.CATEGORY_HOME);
setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(setIntent);
}
}
Now you can call this class by the class that extends application Class:
public class ErrorHandler extends Application {
#Override
public void onCreate() {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(getApplicationContext()));
}}
You can handle the uncaught exceptions yourself by this.
Use below code into your application class.
public class MyApplication extends Application {
private UncaughtExceptionHandler defaultUEH;
private Thread.UncaughtExceptionHandler _unCaughtExceptionHandler =
new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
// here I do logging of exception to a db
Log.d("MyApp", "Uncaught exception.");
// Do what you want.
// re-throw exception to O.S. if that is serious and need to be handled by o.s. Uncomment the next line that time.
//defaultUEH.uncaughtException(thread, ex);
}
};
public MyApplication() {
defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
// setup Thread.setDefaultUncaughtExceptionHandler(_unCaughtExceptionHandler);
}
}
You can use try catch block to catch the exception by this way you can prevent your application from being crashing. In catch block get the expected exception and log that for your help. but remember not every exception can be caught
Because some exceptions don't derive from Exception - e.g. Throwable and Error.
Basically the type hierarchy is:
Object
|
Throwable
/ \
Exception Error
Only Throwables and derived classes can be thrown, so if you catch Throwable, that really will catch everything.
Any exception deriving from Exception (or Exception itself) other than those derived from RuntimeException count as checked exceptions - they're the ones that you have to declare you'll throw, or catch if you call something that throws them.
All told, the Java exception hierarchy is a bit of a mess...

This message cannot be recycled because it is still in use

I'm trying to use this article to create asynchronous UDP socket.
So I've this code:
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpThread
extends HandlerThread {
private static final String TAG = "UDP";
private final Handler uiHandler, workerHandler;
private final DatagramSocket socket = new DatagramSocket();
public UdpThread(final Handler uiHandler, final String hostname, final int port) throws SocketException {
super(TAG);
this.uiHandler = uiHandler;
start();
workerHandler = new Handler(getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(final Message msg) {
/*
if (msg.what == port && msg.obj == hostname) {
final InetSocketAddress address = new InetSocketAddress(hostname, port);
Log.d(TAG, "Connecting to " + address);
try {
socket.connect(address);
} catch (SocketException se) {
throw new RuntimeException(se);
}
}
*/
msg.recycle(); //java.lang.IllegalStateException: This message cannot be recycled because it is still in use.
return true;
}
});
workerHandler.obtainMessage(port, hostname).sendToTarget();
}
}
But when I run the code, I get the mentioned java.lang.IllegalStateException: This message cannot be recycled because it is still in use. when trying to recycle the message. Why is that and how to solve it and prevent memory leaks?
Well first of all lets see how Message recycle() method works.
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
So you are getting IllegalStateException if it is in use
isInUse() just checks flag and looks like:
boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
And when we try to read about that flag we see description:
If set message is in use.
This flag is set when the message is enqueued and remains set while it
is delivered and afterwards when it is recycled. The flag is only
cleared when a new message is created or obtained since that is the
only time that applications are allowed to modify the contents of the
message.
It is an error to attempt to enqueue or recycle a message that is
already in use.
So what we have
You cant recycle message until its "in use"
It is "in use" until new message obtained or created
How to solve the problem
There is method recycleUnchecked() inside Message class to recycle message object even if it is in use.Thats what you need! Description of it:
Recycles a Message that may be in-use.
Used internally by the MessageQueue and Looper when disposing of
queued Messages.
Worst thing that it uses internally and has package access. Good thing that it uses internally when you call:
handler.removeMessages(int what)
So I guess final solution is:
replace
msg.recycle();
to
try {
msg.recycle(); //it can work in some situations
} catch (IllegalStateException e) {
workerHandler.removeMessages(msg.what); //if recycle doesnt work we do it manually
}
You shouldn't call msg.recycle() yourself, message is recycled automatically by Looper after it has been dispatched/processed (after your handleMessage() returns), see source code.
Try to use AsyncTask to delete the message when the handler thread finish to proceed it.
//[..]
//synchronized with the handler thread
#Override
public boolean handleMessage(final Message msg) {
new MessageDestructor().execute(msg);
return true;
}
//[..]
private class MessageDestructor extends AsyncTask<Message, Void, Void> {
Message msg;
#Override
protected String doInBackground(Message... params) {
msg = (Message) params[0];
return null;
}
#Override
protected void onPostExecute(Void result) {
msg.recycle(); //synchronized with the main thread
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}

Listener not called in Unit Test

I tried to create unit test for my project.
Inside my unit test class I have two methods testCalculate() and testLogin(). Method testCalculate() running fine, meaning that test passed and I got correct testing result.
But problem is in testLogin(), I expect that my code will be print something inside the listener, but it never printed.Meaning that I never get this line
System.out.println("Login success ======= " + response.getResponseObject());
My login method that I want to test itself running fine, meaning if I use it inside my real app, it will login successfully and return some datas that I got from server.
Kindly advise what is possible cause that make my listener is not working in unit test. Really appreciate for any kind help.
#RunWith(RobolectricTestRunner.class)
#Config(manifest = Config.NONE)
public class LoginManagerTest {
private static final String TAG = LoginManagerTest.class.getCanonicalName();
private String usernameStr = "androidtest#gmail.com";
private String passwordStr = "********";
private LoginManager loginManager;
#Test
public void testLogin() throws Exception {
ResponseHandlerListener<String> listener = new ResponseHandlerListener<String>() {
#Override
public void onReceive(AxonResponse<String> response) {
System.out.println("Login success ======= " + response.getResponseObject());
String loginSuccess = Constants.LOGIN_SUCCESS;
assertEquals(TAG, loginSuccess, response.getResponseObject());
}
};
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
loginManager.login(usernameStr, passwordStr, null, listener);
}
#Test
public void testCalculate() throws Exception {
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
int num = 5;
int sum = loginManager.calculate(num);
System.out.println("sum = " + sum);
assertEquals(10, sum);
}
}
I had the same issue. I solved by using Robolectric.flushForegroundThreadScheduler(). This will run queued tasks that is on forground thread.
It's going to be like this:
#Test
public void testLogin() throws Exception {
ResponseHandlerListener<String> listener = new ResponseHandlerListener<String>() {
#Override
public void onReceive(AxonResponse<String> response) {
System.out.println("Login success ======= " + response.getResponseObject());
String loginSuccess = Constants.LOGIN_SUCCESS;
assertEquals(TAG, loginSuccess, response.getResponseObject());
}
};
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
loginManager.login(usernameStr, passwordStr, null, listener);
ThreadSleep(500); //Wait for login process to be executed
Robolectric.flushForegroundThreadScheduler(); // this will run all the pending queue on Main Thread
}
I think the problem is the callback will be called after time, it means run asynchronus, and the test is out of time with other (main) thread. I have no experience about Robolectric test, but a little bit about AndroidTestSuite. So, I suggest you need some waitting time before the listener callback is called. Here is the sample and the other idea. Hope that help.
Update:
Try the below idea (Not tested):
private Object lock = new Object();
#Test
public void testLogin() throws Exception {
ResponseHandlerListener<String> listener = new ResponseHandlerListener<String>() {
#Override
public void onReceive(AxonResponse<String> response) {
System.out.println("Login success ======= " + response.getResponseObject());
String loginSuccess = Constants.LOGIN_SUCCESS;
assertEquals(TAG, loginSuccess, response.getResponseObject());
synchronized (lock) {
lock.notifyAll(); // Will wake up lock.wait()
}
}
};
synchronized (lock) {
Context context = Robolectric.getShadowApplication().getApplicationContext();
loginManager = new LoginManager(context);
loginManager.login(usernameStr, passwordStr, null, listener);
lock.wait();
}
}

Second time running the thread makes application crash

I use a worker thread to read text from a url. My thread is as follow. In the first time running, I am sure thread running is finished as I can check sdcard_readstr is null.
In the second time running, when I call thread_download.start();, then the program crashed.
What could be wrong? Thanks
public class DownloadingThread extends AbstractDataDownloading {
#Override
public void doRun() {
// TODO Auto-generated method stub
try {
// Create a URL for the desired page
URL url = new URL(SDcard_DetailView.textfileurl);
// Read all the text returned by the server
BufferedReader in = new BufferedReader(new
InputStreamReader(url.openStream()));
do{
sdcard_readstr = in.readLine();
}while(sdcard_readstr!=null);
in.close();
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}
}
public abstract class AbstractDataDownloading extends Thread{
private final Set<ThreadCompleteListener> listeners
= new CopyOnWriteArraySet<ThreadCompleteListener>();
public final void addListener(final ThreadCompleteListener listener) {
listeners.add(listener);
}
public final void removeListener(final ThreadCompleteListener listener) {
listeners.remove(listener);
}
private final void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.notifyOfThreadComplete(this);
}
}
#Override
public final void run() {
try {
doRun();
} finally {
notifyListeners();
}
}
public abstract void doRun();
}
EDIT1:
In my thread complete notification, I use runOnUiThreadto use the UI components.
Is that causing problem?
public void notifyOfThreadComplete(Thread thread) {
// TODO Auto-generated method stub
if(downloadingStopbuttonispressed == false){//background process completed
textfileurl = null;
this.runOnUiThread(new Runnable() {
public void run() {
Wifibutton = (Button) findViewById(R.id.Wifiscanning);
Wifibutton.setText("Load another day's data");
final MenuItem refreshItem = optionsMenu.findItem(R.id.airport_menuRefresh);
refreshItem.setActionView(null);
}
});
}
}
I called thread start in onResume() as
#Override
protected void onResume() {
super.onResume();
if(textfileurl != null){
Wifibutton.setText("Stop Data Loading");
buttonStatus = "loading";
setRefreshActionButtonState(true);
thread_download.start();
}
}
EDIT2:
My LogCat image is attached.
My solution is here . I can't reuse the same instance of the Thread object in the second time. I need to create a new instance to call the Thread in the second time. So Thread is suitable for single time running process, for multiple time running process I should use AsyncTask. Even AsyncTack is only for one time execution and for multiple time execution, we should use as new MyAsyncTask().execute(""); I don't understand why people downvote with no reason given. I couldn't find the link in my first search.

Trying to update a TextField through a Handler, and getting CalledFromWrongThreadException

I seem to be having trouble with updating a TextView from a thread. I have a GameConnection class (which manages a socket connection) which I want to use across activities. It calls a local "onMessage", which then uses the target handler to call dispatch Message. The "Handler" in this case, is in my GameBrowser activity.
Here's code from the GameConnection class.
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
String message = "".intern();
// as a newline character is read, we interpret it as a message
while ((message = in.readLine()) != null && isConnected){
onMessage(message);
}
As said above, a local method "onMessage" method handles dispatching of the message.
private void onMessage(String message){
... // create message from String
handler.dispatchMessage( msg );
}
However, when I get the response in the GameBrowser class, I get a CalledFromWrongThreadException . Initially, I was using a callback method, which of course wasn't working. So, after some research, I've found that I have to use a Handler, but I can't seem to get it right.
public class GameBrowser extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(C.tag, "GameBrowser.onCreate addr:" + this);
handler = new Handler(new HandlerCallback());
connection.addMessageListener(handler);
connection.connect();
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
setContentView(R.layout.game_browser);
}
private class HandlerCallback implements Callback{
#Override
public boolean handleMessage(Message msg) {
if (txtGameLabel == null){
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
}
String message = msg.getData().getString("message");
Log.d(C.tag, "GameBrowser recieved message " + message);
txtGameLabel.setText("Data: " + message);
return true;
}
}
}
I figured out what I was doing wrong. Instead of calling the handler from the socket thread, I used a callback, then used Runnable to post to the handler in the GameConnection class. When onMessage executes "run", which executes "updateTextField", we're back in the main thread.
#Override
public void onMessage(final String message) {
handler.post(new Runnable(){
#Override
public void run() {
updateTextField(message);
}
});
}
private void updateTextField(String message){
if (txtGameLabel == null)
txtGameLabel = (TextView)findViewById( R.id.txtGamesLabel);
txtGameLabel.setText(message);
}

Categories

Resources