My application gets serial USB input with FTDI chip, I managed to do it.
As I press a button I get 3 input float type numbers displayed on my app.
Here is the onClick:
public void onReadClick(View view) throws UnsupportedEncodingException {
// [FTDriver] Create Read Buffer
byte[] rbuf = new byte[27]; // 1byte <--slow-- [Transfer Speed] --fast--> 4096 byte
// [FTDriver] Read from USB Serial
len = mSerial.read(rbuf);
for(i=0; i<len; i++) {
mText1.append((char) rbuf[i]);
}
Text = mText1.toString();
String[] Splited = Text.split("#");
Long r = Long.parseLong(Splited[1], 16);
Float f = Float.intBitsToFloat(r.intValue());
d1 = f.toString();
val.setText(d1);
Long r2 = Long.parseLong(Splited[2], 16);
Float f2 = Float.intBitsToFloat(r2.intValue());
d2 = f2.toString();
val2.setText(d2);
Long r3 = Long.parseLong(Splited[3], 16);
Float f3 = Float.intBitsToFloat(r3.intValue());
d3 = f3.toString();
val3.setText(d3);
Monitor.setText(Splited[1]);
Monitor2.setText(Splited[2]);
Monitor3.setText(Splited[3]);
}
It was very good until I wanted to make my application do this steps outside of the button onClick, so i take it outside (I'm really new with java) :
package com.application.i;
import java.io.UnsupportedEncodingException;
import jp.ksksue.driver.serial.FTDriver;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class FTDI extends Activity{
// [FTDriver] Object
FTDriver mSerial;
// [FTDriver] Permission String
private static final String ACTION_USB_PERMISSION = "jp.ksksue.tutorial.USB_PERMISSION";
Button btnRead;
TextView Monitor,Monitor2,Monitor3;
TextView val,val2,val3;
TextView indicator;
StringBuffer mText1 = new StringBuffer();
int i,len;
String Text=null;
boolean doIT = true;
String number=null,number2=null,number3=null, hadar1=null, hadar2=null, hadar3=null, d1=null, d2=null, d3=null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ftdisub);
btnRead = (Button) findViewById(R.id.btnRead);
Monitor = (TextView)findViewById(R.id.onitor);
Monitor2 = (TextView)findViewById(R.id.onitor2);
Monitor3 = (TextView)findViewById(R.id.onitor3);
val = (TextView)findViewById(R.id.dec);
val2 = (TextView)findViewById(R.id.dec2);
val3 = (TextView)findViewById(R.id.dec3);
indicator = (TextView)findViewById(R.id.indicator);
// [FTDriver] Create Instance
mSerial = new FTDriver((UsbManager)getSystemService(Context.USB_SERVICE));
// [FTDriver] setPermissionIntent() before begin()
PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
mSerial.setPermissionIntent(permissionIntent);
// [FTDriver] Open USB Serial
if(mSerial.begin(FTDriver.BAUD115200)) {
btnRead.setEnabled(true);
Toast.makeText(this, "connected", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "cannot connect", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onResume() {
if (doIT==true){
// [FTDriver] Create Read Buffer
byte[] rbuf = new byte[27]; // 1byte <--slow-- [Transfer Speed] --fast--> 4096 byte
// [FTDriver] Read from USB Serial
len = mSerial.read(rbuf);
for(i=0; i<len; i++) {
mText1.append((char) rbuf[i]);
}
Text = mText1.toString();
String[] Splited = Text.split("#");
Long r = Long.parseLong(Splited[1], 16);
Float f = Float.intBitsToFloat(r.intValue());
d1 = f.toString();
val.setText(d1);
Long r2 = Long.parseLong(Splited[2], 16);
Float f2 = Float.intBitsToFloat(r2.intValue());
d2 = f2.toString();
val2.setText(d2);
Long r3 = Long.parseLong(Splited[3], 16);
Float f3 = Float.intBitsToFloat(r3.intValue());
d3 = f3.toString();
val3.setText(d3);
Monitor.setText(Splited[1]);
Monitor2.setText(Splited[2]);
Monitor3.setText(Splited[3]);
doIT=false;
}
};
#Override
public void onDestroy() {
super.onDestroy();
// [FTDriver] Close USB Serial
mSerial.end();
}
public void onReadClick(View view) throws UnsupportedEncodingException {
doIT=true;
}
}
I just want to read it once without the Button, and for each additive time next, as i press the button the application will do the process again.
The main thing is that i want it outside of the button, especially to do it once as FTDI activity is being activated.
The FTDI activity is activated as I click a button on my application main screen.
problem:
When i click the FTDI button on the main screen it should start FTDI activity and display 3 float numbers, instead the application is finished with error and close message.
LogCat:
05-15 11:04:46.855: E/AndroidRuntime(9598): FATAL EXCEPTION: main
05-15 11:04:46.855: E/AndroidRuntime(9598): java.lang.RuntimeException: Unable to resume activity {com.application.i/com.application.i.FTDI}: java.lang.NullPointerException
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2616)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2644)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2130)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.ActivityThread.access$600(ActivityThread.java:140)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1227)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.os.Handler.dispatchMessage(Handler.java:99)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.os.Looper.loop(Looper.java:137)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.ActivityThread.main(ActivityThread.java:4898)
05-15 11:04:46.855: E/AndroidRuntime(9598): at java.lang.reflect.Method.invokeNative(Native Method)
05-15 11:04:46.855: E/AndroidRuntime(9598): at java.lang.reflect.Method.invoke(Method.java:511)
05-15 11:04:46.855: E/AndroidRuntime(9598): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
05-15 11:04:46.855: E/AndroidRuntime(9598): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
05-15 11:04:46.855: E/AndroidRuntime(9598): at dalvik.system.NativeStart.main(Native Method)
05-15 11:04:46.855: E/AndroidRuntime(9598): Caused by: java.lang.NullPointerException
05-15 11:04:46.855: E/AndroidRuntime(9598): at jp.ksksue.driver.serial.FTDriver.read(FTDriver.java:271)
05-15 11:04:46.855: E/AndroidRuntime(9598): at jp.ksksue.driver.serial.FTDriver.read(FTDriver.java:257)
05-15 11:04:46.855: E/AndroidRuntime(9598): at com.application.i.FTDI.onResume(FTDI.java:83)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1188)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.Activity.performResume(Activity.java:5280)
05-15 11:04:46.855: E/AndroidRuntime(9598): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2606)
05-15 11:04:46.855: E/AndroidRuntime(9598): ... 12 more
P.S : this FTDI activity works fine:
public class FTDI extends Activity{
// [FTDriver] Object
FTDriver mSerial;
// [FTDriver] Permission String
private static final String ACTION_USB_PERMISSION = "jp.ksksue.tutorial.USB_PERMISSION";
Button btnRead;
TextView Monitor,Monitor2,Monitor3;
TextView val,val2,val3;
TextView indicator;
StringBuffer mText1 = new StringBuffer();
int i,len;
String Text=null;
boolean doIT = true;
String number=null,number2=null,number3=null, hadar1=null, hadar2=null, hadar3=null, d1=null, d2=null, d3=null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ftdisub);
btnRead = (Button) findViewById(R.id.btnRead);
Monitor = (TextView)findViewById(R.id.onitor);
Monitor2 = (TextView)findViewById(R.id.onitor2);
Monitor3 = (TextView)findViewById(R.id.onitor3);
val = (TextView)findViewById(R.id.dec);
val2 = (TextView)findViewById(R.id.dec2);
val3 = (TextView)findViewById(R.id.dec3);
indicator = (TextView)findViewById(R.id.indicator);
// [FTDriver] Create Instance
mSerial = new FTDriver((UsbManager)getSystemService(Context.USB_SERVICE));
// [FTDriver] setPermissionIntent() before begin()
PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
mSerial.setPermissionIntent(permissionIntent);
// [FTDriver] Open USB Serial
if(mSerial.begin(FTDriver.BAUD115200)) {
btnRead.setEnabled(true);
Toast.makeText(this, "connected", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "cannot connect", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onDestroy() {
super.onDestroy();
// [FTDriver] Close USB Serial
mSerial.end();
}
public void onReadClick(View view) throws UnsupportedEncodingException {
// [FTDriver] Create Read Buffer
byte[] rbuf = new byte[27]; // 1byte <--slow-- [Transfer Speed] --fast--> 4096 byte
// [FTDriver] Read from USB Serial
len = mSerial.read(rbuf);
for(i=0; i<len; i++) {
mText1.append((char) rbuf[i]);
}
Text = mText1.toString();
String[] Splited = Text.split("#");
Long r = Long.parseLong(Splited[1], 16);
Float f = Float.intBitsToFloat(r.intValue());
d1 = f.toString();
val.setText(d1);
Long r2 = Long.parseLong(Splited[2], 16);
Float f2 = Float.intBitsToFloat(r2.intValue());
d2 = f2.toString();
val2.setText(d2);
Long r3 = Long.parseLong(Splited[3], 16);
Float f3 = Float.intBitsToFloat(r3.intValue());
d3 = f3.toString();
val3.setText(d3);
Monitor.setText(Splited[1]);
Monitor2.setText(Splited[2]);
Monitor3.setText(Splited[3]);
}
}
You have to check the life cycle of your activity. I guess your mSerial is not initialized when the on resume method is called and try to do the stuff in on start
Related
I was using an integer for the money factor in this little test app but I realized that long was more appropriate and I changed the code so that money is a long instead of an int and I changed SharedPreferences appropriately as well, however it does not work wheras it did when I used int. Thank you for the help!
public class Home extends AppCompatActivity {
SharedPreferences pref;
SharedPreferences.Editor editor;
Intent intent;
TextView home_money_view;
long money; // this is the variable that is causing problems
int initial;
final long TEST = (long)-1;
int gold_pieces;
int gold_price = 50;
TimerTask timerTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
home_money_view = (TextView) findViewById(R.id.home_money_view)
pref = getApplicationContext().getSharedPreferences("MY_PREFS", MODE_PRIVATE);
editor = pref.edit();
money = pref.getLong("temp_money",Long.MIN_VALUE); // get value
if (money==Long.MIN_VALUE){
money=0;
}
gold_pieces = pref.getInt("temp_gold",-1);
if (gold_pieces==-1){
gold_pieces=0;
}
initial = pref.getInt("initial",0);
money+=initial;
editor.putInt("initial",0);
editor.commit();
home_money_view = (TextView) findViewById(R.id.home_money_view);
home_money_view.setText(money+"");
editor.commit();
}
public void backToSplash(View view){
intent = new Intent(Home.this,BusinessSelector.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
public void goToSecondView(View view){
long temp_money = money;
editor.putLong("temp_money",temp_money); // set value
int temp_gold = gold_pieces;
editor.putInt("temp_gold",temp_gold);
editor.commit();
intent = new Intent(Home.this,SecondView.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
public void goToOtherView(View view) {
long temp_money = money;
editor.putLong("temp_money",temp_money); // set value
int temp_gold = gold_pieces;
editor.putInt("temp_gold", temp_gold);
editor.commit();
intent = new Intent(Home.this, Next.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
}
Logcat:
04-13 19:01:03.675 12896-12896/com.exampleryancocuzzo.ryan.markettycoon E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.exampleryancocuzzo.ryan.markettycoon/com.exampleryancocuzzo.ryan.markettycoon.Home}: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
at android.app.ActivityThread.access$600(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
at android.app.SharedPreferencesImpl.getLong(SharedPreferencesImpl.java:228)
at com.exampleryancocuzzo.ryan.markettycoon.Home.onCreate(Home.java:56)
at android.app.Activity.performCreate(Activity.java:4466)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
at android.app.ActivityThread.access$600(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
I am working on a financial app and i have to use BigDecimal to calculate currency.Now I am trying to make one entrance activity which is searching in the SharedPreferences for a previous registration and if their is one it starts another activity , if not it starts the registration activity.The problem is the registration activity causes NumberFormatException Error while I am trying to construct a new object of time Profit (the Profit class contains BigDecimal field).Also I am not quite sure that I am using SharedPreferences right.I am not quite sure that my idea and my coding are fine because I am new at android development and i am stuck with this problem so I am giving you all the classes.
the Registration activity:
public class Registration extends Activity {
private static String enteredPassword;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final EditText password1 = (EditText) findViewById(R.id.password1);
final EditText password2 = (EditText) findViewById(R.id.password2);
final EditText availability = (EditText) findViewById(R.id.availability);
EditText profitEditText = (EditText) findViewById(R.id.profit);
Spinner spinner = (Spinner) findViewById(R.id.period_spinner);
Button registrationButton = (Button) findViewById(R.id.registrationButton);
DatePicker picker = (DatePicker) findViewById(R.id.thePicker);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.periods_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
final String balance = availability.getText().toString().replace(",",".");
String profitPeriod = ((Period) spinner.getSelectedItem()).name();
final Profit profit = new Profit("regular_profit", profitEditText.getText().toString(),
profitPeriod ,picker);
registrationButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (password1.getText().toString().equals(password2.getText().toString())) {
enteredPassword = password1.getText().toString();
Repository.setPassword(enteredPassword, mContext);
}
Repository.setBalance(balance, mContext);
Repository.setProfit(profit, mContext);
}
});
}
}
the profit activity
public class Profit {
private Date mProfitDate;
private Date mNextProfitDate;
private BigDecimal value;
public final static String TITLE = "title";
public final static String PERIOD = "period";
Profit(String title,String value, String period, DatePicker picker) {
this.mTitle = title;
if(value!=null){this.value = new BigDecimal(value);}else{ this.value = new BigDecimal("0.0");};
this.mPeriod = Period.class.cast(period);
this.mProfitDate = Repository.getDateFromPicker(picker);
}
public long getNextProfitDate(Date profitDate, Period period){
long unixProfitDate = profitDate.getTime() / 1000L;
long nextProfitDate=0;
switch (period){
case DAILY:
nextProfitDate = DateUtils.DAY_IN_MILLIS/1000 + unixProfitDate;
break;
case WEEKLY:
nextProfitDate = DateUtils.WEEK_IN_MILLIS/1000 + unixProfitDate;
break;
case MONTHLY:
Date dateNow = new Date();
dateNow.getTime();
nextProfitDate = Repository.monthsToSeconds(Calendar.getInstance()
.get(Calendar.MONTH)) + unixProfitDate;
break;
case YEARLY:
nextProfitDate = DateUtils.YEAR_IN_MILLIS/1000 + unixProfitDate;
break;
}
return nextProfitDate;
}
}
the entrance activity
public class EnterActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter);
CountDownTimer timer = new CountDownTimer(3000, 100) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
if(Repository.getPassword(mContext.getApplicationContext()).equals("No Value")){
Intent registrationIntent = new Intent(mContext, Registration.class);
startActivity(registrationIntent);
}
else{
Intent configurationIntent = new Intent(mContext, Configuration.class);
startActivity(configurationIntent);
}
}
}.start();
}
}
the Repository
public class Repository {
public static SharedPreferences sharedPreferences;
private static SharedPreferences getPrefs(Context context) {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
public static String getPassword(Context context){
return getPrefs(context).getString(PASSWORD,"No Value");
}
public Repository() {
}
public static void setPassword(String password, Context context){
SharedPreferences.Editor editor = getPrefs(context).edit();
editor.putString(PASSWORD, password);
editor.commit();
}
public static void setBalance(String balance, Context context){
SharedPreferences.Editor editor = getPrefs(context).edit();
editor.putString(BALANCE, balance);
editor.commit();
}
public static void setProfit(Profit profit, Context context){
SharedPreferences.Editor editor = getPrefs(context).edit();
editor.putString(BALANCE, profit.getValue().toString());
editor.commit();
}
}
the output
E/AndroidRuntime: FATAL EXCEPTION: main
E/AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{/.Registration}: java.lang.NumberFormatException: Bad offset/length: offset=0 len=0 in.length=0
E/AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
E/AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
E/AndroidRuntime: at android.app.ActivityThread.access$600(ActivityThread.java:123)
E/AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime: at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:4424)
E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime: Caused by: java.lang.NumberFormatException: Bad offset/length: offset=0 len=0 in.length=0
E/AndroidRuntime: at java.math.BigDecimal.<init>(BigDecimal.java:282)
E/AndroidRuntime: at java.math.BigDecimal.<init>(BigDecimal.java:438)
E/AndroidRuntime: at .Profit.<init>(Profit.java:41)
E/AndroidRuntime: at .Registration.onCreate(Registration.java:57)
E/AndroidRuntime: at android.app.Activity.performCreate(Activity.java:4466)
E/AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
E/AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
E/AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
E/AndroidRuntime: at android.app.ActivityThread.access$600(ActivityThread.java:123)
E/AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime: at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:4424)
E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
You instantiate a Profit in only one place in the code you presented:
Profit profit = new Profit("regular_profit", profitEditText.getText().toString(),
profitPeriod, picker);
If that causes a NumberFormatException then it must come from this code in the Profit constructor:
if(value!=null){this.value = new BigDecimal(value);}else{ this.value = new BigDecimal("0.0");};
Since the value String will have come from invoking toString() on an object, you can rely on it to not be null (and anyway, if it were null then you would end up at new BigDecimal("0.0"), and you can verify for yourself that that works fine). That leaves us with new BigDecimal(value) as the culprit. The docs for this constructor provide details of the expected format of the argument string. If the argument does not comply with that format then a NumberFormatException will be thrown.
Among the more likely malformed strings that one might imagine in a scenario such as you describe is an empty string, which is not the same as null in Java. Given that the text is coming from a UI field, you also have to watch out for fun and difficult-to-spot malformations such as leading and trailing whitespace.
Perhaps it would be better to write the affected part of the constructior like so:
if (value != null) {
value = value.trim();
this.value = value.length() == 0 ? BigDecimal.ZERO : new BigDecimal(value);
} else {
this.value = BigDecimal.ZERO;
}
Do note that even with that change, this constructor will still throw NumberFormatException in the event of other kinds of malformation. Wherever you are uncertain about the validity of the data, you should be prepared to handle such an exception.
You aren't parsing your string to a Big Decimal correctly.
The following in your Profit contructor:
if(value!=null)
{
this.value = new BigDecimal(value);
}
else
{
this.value = new BigDecimal("0.0");
}
Needs to parse the string to a BigDecimal. Like the following where this.value is of type BigDecimal:
this.value = (BigDecimal) decimalFormat.parse(value);
Also keep in mind that decimalFormat.parse can throw a ParseException. You will need to handle it with try/catch or throw it.
I'm using achartengine to plot a graph in my app. I declare points in a table in table.xml which is connected to Table.java. Now should my graph get this points and use them. My graph is coded in Graph.java and gets called through Graphdisplay.java.
EDIT2: I changed the code a bit. First of all I added the code from Graphdisplay.java into the onCreate method of Graph.java and deleted Graphdisplay.java.
Second I added some get and set methods like here in the first answer in Graph.java and get the data from Table.java in the onCreate method.
Third I put the get method in the GraphicalView
Graph.java:
public class Graph extends Activity{
//only for x1 for now
public double ds_x1;
public Double getX1(){return this.ds_x1;}
public void setX1(Double ds_x1){this.ds_x1=ds_x1;}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.graph);
//getting the data from Table.java
ds_x1 = getIntent().getExtras().getDouble("s_x1");
Graph line = new Graph();
final GraphicalView gView = line.getView(getApplicationContext());
LinearLayout layout = (LinearLayout) findViewById(R.id.chart);
layout.addView(gView);
}
public GraphicalView getView(Context context) {
Double d_x1 = getX1();
ArrayList<Double> xList = new ArrayList<Double>();
double x1 = d_x1;
xList.add(x1);
double x2 = 2;
xList.add(x2);
double x3 = 3;
xList.add(x3);
ArrayList<Double> yList = new ArrayList<Double>();
double y1 = 1;
yList.add(y1);
double y2 = 2;
yList.add(y2);
double y3 = 3;
yList.add(y3);
XYSeries series = new XYSeries("List");
for (int i = 0; i < xList.size(); i++) {
series.add(i, xList.get(i), yList.get(i));
}
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
dataset.addSeries(series);
XYSeriesRenderer renderer = new XYSeriesRenderer();
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
return ChartFactory.getLineChartView(context, dataset, mRenderer);
}
}
Table.java: Now Double not Strings
EditText x1 = (EditText) findViewById(R.id.x1);
EditText x2 = (EditText) findViewById(R.id.x2);
EditText x3 = (EditText) findViewById(R.id.x3);
EditText y1 = (EditText) findViewById(R.id.y1);
EditText y2 = (EditText) findViewById(R.id.y2);
EditText y3 = (EditText) findViewById(R.id.y3);
Button b_continue = (Button) findViewById(R.id.b_continue);
b_continue.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Double s_x1 = Double.parseDouble(x1.getText().toString());
Double s_x2 = Double.parseDouble(x2.getText().toString());
Double s_x3 = Double.parseDouble(x3.getText().toString());
Double s_y1 = Double.parseDouble(y1.getText().toString());
Double s_y2 = Double.parseDouble(y2.getText().toString());
Double s_y3 = Double.parseDouble(y3.getText().toString());
Intent myIntent = new Intent(view.getContext(), Graph.class);
myIntent.putExtra("s_x1", s_x1);
myIntent.putExtra("s_x2", s_x2);
myIntent.putExtra("s_x3", s_x3);
myIntent.putExtra("s_y1", s_y1);
myIntent.putExtra("s_y2", s_y2);
myIntent.putExtra("s_y3", s_y3);
startActivity(myIntent);
}
});
Logcat:
08-29 14:31:00.720 17322-17322/test.com.myApp E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity
ComponentInfo{test.com.myApp/test.com.myApp.Graph}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2295)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349)
at android.app.ActivityThread.access$700(ActivityThread.java:159)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at test.com.myApp.Graph.getView(Graph.java:96)
at test.com.myApp.Graph.onCreate(Graph.java:44)
at android.app.Activity.performCreate(Activity.java:5372)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349)
at android.app.ActivityThread.access$700(ActivityThread.java:159)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)
Problem: When clicking on the button to get to the graph the app crashes instead of showing the graph with the values! I figured out that the problem is that it isn't a defined value like double double = 5.0. aChartEngine has got problems with the values wich are getting entered in the table.
There's also a method to set "double extras" to your intent:
Intent android.content.Intent.putExtra(String name, double value)
and a method to get double extras:
double android.content.Intent.getDoubleExtra(String name, double defaultValue)
so you don't need to parse the strings...
But yeah, in general that's the right approach. Or do you have a specific problem with it?
EDIT:
use this instead of valueOf:
double y2 = Double.parseDouble(getIntent().getStringExtra("s_y2"))
EDIT2, try:
Button b_continue = (Button) findViewById(R.id.b_continue);
b_continue.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String s_x1 = x1.getText().toString();
String s_x2 = x2.getText().toString();
String s_x3 = x3.getText().toString();
String s_y1 = y1.getText().toString();
String s_y2 = y2.getText().toString();
String s_y3 = y3.getText().toString();
Intent myIntent2 = new Intent(view.getContext(), Graph.class);
myIntent2.putExtra("s_x1", s_x1);
myIntent2.putExtra("s_x2", s_x2);
myIntent2.putExtra("s_x3", s_x3);
myIntent2.putExtra("s_y1", s_y1);
myIntent2.putExtra("s_y2", s_y2);
myIntent2.putExtra("s_y3", s_y3);
Intent myIntent = new Intent(view.getContext(), Graphdisplay.class);
startActivity(myIntent);
}
});
This has only happened once but I'm a bit concerned with it. I was testing the app changing the orientation and the application crashed. Never happened before so just want to see if anyone else has had this issue and what I could do to fix it. Please see the log below:
05-15 12:13:07.304: E/AndroidRuntime(2596): FATAL EXCEPTION: main
05-15 12:13:07.304: E/AndroidRuntime(2596): java.lang.RuntimeException: Unable to start activity ComponentInfo{com./.hearing.InstructionsActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class <unknown>
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3740)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.ActivityThread.access$700(ActivityThread.java:141)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.os.Handler.dispatchMessage(Handler.java:99)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.os.Looper.loop(Looper.java:137)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.ActivityThread.main(ActivityThread.java:5103)
05-15 12:13:07.304: E/AndroidRuntime(2596): at java.lang.reflect.Method.invokeNative(Native Method)
05-15 12:13:07.304: E/AndroidRuntime(2596): at java.lang.reflect.Method.invoke(Method.java:525)
05-15 12:13:07.304: E/AndroidRuntime(2596): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
05-15 12:13:07.304: E/AndroidRuntime(2596): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
05-15 12:13:07.304: E/AndroidRuntime(2596): at dalvik.system.NativeStart.main(Native Method)
05-15 12:13:07.304: E/AndroidRuntime(2596): Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class <unknown>
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.createView(LayoutInflater.java:620)
05-15 12:13:07.304: E/AndroidRuntime(2596): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.onCreateView(LayoutInflater.java:669)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:694)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
05-15 12:13:07.304: E/AndroidRuntime(2596): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:267)
05-15 12:13:07.304: E/AndroidRuntime(2596): at com.actionbarsherlock.internal.ActionBarSherlockNative.setContentView(ActionBarSherlockNative.java:133)
05-15 12:13:07.304: E/AndroidRuntime(2596): at com.actionbarsherlock.app.SherlockActivity.setContentView(SherlockActivity.java:229)
05-15 12:13:07.304: E/AndroidRuntime(2596): at .InstructionsActivity.onCreate(InstructionsActivity.java:40)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.Activity.performCreate(Activity.java:5133)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
05-15 12:13:07.304: E/AndroidRuntime(2596): ... 12 more
05-15 12:13:07.304: E/AndroidRuntime(2596): Caused by: java.lang.reflect.InvocationTargetException
05-15 12:13:07.304: E/AndroidRuntime(2596): at java.lang.reflect.Constructor.constructNative(Native Method)
05-15 12:13:07.304: E/AndroidRuntime(2596): at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.view.LayoutInflater.createView(LayoutInflater.java:594)
05-15 12:13:07.304: E/AndroidRuntime(2596): ... 26 more
05-15 12:13:07.304: E/AndroidRuntime(2596): Caused by: java.lang.OutOfMemoryError
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:503)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:356)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:800)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.content.res.Resources.loadDrawable(Resources.java:2105)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.widget.ImageView.<init> (ImageView.java:127)
05-15 12:13:07.304: E/AndroidRuntime(2596): at android.widget.ImageView.<init>(ImageView.java:117)
05-15 12:13:07.304: E/AndroidRuntime(2596): ... 29 more
So to me it looks like it had a issue with inflating the layout. I don't see how because I'd changed the orientation about 4 times before it crashed.
A bit further down there is a java.lang.OutOfMemoryError error so I assume this has caused the android.view.InflateException.
Any help of this would be greatly appreciated. Thanks
Edit:
Here is the activity it crashed on:
public class InstructionsActivity extends MenuActivity {
private ScrollView mScrollButton;
private WebView topContent;
private WebView bottomContent;
private boolean mMoreInfoTop = false;
private int mYdelta = 0;
private int mBottomOffset = 0;
private ActivityHelper activityHelper;
private boolean isPhone;
private String topHtml;
private String bottomHtml;
private String flag;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.instructions);
activityHelper = new ActivityHelper(this);
activityHelper.getScreenTag(R.id.instructions);
activityHelper.getDrawableFolder();
activityHelper.setTitleTextSize(R.string.Hearing_Test, true);
isPhone = activityHelper.isPhone();
if(isPhone){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
mScrollButton = (ScrollView) findViewById(R.id.scroll_view);
flag = String.valueOf(getIntent().getStringExtra("Flag"));
if (flag.equalsIgnoreCase("firstInstructions")) {
topHtml = this.getString(R.string.top_content);
Button startTest = (Button) findViewById(R.id.test);
startTest.setText(R.string.start_test);
}else if(flag.equalsIgnoreCase("secondInstructions")){
topHtml = this.getString(R.string.switch_file);
Button startTest = (Button) findViewById(R.id.test);
startTest.setText(R.string.continue_test);
}
bottomHtml = this.getString(R.string.bottom_content);
topContent = (WebView) findViewById(R.id.top_content);
topContent.setBackgroundColor(0);
bottomContent = (WebView) findViewById(R.id.bottom_content);
bottomContent.setBackgroundColor(0);
bottomContent.getSettings().setUseWideViewPort(false);
topContent.loadUrl("file:///android_asset/html/" + topHtml);
bottomContent.loadUrl("file:///android_asset/html/" + bottomHtml);
getMargins();
setResult(RESULT_OK);
}
public void getMargins() {
ViewTreeObserver viewTreeObserver = topContent.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
#Override
public boolean onPreDraw() {
int topHeight = topContent.getMeasuredHeight();
int bottomHeight = bottomContent.getMeasuredHeight();
if (isPhone) {
if (topHeight != 0) {
Log.d("Web View Height", "Continue Height: "
+ topHeight);
if (mScrollButton != null) {
RelativeLayout instructions = (RelativeLayout) findViewById(R.id.more_info);
instructions.post(mAddMargin);
topContent.getViewTreeObserver()
.removeOnPreDrawListener(this);
}
topContent.getViewTreeObserver()
.removeOnPreDrawListener(this);
}
} else if (!isPhone) {
if (topHeight != 0 && bottomHeight != 0) {
Log.d("Web View Height", "top Height: " + topHeight
+ "bottom height:" + bottomHeight);
RelativeLayout instructions = (RelativeLayout) findViewById(R.id.more_info);
instructions.post(mAddMargin);
topContent.getViewTreeObserver()
.removeOnPreDrawListener(this);
}
}
return false;
}
});
}
Runnable mAddMargin = new Runnable() {
#Override
public void run() {
try {
int marginHeight;
if (isPhone) {
marginHeight = activityHelper.getMarginHeight(R.id.more_info, R.id.bottom_content);
RelativeLayout buttonHolder = (RelativeLayout) findViewById(R.id.instructionsLayout);
mBottomOffset = buttonHolder.getBottom();
mScrollButton = (ScrollView) findViewById(R.id.scroll_view);
mYdelta = mScrollButton.getScrollY();
activityHelper.setMarginHeight(marginHeight, R.id.instructionsLayout);
} else if (!isPhone) {
// int sideMargin = activityHelper.getWebViewMargin(R.id.bottom_content);
// if(sideMargin != 0){
// activityHelper.setWebViewMargin(sideMargin, R.id.top_content);
// activityHelper.setWebViewMargin(sideMargin, R.id.bottom_content);
// }
marginHeight = activityHelper.getMarginHeight(R.id.more_info, R.id.bottom_content);
activityHelper.setMarginHeight(marginHeight, R.id.more_info);
}
} catch (Exception e) {
Log.e("Scroll View", "Couldn't run mAddMargin:", e);
}
}
};
public void onClickHandler(View aView) {
if (flag.equalsIgnoreCase("firstInstructions")) {
Intent intent = new Intent(this, HearingTestActivity.class);
startActivity(intent);
}else if(flag.equalsIgnoreCase("secondInstructions")){
finish();
}
}
public void infoView(View aView) {
Intent intent = new Intent(this, InfoActivity.class);
startActivity(intent);
}
public void onMoreInstructions(View aView) {
// Scroll the start button to the top of the screen.
mScrollButton.post(new Runnable() {
#Override
public void run() {
if (mMoreInfoTop) {
mMoreInfoTop = false;
mScrollButton.scrollTo(0, mYdelta);
} else {
mMoreInfoTop = true;
mScrollButton.scrollTo(0, mBottomOffset);
}
}
});
}
}
Do you need any other code from me?
New code:
This is my updated code:
public void getMargins() {
ViewTreeObserver viewTreeObserver = topContent.getViewTreeObserver();
x = new OnPreDrawListener() {
#Override
public boolean onPreDraw() {
int topHeight = topContent.getMeasuredHeight();
int bottomHeight = bottomContent.getMeasuredHeight();
if (isPhone) {
if (topHeight != 0) {
Log.d("Web View Height", "Continue Height: "
+ topHeight);
if (mScrollButton != null) {
RelativeLayout instructions = (RelativeLayout) findViewById(R.id.more_info);
instructions.post(mAddMargin);
topContent.getViewTreeObserver()
.removeOnPreDrawListener(this);
}
topContent.getViewTreeObserver()
.removeOnPreDrawListener(this);
}
} else if (!isPhone) {
if (topHeight != 0 && bottomHeight != 0) {
Log.d("Web View Height", "top Height: " + topHeight
+ "bottom height:" + bottomHeight);
RelativeLayout instructions = (RelativeLayout) findViewById(R.id.more_info);
instructions.post(mAddMargin);
topContent.getViewTreeObserver()
.removeOnPreDrawListener(this);
}
}
return false;
}
};
viewTreeObserver.addOnPreDrawListener(x);
}
Here I now save the listener to a variable x.
onDestroy method:
#Override
protected void onDestroy() {
super.onDestroy();
if(x != null){
topContent.getViewTreeObserver()
.removeOnPreDrawListener(x);
}
}
I then check to see if the variable x is null, if it is remove the listener?
Am I correct in this? Thanks
This looks like a classic memory leak situation.
Most likely, you're keeping a live reference to some UI component (or maybe even the Activity) in a listener or an AsyncTask which causes the Activity instance to be leaked (kept from being garbage collected) when you turn the device -- because due to orientation change another Activity instance is created and the old one is supposed to be destroyed and collected.
After you turn the device 3 times you have 4 copies of everything -- hence the OOM.
Another possibility is that you're decoding a Bitmap manually and not calling recycle() on it when your Activity is destroyed.
And yep, as the guys suggest in the comments, nothing more specific can be said until you post your code.
UPD Oh, yeah, now that the code is there, most likely the source of your problem is somewhere in the anonymous classes (the OnPreDrawListener and the Runnable). First, not all conditions guarantee that your listener gets removed -- I'm not sure this is exactly what's causing the leak but consider checking if the listener is still around and removing it in onDestroy() also. But the more general idea is that any untrivial anonymous and nested non-static classes are a bad idea because they store an implicit reference to the instance of the containing class -- in this case, the Activity. Should anything unsuspected happen with any of that code -- it can cause the containing instance to be retained.
So, safest strategy is to avoid using non-static nested (let alone anonymous) classes unless the logic they carry is so trivial that you're absolutely sure about the implications.
My go-to approach is to create static nested Listeners (or AsyncTasks, Runnables, etc.) that refer to everything they need via WeakReference. Most obvious solution is to store the reference to the Activity in a member WeakReference<InstructionsActivity> and check it for null when the corresponding code gets executed. If it returns null - that means your Activity got destroyed, just return immediately.
UPD
Also, consider using Eclipse MAT (here's a good article, google around for more) to detect memory leaks. It has an awesome ability to run OQL queries on an HPROF dump file, this way you can query for your suspect leaked class (the activity class) and if there are two or more of them -- you know you have a problem. It will even show you what objects keep them retained -- look for paths to GC root
This may be causes of configuration change add below property in your mainifest file inside the activity.you can change as per your requirement
android:configChanges="orientation|screenSize|keyboard|screenLayout"
I have been able to export my code into an application and use the Tess-Two file from this tutorial
to integrate the tesseract into it. But now I'm facing problems; when the picture is sent to the tesseract it just returns the same random characters each time: 'f' wig, W fin. A. " 5' ' ,{ >>zv' ' ~" > ';>'. What seems to be the problem?
ImageView iv;
TextView tv;
protected Bitmap _image;
protected Bitmap bmp;
public static String The_path = "/mnt/sdcard/DCIM/100MEDIA/TESS.jpg";
public static String lang = "eng";
public static final String DATA_PATH = Environment.getExternalStorageDirectory().toString() + "/SimpleAndroidOCR/";
private int pageSegmentationMode = TessBaseAPI.PageSegMode.PSM_AUTO;
#Override
public void onCreate(Bundle savedInstanceState) {
try {
AssetManager assetManager = getAssets();
InputStream in = assetManager.open("tessdata/eng.traineddata");
//GZIPInputStream gin = new GZIPInputStream(in);
OutputStream out = new FileOutputStream(DATA_PATH + "tessdata/eng.traineddata");
//Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
//while ((len = gin.read(buf)) > 0) {
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
//gin.close();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
iv = (ImageView) findViewById(R.id.imageView1);
tv = (TextView) findViewById(R.id.textView1);
Button but = (Button) findViewById(R.id.button1);
Button but2 = (Button) findViewById(R.id.button2);
but.setOnClickListener(new OnClickListener() {
public void onClick(View v){
//File file = new File( _path );
//Uri outputFileUri = Uri.fromFile( file );
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
//intent.putExtra( MediaStore.EXTRA_OUTPUT, outputFileUri );
startActivityForResult(intent, 0);
}
});
but2.setOnClickListener(new OnClickListener() {
public void onClick(View v){
TessBaseAPI baseApi = new TessBaseAPI();
baseApi.setDebug(true);
baseApi.setPageSegMode(pageSegmentationMode);
baseApi.init(DATA_PATH, lang);
// DATA_PATH = Path to the storage
// lang for which the language data exists, usually "eng"
try {
baseApi.setImage(ReadFile.readBitmap(bmp));
String recognizedText = baseApi.getUTF8Text();
txt(recognizedText);
} catch(RuntimeException e) {
}
baseApi.end();
}
private void txt(String txt) {
// TODO Auto-generated method stub
tv.setText(txt);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(The_path, options);
try {
ExifInterface exif = new ExifInterface(The_path);
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int rotate = 0;
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
if (rotate != 0) {
// Getting width & height of the given image.
int w = bitmap.getWidth();
int h = bitmap.getHeight();
// Setting pre rotate
Matrix mtx = new Matrix();
mtx.preRotate(rotate);
// Rotating Bitmap
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
}
bitmap = toGrayscale(bitmap);
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
} catch (IOException e) {
}
_image = (Bitmap) data.getExtras().get("data");
iv.setImageBitmap(_image);
bmp = bitmap;
} public static Bitmap toGrayscale(Bitmap bmpOriginal){
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
here is the new log cat after adding the grayscale function:
(receiving a new set of reoccurring random characters)
01-26 10:21:36.973: D/libEGL(1389): loaded /system/lib/egl/libEGL_adreno200.so
01-26 10:21:36.973: D/libEGL(1389): loaded /system/lib/egl/libGLESv1_CM_adreno200.so
01-26 10:21:36.973: D/libEGL(1389): loaded /system/lib/egl/libGLESv2_adreno200.so
01-26 10:21:36.983: I/Adreno200-EGL(1389): <eglInitialize:269>: EGL 1.4 QUALCOMM build: Nondeterministic AU_full_mako_PARTNER-ANDROID/JB-MR1- DEV_CL2946718_release_AU (CL2946718)
01-26 10:21:36.983: I/Adreno200-EGL(1389): Build Date: 11/04/12 Sun
01-26 10:21:36.983: I/Adreno200-EGL(1389): Local Branch:
01-26 10:21:36.983: I/Adreno200-EGL(1389): Remote Branch: m/partner-android/jb-mr1-dev
01-26 10:21:36.983: I/Adreno200-EGL(1389): Local Patches: NONE
01-26 10:21:36.983: I/Adreno200-EGL(1389): Reconstruct Branch: NOTHING
01-26 10:21:37.043: D/OpenGLRenderer(1389): Enabling debug mode 0
01-26 10:21:45.502: E/BitmapFactory(1389): Unable to decode stream: java.io.FileNotFoundException: /mnt/sdcard/DCIM/100MEDIA/TESS.jpg: open failed: ENOENT (No such file or directory)
01-26 10:21:45.502: E/JHEAD(1389): can't open '/mnt/sdcard/DCIM/100MEDIA/TESS.jpg'
01-26 10:21:45.512: D/AndroidRuntime(1389): Shutting down VM
01-26 10:21:45.512: W/dalvikvm(1389): threadid=1: thread exiting with uncaught exception (group=0x417b0930)
01-26 10:21:45.522: E/AndroidRuntime(1389): FATAL EXCEPTION: main
01-26 10:21:45.522: E/AndroidRuntime(1389): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { act=inline-data (has extras) }} to activity {com.cam.calc/cam.calc.Main}: java.lang.NullPointerException
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.deliverResults(ActivityThread.java:3319)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.handleSendResult(ActivityThread.java:3362)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.access$1100(ActivityThread.java:141)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1282)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.os.Handler.dispatchMessage(Handler.java:99)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.os.Looper.loop(Looper.java:137)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.main(ActivityThread.java:5039)
01-26 10:21:45.522: E/AndroidRuntime(1389): at java.lang.reflect.Method.invokeNative(Native Method)
01-26 10:21:45.522: E/AndroidRuntime(1389): at java.lang.reflect.Method.invoke(Method.java:511)
01-26 10:21:45.522: E/AndroidRuntime(1389): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
01-26 10:21:45.522: E/AndroidRuntime(1389): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
01-26 10:21:45.522: E/AndroidRuntime(1389): at dalvik.system.NativeStart.main(Native Method)
01-26 10:21:45.522: E/AndroidRuntime(1389): Caused by: java.lang.NullPointerException
01-26 10:21:45.522: E/AndroidRuntime(1389): at cam.calc.Main.onActivityResult(Main.java:388)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.Activity.dispatchActivityResult(Activity.java:5293)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.deliverResults(ActivityThread.java:3315)
01-26 10:21:45.522: E/AndroidRuntime(1389): ... 11 more
You need to process the images before OCR, at least convert the image to black&white (gray scale) can enhance the result :
bitmap = toGrayscale(bitmap);
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
you can user OpenCV or any Image Processing Library, for for simple task like grayscale its enopugh to use
import android.graphics.*;
public static Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
Also if the image is too large you may need to crop the image and get the area that contain the characters & numbers you want to recognize, its also make OCR engine job more easier/more accuracy and sometimes its prevents you from OutOfMemoryException.