NullPointerException in onProgressUpdate() - java

Edit: I put this pB = (ProgressBar) findViewById(R.id.progressBar); in the onPreExecute(). It works, everything works. But is this a good solution? I know that in my main thread the progress bar was !null. But before this findViewById, my asynctask just couldn't find the progress bar I wanted, even though I thought I was passing it in .execute().
This is my first experience with asynctask. I have a progress bar that I want to count up, but I keep getting a NullPointerException.
The log read "Progress Update: 1" but then the VM shuts down. So I know an integer is getting passed, but I can't figure out why it can't find the progress bar(pB). I've tried to setProgress(0) in the main thread, in the onPreExecute(), but the machine hated it.
It runs the rest of the for loop in doInBackground(), and logs the "Percent Progress: " and "Sleeping " but won't log any more "Progress Update: ".
The NullPointerException is at line 31, which is pB.setProgress(progress[0]);
#Override
protected void onProgressUpdate(Integer...progress){
Log.d(LOG_TAG, "Progress Update: "+progress[0].toString());
super.onProgressUpdate(progress);
if(progress[0]!=null){
pB.setProgress(progress[0]);
}
}
#Override
protected Boolean doInBackground(Integer...numSeconds){
Log.d(LOG_TAG, "doInBackground: "+numSeconds[0]);
try {
int totalSecs = numSeconds[0].intValue();
Log.d(LOG_TAG, "Total SECS: "+totalSecs);
for(int i = 1; i <= totalSecs; i++){
Log.d(LOG_TAG, "Sleeping "+i);
Thread.sleep(1000);
float percentage = ((float)i/(float)totalSecs)*100;
Log.d(LOG_TAG, "Percentage Progress: "+ percentage);
Float progress = Float.valueOf(percentage);
publishProgress(new Float(progress).intValue());
}
} catch (InterruptedException e){
e.printStackTrace();
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean result){
Log.d(LOG_TAG, "Post Execute "+ result);
super.onPostExecute(result);
pB.setProgress(0);
}
Here's some from my main thread:
To initialize the progress bar:
timer = (ProgressBar) findViewById(R.id.progressBar);
timer.setProgress(0);
To execute the asynctask:
OnClickListener startBubbles = new OnClickListener(){
#Override
public void onClick(View arg0) {
new ProgBar(timer).execute(100);
setAll();
}
};
The constructor:
public ProgBar(ProgressBar pB){
Log.d(LOG_TAG, "Constructor");
}

Null Pointer Exception occurs when you are accessing value , which is not yet been initaialized.
So for ex. char a[10];
System.out.println(a[3]);
So there must be variable within your code which you are accessing without initialising it. I thing numSecond but I am not sure.
Sorry thats all I know

Related

How can a Double.parseDouble crash my app?

I'm learning java and i have found a great tutorial on youtube, when trying to addapt it for my needs, i came to this problem:
I need to turn a string into a double, do some math, and fill a TextView with the result.
Also, it would be nice, if i could get that data from the firebase database (which my code does in another activity).
Now, i've abandoned the ideea of getting the data from the dtb because the app crashes everytime i open the activity, after i added the try, catch, finally, it doenst crash, but the activity is blank and no error is being displayed.
Tried eliminating row by row, to see where the problem is, but the app still crashes, even if one row is being left in.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText sup = findViewById(R.id.etSup);
EditText emi = findViewById(R.id.etEmi);
EditText ver = findViewById(R.id.etVer);
EditText abs = findViewById(R.id.etAbs);
TextView ResultTextView = findViewById(R.id.tvResult);
TextView Car = findViewById(R.id.tvCar);
Double dsup = Double.parseDouble(sup.getText().toString());
Double demi = Double.parseDouble(emi.getText().toString());
Double dver = Double.parseDouble(ver.getText().toString());
Double dabs = Double.parseDouble(abs.getText().toString());
Double CE = dsup * demi;
ResultTextView.setText("Total emissions are " + CE);
Double PS = dver * dabs;
Double Total = CE - PS;
Car.setText("Emission balance is " + Total);
}
});
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
No error messages have been seen
Try putting the entirety of the onClick() method in a try/catch block. By the time a parseDouble() method throws an exception, you are no longer in the onCreate() method because all you are doing in onCreate() is registering a listener. The onClick() method runs later on
I'm not sure what exception you might be getting from your parseDouble calls (could be many things, nullpointer perhaps?) but this change will allow you to find out.
In case I'm not explaining myself very well:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
// do things
} catch (Throwable e) {
e.printStackTrace();
throw e;
}
}
}
Edit: Changed catching 'Exception' to 'Throwable' just to be sure we don't miss anything (as a side note, you really shouldn't catch a Throwable except for debugging, which is why I've thrown it on again)

