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...
Related
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) {
}
}
This question already has answers here:
CalledFromWrongThreadException
(2 answers)
Closed 6 years ago.
I'm trying to make a small Chat app on Android. I'm trying to send some text messages from Android to my server on PC.
I'm using some knowledge that I've found on Android developers and I created a new class for an AsyncTask:
public class ChatTask extends AsyncTask<Void, Void, Void>
{
private BufferedReader in;
private PrintWriter out;
#Override
protected Void doInBackground(Void... voids)
{
try
{
startClient();
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
// Chat start method
private void startClient() throws IOException
{
Socket socket = new Socket(ipAddress, 9001);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
writeText("Conectat la serverul: " + ipAddress);
while (true)
{
String line = in.readLine();
if (line.startsWith("SUBMITNAME"))
{
out.println(name);
}
else if (line.startsWith("NAMEACCEPTED"))
{
}
else if (line.startsWith("MESSAGE"))
{
writeText(line.substring(8) + "\n");
}
}
}
// Write to TextView
private void writeText(String text)
{
ChatActivity.setsTextToSend(text + "\n");
}
// Write to server
public void sendTextToServer(final String text)
{
Thread thread = new Thread(new Runnable()
{
#Override
public void run()
{
out.println(text + "\n");;
}
});
thread.start();
}
}
Then I linked the Task with my main Activity. I called the Task.execute() function and it's working well (i think) until the point I write a message and press send. The thing is my message that I write is sent over to the server but the my application crashes and it's giveing me this error:
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: ro.remus.messenger, PID: 3460
java.lang.RuntimeException: An error occurred while executing doInBackground()
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at ro.remus.messenger.ChatActivity.writeTo(ChatActivity.java:90)
at ro.remus.messenger.ChatActivity.setsTextToSend(ChatActivity.java:26)
at ro.remus.messenger.ChatTask.writeText(ChatTask.java:70)
at ro.remus.messenger.ChatTask.startClient(ChatTask.java:62)
at ro.remus.messenger.ChatTask.doInBackground(ChatTask.java:29)
at ro.remus.messenger.ChatTask.doInBackground(ChatTask.java:15)
[ I didn't post the entire error because is not relevant ]
My code in the main activity where the error keeps showing is:
btnSend.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
runOnUiThread(new Runnable()
{
#Override
public void run()
{
chatTask.sendTextToServer(getsTextToSend());
}
});
//textToSend.setText("");
}
});
private static void writeTo(String text)
{
tvReceivedText.append(text);
}
I know I'm doing some weird code here but it is doing (somehow) what I want until the point it crashes after I hit 'Send'.
How can I fix this error and stop it from crashing my app ?
Thanks in advance.
Anymore info that is needed I will provide.
As the error say, only the UIThread can make changes to the UI, in this case the TextView. You can use this answer to call sendTextToSend
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....
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.
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);
}