android development with arduino - java

So I am new to Java and android development. So far I have been creating an app that is able to connect and interface with an arduino. I have a method that is able to read the data from the arduino (in bytes ) and then print the data as a string in UTF-8....However, I simply want this method to read and interpret the data, and have the interpreted data to be callable from another method, say button from android. Following is code that reads the data.
public class MainActivity extends AppCompatActivity {
public final String Action_USB_Permission = "com.example.myapplication.USB_PERMISSION";
UsbManager usbManager;
UsbDevice device;
UsbSerialDevice serial;
UsbDeviceConnection connection;
String data;
String adata;
TextView textView;
Button tempButton
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0) {
try {
data = new String(arg0, "UTF-8"); //edit (removed String in "String data =" )
} catch (UnsupportedEncodingException e) {
e.getStackTrace();
}
}
};
// Serial codes and commands
public void pushcmd(String command) { //command for serial
serial.write(command.getBytes());
}
public void gettemp() {
pushcmd("T\n");
serial.read(mCallback);
adata = data;
}
//This is for the app creation i think
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
usbManager = (UsbManager) getSystemService(this.USB_SERVICE);
tempButton = (Button) findViewById(R.id.buttontemp);
}
public void onClickTemp(View view) { //This is the command to print data
gettemp();
tvAppend(textView, "\n Measured temperature \n" + adata);
}
private void tvAppend(TextView tv, CharSequence text) {
final TextView ftv = tv;
final CharSequence ftext = text;
runOnUiThread(new Runnable() {
#Override
public void run() {
ftv.append(ftext);
}
});
}
}
tvAppend is a method that prints the string on a textview on the screen.
I got the libraries from https://github.com/felHR85/UsbSerial and it says to simply reference it with
serial.read(mcallback), I have tried the command, but I receive a "measured temperaturenull" then the measurement is printed after, which is from the onReceivedData method . Any suggestions would be greatly appreciated.Or if I'm not clear, let me know, I'll try to clear things up some more.
Edit: I added my tvAppend method, defined a textview field and a button. I am also pointing out that I don't have the whole program included, I followed the implementation from all about circuits http://www.allaboutcircuits.com/projects/communicate-with-your-arduino-through-android/ Thanks again for the feedback
COMMENT about edit: when the code is changed to how it is above. the adata is not displayed, only "Measured temperature".

I think you're confusing yourself with the flow of data here.
You click a button on the app
It calls pushcmd to the Arduino
The Arduino sends some data back at some unknown point in the future
You read that data and update the TextView
Now, with that logic, the code could be structured like so. (Feel free to re-organize back into your app how you want).
public void onClickTemp(View view) {
gettemp();
// No value of "adata" or "data" is guaranteed here
}
public void gettemp() {
pushcmd("T\n");
serial.read(mCallback); // asynchronous callback
// No value of "adata" or "data" is guaranteed here, either
}
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0) {
try {
// Here, you are guaranteed some data
String data = new String(arg0, "UTF-8");
tvAppend(textView, "\n Measured temperature \n" + data);
} catch (UnsupportedEncodingException e) {
e.getStackTrace();
}
}
};
Or, if you want to fold that all into one method, then
public void onClickTemp(View view) {
pushcmd("T\n");
serial.read(new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0) {
try {
// Here, you are guaranteed some data
String data = new String(arg0, "UTF-8");
tvAppend(textView, "\n Measured temperature \n" + data);
} catch (UnsupportedEncodingException e) {
e.getStackTrace();
}
}
});
}

Related

My current code takes a JSON response, parses it, then displays the value to an activity, all in one function. How do I separate them into threads?