Android Studio - Starting and Stopping a Loop With a Button Press

I'm new to using Android Studio, and am currently writing an app that makes use of sensors in the phone to control another device. I searched and haven't found much that helps me address my issue. Eventually I need to transmit the data I get from the sensors over a network, but I'm nowhere near that point yet so that's for another day.
Right now, the app can access the sensors and display it on the phone screen. Each time the on screen button is pressed it updates the readings. What I want it to do though is once I press the button once, continually update the values in real time as the phone is moved around. If the button is pressed again I'd like it to stop. Below is my current code in the main activity. What I tried to do was use an integer that I would toggle each time the button was pressed and run a do while loop on one of the values. When the do while loop is in there it won't do anything. If I take it out, it runs like it originally did updating the values each time the button is pressed. I also am displaying the value of "toggle" next to the sensor values and it is toggling when the do while loop isn't in there. I don't understand why the do while loop won't run at all. I also tried using a boolean value and toggling between true and false but I got the same result. I also realize that the way the do while loop is set up it would probably not be able to be stopped, but I would've thought it would've at least entered the loop and kept running which would've at least got me started.
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.widget.TextView;
import android.widget.Button;
import android.view.View;
public class MainActivity extends AppCompatActivity
{
MySensorUpdateThread mySensorUpdateThread = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mySensorUpdateThread = new MySensorUpdateThread(this);
SensorManager sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
final float[] mValuesMagnet = new float[3];
final float[] mValuesAccel = new float[3];
final float[] mValuesOrientation = new float[3];
final float[] mRotationMatrix = new float[9];
final Button btn_valider = (Button) findViewById(R.id.btn1);
final TextView txt1 = (TextView) findViewById(R.id.textView1);
final SensorEventListener mEventListener = new SensorEventListener() {
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
System.arraycopy(event.values, 0, mValuesAccel, 0, 3);
break;
case Sensor.TYPE_MAGNETIC_FIELD:
System.arraycopy(event.values, 0, mValuesMagnet, 0, 3);
break;
}
}
;
};
setListners(sensorManager, mEventListener);
btn_valider.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
mySensorUpdateThread.toggleThread();
if (mySensorUpdateThread.isRunning())
{
mySensorUpdateThread.start();
}
}
});
}
public void setListners(SensorManager sensorManager, SensorEventListener mEventListener)
{
sensorManager.registerListener(mEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(mEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_NORMAL);
}
public class MySensorUpdateThread extends Thread
{
private boolean keepRunning = false;
private String sensorResults = "";
private MainActivity mActivity;
public MySensorUpdateThread(MainActivity activity)
{
this.mActivity = activity;
}
public void toggleThread()
{
this.keepRunning = !this.keepRunning;
}
public boolean isRunning()
{
return this.keepRunning;
}
public String getSensorResults()
{
return this.sensorResults;
}
#Override
public void run()
{
int i = 0;
int maxIterations = 100;
try{
while(this.keepRunning)
{
// This keeps the thread from going on too long in case
if(i > maxIterations)
{
this.keepRunning = false;
break;
}
// This causes the thread to rest for 50ms to
// slow things down
try
{
Thread.sleep(50);
}
catch(InterruptedException e)
{
}
SensorManager.getRotationMatrix(mRotationMatrix, null, mValuesAccel, mValuesMagnet);
SensorManager.getOrientation(mRotationMatrix, mValuesOrientation);
sensorResults = "Roll/Pitch (degrees): " + /*mValuesOrientation[0]*(180/Math.PI) + " "+ "," + " " +*/
mValuesOrientation[1] * (180 / Math.PI) + " " + "/" + " " +
mValuesOrientation[2] * (-180 / Math.PI);
// Now post the results to the UI Thread
runOnUiThread(new Runnable(){
#Override
public void run(){
txt1.setText(getSensorResults());
}
});
}
}
catch()
{
Log.e(TAG, ex.getMessage());
}
}
}
}
I found it helpful when I used handler thread for long time tasks, handler thread is androids official way for handling long running task. Here is the offical link
for more information on how to use a handler thread.
https://developer.android.com/reference/android/os/HandlerThread.html
Put your sensor reading in a background thread. This is just an example. Make modifications as may be needed!
In your Activity class you will need to setup your background thread object:
MySensorUpdateThread mySensorUpdateThread = null;
In your Activities onCreate() method initialize the background thread by adding:
mySensorUpdateThread = new MySensorUpdateThread();
In your onClick() method start and stop you background thread:
public void onClick(View view){
mySensorUpdateThread.toggleThread();
if(mySensorUpdateThread.isRunning()){
mySensorUpdateThread.start();
}
});
Now here is the code for the background thread:
public class MySensorUpdateThread extends Thread{
SensorManager sensorManager = null;
private boolean keepRunning = false;
private String sensorResults = "";
public void toggleThread(){
this.keepRunning = !this.keepRunning;
}
public void isRunning(){
return this.keepRunning;
}
public String getSensorResults(){
return this.sensorResults;
}
#Override
public void run(){
if(sensorManager == null){
sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
}
int i = 0;
int maxIterations = 100;
String mess = "";
try{
while(this.keepRunning){
mess = "Number of iterations: " + i;
Log.e(TAG, mess);
// This keeps the thread from going on too long in case
if(i > maxIterations){
this.keepRunning = false;
break;
}
// This causes your thread to rest for 500ms it might be a
// good idea to slow things down a bit -- just a suggestion
Thread.sleep(500);
// Get your sensor data here and set it to the
// local variable to be posted to the UI Thread
//this.sensorResults = sensorString;
// Now post the results to the UI Thread
runOnUiThread(new Runnable(){
#Override
public void run(){
txt1.setText(getSensorResults());
}
}
}
}
catch(){
Log.e(TAG, ex.getMessage());
}
}
}
You will probably want to stop the background thread on the Activities onPause() method and perhaps restart it on onResume().

Thread is started twice

I have a problem with my onCreate method. I have identified that when I switch to this activity the onCreate method gets called twice and therefore starting 2 threads which I dont want. Because the thread sends coordinates to a RaspberryPi and the 2nd unwanted thread always sends 0 0 0 which I dont want. I cant seem to find a fix for this so . . . I'd appreciate help if someone could tell me a fix so the thread starts only once.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Joystick = (ImageView) findViewById(R.id.Joystick);
Regler = (ImageView) findViewById(R.id.Regler);
buttonFoto = (Button) findViewById(R.id.buttonFoto);
buttonVideo = (Button) findViewById(R.id.buttonVideo);
buttonNeu = (Button) findViewById(R.id.buttonNeu);
buttonSpeichern = (Button) findViewById(R.id.buttonSpeichern);
touchscreenJoystick = (TextView) findViewById(R.id.touchscreenJoystick);
touchscreenJoystick.setOnTouchListener(this);
touchscreenRegler = (TextView) findViewById(R.id.touchscreenRegler);
touchscreenRegler.setOnTouchListener(this);
RL = (RelativeLayout) findViewById(R.id.activity_main);
running = true;
firstTouch = true;
Bild = (WebView) findViewById(R.id.webView);
Bild.loadUrl("http://10.0.0.1:8080/stream");
thread = new Thread(new MainActivity.TransmitThread());
thread.start();
}
EDIT:
I tried something with SaveInstanceState
//Same onCreate-stuff as above
if(savedInstanceState == null)
{
thread = new Thread(new MainActivity.TransmitThread());
thread.start();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("message","crashed");
super.onSaveInstanceState(outState);
}
what this does is weird. Now I only have one thread that crashes immediately after sending the coordinates once.
Logs:
Log.i that i put before sending:
I/sent: //X: 0 //Y: 0 //Z: 0
Log that comes right after
I/System: core_booster, getBoosterConfig = false
Edit 2:
I've also tried starting the thread at an other timing. In my onTouch like this:
public boolean onTouch(View v, MotionEvent me)
{
xt = me.getX();
yt = me.getY();
int Aktion = me.getAction();
if(firstTouch)
{
thread = new Thread(new MainActivity.TransmitThread());
thread.start();
firstTouch = false;
}
//other stuff that i need to do here
}
But this results into the same as my try with SaveInstanceState a thread that transmits once but doesnt loop.
Edit 3:
I should probably post my thread too
class TransmitThread implements Runnable
{
#Override
public void run()
{
while(running)
{
delay();
xss = xs;
yss = ys;
zss = zs;
Log.i("sent","//X: " + xss + " //Y: " + yss + " //Z: " + zss);
transmit();
}
}
public void transmit()
{
try{
socket = new Socket(ServerIP,ServerPort);
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printStream.print(xs + " " + ys + " " + zs);
Akkustand = input.readLine();
handler.sendEmptyMessage(0);
}catch(UnknownHostException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
public void delay(){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
FINAL EDIT:
I managed to do a workaround. I check before sending if the value is 0 if it is then I change it to 200. On the other end I check if its 200 and change it to 0 and ignore any 0 that I get.
First of all OnCreate will only be called one time for each lifetime of the Activity. However, there are a number of situations that can cause your activity to be killed and brought back to life. Thus, OnCreate get called again.
First thing you can debug the code and find the place where it called repeatedly.
Note: To avoid this situation you can save state information in onSaveInstanceState and restore it back in the state bundle you get in on create.
Thanks
OnCreate() already creates a main thread, and then you call another instance of the main class by manually creating a thread of the main class.
According to this answer all you dont need boolean check, just check if savedInstance is null, and only then start the second thread.
More general solution would be to initialise and start the thread in onStart() but dont forget to stop it in onStop() . If you want this thread to be long running in the background- I suggest start using something else- Service docs
Any configuration change will cause Android to restart your Activity like screen rotation, keyboard availability etc. what the system is actually doing is calling onDestroy() and then immediately calling onCreate(), meaning that the original Activity object is replaced by a new one without any knowledge of the executing background thread, so only the Activity object that started the thread knows that the thread was started.
A better way of handling this is through retaining thread in Activity.
The Activity class contains two methods for handling thread retention:
public Object onRetainNonConfigurationInstance()
called before configuration change occurs
public Object getLastNonConfigurationInstance()
Called in the new Activity object to retrieve the retained object returned in onRetainNonConfigurationInstance()
So you can implement this in following way.
private static MyThread t;
#Override
public void onCreate(Bundle savedInstanceState) {
Object retainedObject = getLastNonConfigurationInstance();
if (retainedObject != null) {
t = (MyThread) retainedObject;
}
else{
t = new MyThread();
t.start();
}
}
#Override
public Object onRetainNonConfigurationInstance() {
if (t != null && t.isAlive()) {
return t;
}
return null;
}

android - OutofMemoryError - bitmap size exceeds VM budget - on orientation change

I have just started using Android. I have tried an apps with orientation change.
I am facing bitmap size exceeds VM budget. Have gone through many post in stackoverflow and could not figure out the problem. Exception is throwing at setContentView(R.layout.level1); in onCreate. This is happening when I change the orientation.
I have tried all forums and stackoverflow but could not figure it out. Trying to fix this for past 3 days.
Below class is being called from another activity on button click using intent and startActivity.
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d("onCreate", "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.level1);
if(!isOrientationChanged) //this part is executed if orientation is not changed (activity starts as usual)
{
drawableList = new ArrayList<Drawable>();
drawableList.add( getResources().getDrawable(colorEnum[0]));
drawableList.add( getResources().getDrawable(colorEnum[1]));
}
isOrientationChanged = false;
timeView = (TextView) findViewById(R.id.timeView);
colorButton = (Button) findViewById(R.id.game_button);
}
#Override
protected void onResume() {
scoreView = (TextView) findViewById(R.id.scoreView);
scoreView.setText("Score: " + score);
hand.postDelayed(runThread, 0);
super.onResume();
}
#Override
public Object onRetainNonConfigurationInstance() {
isOrientationChanged = true;
return null; //as you are not returning an object you are not leaking memory here
}
#Override
protected void onPause() {
hand.removeCallbacks(runThread);
super.onPause();
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindDrawables(findViewById(R.id.RootView));
System.gc();
}
private void unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
Log.d("onDestroy","Inside loop to getting child "+((ViewGroup) view).getChildAt(i));
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
hand.removeCallbacks( runThread);
}
/** The run thread. */
Thread runThread = new Thread() {
#Override
public void run() {
timeView.setText("Time Left: " + timeLeftVal);
:
:
:
} else {
changeColor();
:
:
hand.postDelayed(runThread, GET_DATA_INTERVAL);
}
}
};
/**
* Change color.
*/
private void changeColor() {
colorButton.setBackgroundDrawable(drawableList.get(randomNum));
}
In onCreate method, creating a drawable list and initializing it on first load.
Using Thread to set the button image background randomly
Calling unbindDrawables() method onDestroy so that on orientation change old view will be removed from memory.
hand.removeCallbacks(runThread) is also being called in onPause method
returned null in onRetainNonConfigurationInstance()
I have fixed the problem.
Small mistake resulted in this big issue. I have used Thread instead of Runnable in Handler. Hence, removeCallback didn't work as expected.
Hope the following links help:
Eclipse Memory Analyser-Article
Youtube Video
Google search for: "Google IO 2011 Memory management for Android Apps"

Splashscreen is only showed sometimes

I defined a splashscreen the following way:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExceptionHandler.register(this);
setFullscreen();
splashScreen();
}
private void splashScreen() {
runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(R.layout.splashscreen);
splash = (ImageView) findViewById(R.id.splashscreenLayer);
startSplashTime = new Date();
}
});
new LoadingThread().start();
}
private class LoadingThread extends Thread {
#Override
public void run() {
checkNetwork();
}
}
Somewhere at specific conditions in the checkNetwork() method, the stopSplash method is called:
public void stopSplash() {
Message msg = new Message();
msg.what = STOPSPLASH;
Date endSplashTime = new Date();
long time = endSplashTime.getTime() - startSplashTime.getTime();
System.out.println("Time Splashscreen was displayed: " + time);
if (time < SPLASH_MIN_TIME) {
long delay = SPLASH_MIN_TIME - time;
System.out.println("Delay Splashscreen for: " + delay);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
splashHandler.sendMessage(msg);
} else {
System.out.print("Show Splashscreen now");
splashHandler.sendMessage(msg);
}
}
private Handler splashHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case STOPSPLASH:
splash.setVisibility(View.GONE);
break;
}
super.handleMessage(msg);
}
};
The problem is, sometimes (maybe 1 of 10) if I started the app directly from Eclipse, the Splashscreen isn't showed, but instead just a black screen.
Other problem: if i restart the app, e.g. after onDestroy() was called after clicking the back button on the device, the Splashscreen is almost never shown.
Any hints why?
My assumption: could it be, that the LoadingThread starts "faster" than the Runnable, and so the network staff is done before the Splashscreen is set?
You might try using a CountdownTimer in your implementation. On your first activity, start a CountdownTimer that checks in onTick() every so often for a synchronized boolean finishedLoading with some kind of timeout in onFinish() (15 seconds or something), while your loading is done in another thread that sets finishedLoading to true when it is finished.
Maybe the splash screen isnt being terminated before the v=next activity starts.. just a thought..

Categories

Resources