(note: I'm using the Android Volley library for the network connection)
public class PostureActivity extends AppCompatActivity {
private static final String LOG_TAG = PostureActivity.class.getName();
private static final String EMB_URL = "https://api.thingspeak.com/channels/xxxxxxx/feed/last.json?round=1";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
connect(); // call at the start
final Handler handler = new Handler();
Runnable scrape = new Runnable() {
#Override
public void run() {
connect(); // call every x ms
handler.postDelayed(this, 3000);
}
};
handler.postDelayed(scrape, 3000);
}
private void connect() {
MySingleton.getInstance(this.getApplicationContext()).getRequestQueue();
JsonObjectRequest collectData = new JsonObjectRequest(
Request.Method.GET, // HTTP method
EMB_URL, // URL string that returns the desired JSON // TODO: change appropriate url
null, // optional JSON to send as request
response -> { // retrieved data
try {
JSONObject myResponse = new JSONObject(response.toString());
// TODO: cast to double to show the average
String ultrasonic = myResponse.getString("field1");
String flex1 = myResponse.getString("field2");
String flex2 = myResponse.getString("field3");
TextView neck = findViewById(R.id.neck_number);
TextView back = findViewById(R.id.back_number);
TextView butt = findViewById(R.id.butt_number);
neck.setText(ultrasonic);
back.setText(flex1);
butt.setText(flex2);
} catch (JSONException e) { // what if response is null?
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Response values are empty.", Toast.LENGTH_LONG).show();
finishAffinity();
finishAndRemoveTask();
}
},
error -> { // retrieved error/failure
error.printStackTrace();
Toast.makeText(getApplicationContext(), "Could not connect to website.", Toast.LENGTH_LONG).show();
finishAffinity();
finishAndRemoveTask();
}
);
MySingleton.getInstance(this).addToRequestQueue(collectData);
}
As you can see, connect() essentially retrieves, parses, and displays the data, and I run it via a handler. How do split the code so that this entire function doesn't simply populate the UI thread? I'm not very familiar with handler/loopers or java threads outside of async tasks, so I was hoping that I could be pointed in the right direction as to how to optimize the function better.

Parsing JSON and adding objects to array only working on second button press?

I am having an issue with my Android Studio application in that I am trying to parse JSON data from a URL and create objects "Director" with the data and then store each object in an array. The problem is that when I press the button to start the method that does this, Logcat shows that at the end of the method nothing was added to the array. However, when I press the button a second time they get added to the array. Below is my code:
public class MainActivity extends AppCompatActivity implements MainAdapter.OnCompanyClickedListener {
private Button search;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Button to start method
search = (Button) findViewById(R.id.btnSearch);
search.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
searchCompanyDirectors("02293426");
}
});
}
//Parse JSON File From API and Create Directors
public void searchCompanyDirectors(final String companyNumber){
Thread thread = new Thread(new Runnable(){
#Override
public void run(){
HttpClient httpClient = new HttpClient();
try{
final String response = httpClient.run("https://MyApiURL"+companyNumber);
runOnUiThread(new Runnable(){
#Override
public void run(){
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray array = jsonObject.getJSONArray("items");
for (int i = 0; i < array.length();i++){
JSONObject o = array.getJSONObject(i);
String appointment = o.getString("links");
String parsedAppointment = parseApp(appointment);
Director director = new Director(o.getString("name"),parsedAppointment);
Director.directorList.add(director);
}
Log.d("tag1",Director.directorList.toString());
}catch (JSONException e){
e.printStackTrace();
}
}
});
}
catch (Exception ex){
ex.printStackTrace();
}
}
});
thread.start();
Log.d("tag2",Director.directorList.toString());
}
//Parse Returned String From JSON
public String parseApp(String appointment){
String[] arrayDirectors = appointment.split("/",3);
String[] split = arrayDirectors[2].split("\\\\");
return split[0];
}
}
#Override
public void onCompanyClicked(int position){
//Do stuff with directorlist...
}
My Director Class:
public class Director {
private String name;
private String appointment;
public static List<Director> directorList = new ArrayList<>();
public Director (String name, String appointment){
this.name = name;
this.appointment = appointment;
}
public String getName() {
return name;
}
}
Logcat "tag1" output on first button press:
[Director1, Director2, Director3]
Logcat "tag2" output on the first button press:
[]
Logcat "tag1" output on the second button press:
[Director1, Director2, Director3, Director1, Director2, Director3]
Logcat "tag2" output on the second button press:
[Director1, Director2, Director3]
The problem with this arises when I try to make use of the directorList in the last method (it does stuff based on the directorList array), however because the array is empty when the method is finished on the first button press, it doesn't do what it is supposed to do. I am also unsure as to why Logcat "tag2" is showing the the values being added to the array in the middle of the method and then the array being empty at the end of the method whereas Logcat "tag1" is showing the values being added?

How to convert UTF-8 to String in Java

I am stuck here because after making the convertion from byte to String I works with append method but if I want to use setText instead of append, I get no text shown on my phone. And I don't want to write text next to the last one.
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0) {
String data = null;
try {
data = new String(arg0 , "UTF-8");
tvAppend(mostrarEntradaAnalogica, data);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
};
public void tvAppend(TextView tv, String text) {
final TextView ftv = tv;
final String ftext = text;
runOnUiThread(new Runnable() {
#Override
public void run() {
ftv.append(ftext);
}
});
}

Android Translation application using yandex api showing result in emulator text view but not in real device

I am trying to make a translation application from English to Bangla using Yandex API.
It works fine in the emulator but in the real device it shows result for only one word in the text view but when writing a sentence it shows null / nothing.
I think the problem is buffer overflow but don't know how to fix it for the real device. Here are some reference pictures. In the emulator the result works fine:
In the real device it shows empty in text view:
But it works fine when a single word is used in real device.
Here is the code for my Asynctask:
public class
TranslatorBackgroundTask extends AsyncTask<String, Void, String> {
//Declare Context
Context ctx;
//Set Context
TranslatorBackgroundTask(Context ctx){
this.ctx = ctx;
}
String resultString;
#Override
protected String doInBackground(String... params) {
//String variables
String textToBeTranslated = params[0];
String languagePair = params[1];
String jsonString;
try {
//Set up the translation call URL
String yandexKey = "trnsl.1.1.20170823T130435Z.79a583874abfc8ff.61e23593359fdc92452e69a3d5ec05347fc4180b";
String yandexUrl = "https://translate.yandex.net/api/v1.5/tr.json/translate?key=" + yandexKey
+ "&text=" + textToBeTranslated + "&lang=" + languagePair;
URL yandexTranslateURL = new URL(yandexUrl);
//Set Http Conncection, Input Stream, and Buffered Reader
HttpURLConnection httpJsonConnection = (HttpURLConnection) yandexTranslateURL.openConnection();
InputStream inputStream = httpJsonConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//Set string builder and insert retrieved JSON result into it
StringBuilder jsonStringBuilder = new StringBuilder();
while ((jsonString = bufferedReader.readLine()) != null) {
jsonStringBuilder.append(jsonString + "\n");
}
//Close and disconnect
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
inputStream.close();
httpJsonConnection.disconnect();
//Making result human readable
resultString = jsonStringBuilder.toString().trim();
//Getting the characters between [ and ]
resultString = resultString.substring(resultString.indexOf('[')+1);
resultString = resultString.substring(0,resultString.indexOf("]"));
//Getting the characters between " and "
resultString = resultString.substring(resultString.indexOf("\"")+1);
resultString = resultString.substring(0,resultString.indexOf("\""));
Log.d("Translation Result:", resultString);
return jsonStringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//String text = String.valueOf(resultString);
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String result) {
MainActivity.tvTranslatedText.setText(resultString);
Toast.makeText(ctx, resultString, Toast.LENGTH_LONG).show();
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
And the code for the main activity:
public class MainActivity extends AppCompatActivity{
Context context=this;
private static final int REQUEST_CODE = 1234;
static TextView tvTranslatedText;
EditText etUserText;
Button buTranslate;
Button buSpeak;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_activity_main);
tvTranslatedText = (TextView)findViewById(R.id.tvTranslatedText);
etUserText = (EditText)findViewById(R.id.etUserText);
buTranslate = (Button)findViewById(R.id.buTranslate);
buSpeak = (Button)findViewById(R.id.buSpeak);
}
public void buTranslate(View view) {
//Default variables for translation
String textToBeTranslated = "";
textToBeTranslated= etUserText.getText().toString();
String languagePair = "en-bn"; //English to bengali ("<source_language>-<target_language>")
//Executing the translation function
Translate(textToBeTranslated,languagePair);
}
//Function for calling executing the Translator Background Task
void Translate(String textToBeTranslated, String languagePair){
TranslatorBackgroundTask translatorBackgroundTask= new TranslatorBackgroundTask(context);
String translationResult = "";
translationResult = String.valueOf(translatorBackgroundTask.execute(textToBeTranslated,languagePair)); // Returns the translated text as a String
Log.d("Translation Result",translationResult); // Logs the result in Android Monitor
}
//Speak button activities
public void buSpeak(View view) {
startVoiceRecognitionActivity();
}
private void startVoiceRecognitionActivity()
{
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak to translate");
startActivityForResult(intent, REQUEST_CODE);
}
/**
* Handle the results from the voice recognition activity.
*/
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
if (data != null) {
//pull all of the matches
ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String topResult = matches.get(0);
EditText AutoText = (EditText) findViewById(R.id.etUserText);
AutoText.setText(topResult);
}
}
}
}
The error message:
Caused by: com.google.android.apps.gsa.shared.exception.GsaIOException: Error code: 393238 | Buffer overflow, no available space.
Why didn't you add a listener to your sample code?
Try adding these on onCreate in MainActivity:
buTranslate.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
buTranslate(view);
}
}
);
Update:
There was another issue. Emulators on android sdk 16 don't show Unicode properly. Thats why you don't see your results, as those are Unicodes. Try Log to print your resultString.

Trying to circumvent NetworkOnMainThreadException on AsyncTask because of ProgressDialog

I have the following problem. I am using the DropBox SDK to upload a file to dropbox which works fine. When the file is being uploaded (inside an AsyncTask) a ProgressDialog is being shown with a cancel button, still fine here. What is not working fine is, when the cancel button gets pressed a NetworkOnMainThreadException is being raised. I am new to Android programming but I am suspecting it has something to do with the ProgressDialog which is in the constructor. Since it is not in the "doInBackground" part.
Tried to fix it with implementing the OnDismissListener and doing the abortion onDismiss but still no luck. I am getting the error when "mRequest.abort()" is called.
Thanks in advance for any answers!
So here is my code
public class DropBoxUpload extends AsyncTask<Void, Long, Boolean> implements OnDismissListener {
private DropboxAPI<?> mApi;
private String mPath;
private File mFile;
private long mFileLen;
private UploadRequest mRequest;
private Context mContext;
private final ProgressDialog mDialog;
private String mErrorMsg;
public DropBoxUpload(Context context, DropboxAPI<?> api, String dropboxPath, File file) {
// We set the context this way so we don't accidentally leak activities
mContext = context.getApplicationContext();
mFileLen = file.length();
mApi = api;
mPath = dropboxPath;
mFile = file;
mDialog = new ProgressDialog(context);
mDialog.setMax(100);
mDialog.setMessage("Uploading " + file.getName());
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setProgress(0);
mDialog.setButton("Cancel", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// This will cancel the putFile operation
mDialog.dismiss();
}
});
mDialog.setCancelable(true);
mDialog.setOnDismissListener(this);
mDialog.show();
}
#Override
protected Boolean doInBackground(Void... params) {
try {
// By creating a request, we get a handle to the putFile operation,
// so we can cancel it later if we want to
FileInputStream fis = new FileInputStream(mFile);
String path = mPath + mFile.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
new ProgressListener() {
#Override
public long progressInterval() {
// Update the progress bar every half-second or so
return 500;
}
#Override
public void onProgress(long bytes, long total) {
publishProgress(bytes);
}
});
if (mRequest != null) {
mRequest.upload();
return true;
}
} catch (DropboxUnlinkedException e) {
// This session wasn't authenticated properly or user unlinked
mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) {
// File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) {
// We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen,
// but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) {
// Unauthorized, so we should unlink them. You may want to
// automatically log the user out in this case.
} else if (e.error == DropboxServerException._403_FORBIDDEN) {
// Not allowed to access this
} else if (e.error == DropboxServerException._404_NOT_FOUND) {
// path not found (or if it was the thumbnail, can't be
// thumbnailed)
} else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
// user is over quota
} else {
// Something else
}
// This gets the Dropbox error, translated into the user's language
mErrorMsg = e.body.userError;
if (mErrorMsg == null) {
mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry
mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) {
// Unknown error
mErrorMsg = "Unknown error. Try again.";
} catch (FileNotFoundException e) {
}
return false;
}
#Override
protected void onProgressUpdate(Long... progress) {
int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
mDialog.setProgress(percent);
}
#Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
}
#Override
public void onDismiss(DialogInterface arg0) {
// TODO Auto-generated method stub
mRequest.abort();
}
}
You cannot access the mRequest object from the main UI thread as this is what is responsible for the network operation. That is why you get a NetworkOnMainThreadException when you call mRequest.abort().
You should modify your code such that you use AsyncTask.cancel on dialog dismissal and check for isCancelled periodically in your doInBackground and call mRequest.abort() when the task is cancelled.
you should call the cancel method to stop your uploading process.
ast.cancel(true);
where ast is your asynctask object

Categories

Resources