I have a ListView that pulls data from a ContentProvider via a CursorLoader.
I want to have a button that reads out the data in the ListView when pressed. The tricky part is that the data in the ListView is continually updating (data from the ContentProvider changes periodically every few seconds) and the data for each row might update while the audio is being read.
How do I make it such that the latest data is read each time it is updated?
Try the following code:
private boolean ttsEnabled= true;
private Thread ttsThread = null;
private ListView lastState = null;
public void enableTTS() {
ttsEnabled = true;
ttsThread = new Thread(ttsRunnable);
ttsThread.start();
}
public void disableTTS() {
ttsEnabled = false;
try {
ttsThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private Runnable ttsRunnable = new Runnable() {
#Override
public void run() {
while (ttsEnabled) {
if (lastState == null || !lastState.equals(yourListView)) {
// List view updated, tts here
lastState = yourListView;
}
}
}
};
Related
What is the proper/correct way to handle taking a picture with the Camera2 api when a device doesn't have autofocus functionality?
Based on responses to other questions the code I have so far is:
private void setUpCameraOutputs(int width, int height){
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
//Check if autofocus is available on camera
int[] afAvailableModes = characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
if (afAvailableModes.length == 0 || (afAvailableModes.length == 1
&& afAvailableModes[0] == CameraMetadata.CONTROL_AF_MODE_OFF)) {
mAutoFocusSupported = false;
} else {
mAutoFocusSupported = true;
}
//end autofocus check
//additional camera setup code here that is not relevant to this problem
}
private void takePicture() {
if (mAutoFocusSupported) {
lockFocus();
} else {
captureStillPicture();
}
}
private void lockFocus() {
try {
// This is how to tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_START);
// Tell #mCaptureCallback to wait for the lock.
mState = STATE_WAITING_LOCK;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
//setFlashMode(captureBuilder);
setFlashOn(captureBuilder);
// Orientation
int captureRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(captureRotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
unlockFocus();
synchronized(lock) {
captureComplete(captureRotation);
}
}
};
mCaptureSession.stopRepeating();
mCaptureSession.abortCaptures();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
Within the else brackets, should the code ;
modify the mPreviewRequestBuilder to remove any mention of AF before the call to capture?
change the mState before any calls to capture to appropriately reflect a status change indicating that it is about to take a picture (but without a LOCK)?
call a unique mCaptureSession similar to the way lockFocus does, instead of the captureStillPicture (that also has references to CONTROL_AF_MODE)?
I have a problem to update my UI by use of the notifyDataSetChanged method.
If I do this without using thread it will work.
The following class implements the Runnable interface which gets data through Web API and it updates my db.
After it updates the data I want to update my UI, but it wont work with the thread concept.
public class ExchangeRateUpdateRunnable implements Runnable {
private ExchangeRateDatabase db;
private CustomAdapter adapter;
public ExchangeRateUpdateRunnable(ExchangeRateDatabase db, CustomAdapter adapter) { this.db = db; this.adapter = adapter;}
#Override
public void run() {
refresh();
}
private void refresh() {
List<ExchangeRate> exchangeRates = new ArrayList<>();
String urlString = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
try {
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
InputStream inputStream = connection.getInputStream();
String encoding = connection.getContentEncoding();
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setInput(inputStream, encoding);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if ("Cube".equals(parser.getName())) {
if(parser.getAttributeValue(null,"currency") != null) {
String currency = parser.getAttributeValue(null , "currency");
String rate = parser.getAttributeValue(null, "rate");
ExchangeRate exchangeRate = new ExchangeRate(currency, new Double(rate));
exchangeRates.add(exchangeRate);
}
}
}
eventType = parser.next();
}
inputStream.close();
updateDB(exchangeRates);
} catch (Exception e) {
e.printStackTrace();
}
}
private void updateDB ( List<ExchangeRate> exchangeRates) {
db.setExchangeRate(exchangeRates);
adapter.notifyDataSetChanged();
}
}
And this is a method that is implemented on the mainActivity class, which listens to menu items (This means as soon as I click on the item it will call this function). It implements the Thread that runs on the background and updates my data:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
Intent intent = new Intent(this, CurrencyListActivity.class);
startActivity(intent);
case R.id.refresh:
new Thread(new ExchangeRateUpdateRunnable(db,adapter)).start();
//new RefreshRates(db,adapter).refresh(); //single Threaded
}
return super.onOptionsItemSelected(item);
}
If I put the codeline: adapter.notifyDataSetChanged(); on the method of the mainActivity class it will only work when I click the button twice. But I want to update my UI as soon as I click on the button.
How do I solve this problem ?
Is this a Thread problem or something that Android cant handle by use of Threads?
Thanks in advance.
You won't be able to notifytheDataSetChange from thread, you might need to use the handler.post or runOnUiThread to achieve this.
Example
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("updating...", "");
Notifydatasetchanged()
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
I created an image gallery app.
My requirment: I want to select multiple images, click on button cut and come back to activity which displays all folders (ImageGallery.java). Now, I want to select a folder and paste all the selected images in that folder, on selecting the folder.
What is happening? I am able to select images using my app and come back to activity which displays all folders but not able to move them using my app.
I put the code for moving images in a background thread using task. I select images from one folder, come back to the activity which displays all the folders (ImageGallery.java) and select the folder to which the images are to be moved. But when I try to move images, selected images do not move to other folder being selected, on selecting a folder. I guess the code inside AsyncTask isn't even getting executed.
How do I fix it ?
PhotosActivity.java (Activity used to select images):
int int_position;
private GridView gridView;
GridViewAdapter adapter;
ArrayList<Model_images> al_menu = new ArrayList<>();
private ArrayList<Integer> mSelected = new ArrayList<>();
boolean boolean_folder;
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(final AdapterView<?> parent, View view, final int position, long id) {
if (mSelected.contains(position)) {
mSelected.remove(position);
view.setBackgroundColor(Color.TRANSPARENT);// remove item from list
// update view (v) state here
// eg: remove highlight
} else {
mSelected.add(position);
view.setBackgroundColor(Color.LTGRAY);// add item to list
// update view (v) state here
// eg: add highlight
}
buttoncut.setVisibility(View.VISIBLE);
button2.setVisibility(View.VISIBLE);
button3.setVisibility(View.VISIBLE);
button4.setVisibility(View.VISIBLE);
button5.setVisibility(View.VISIBLE);
buttoncut.setOnClickListener(
new View.OnClickListener() {
public void onClick(View view) {
buttoncut.setVisibility(View.GONE);
button2.setVisibility(View.GONE);
button3.setVisibility(View.GONE);
button4.setVisibility(View.GONE);
button5.setVisibility(View.GONE);
Intent moveIntent = new Intent(PhotosActivity.this, ImageGallery.class);
moveIntent.putIntegerArrayListExtra("selected_images", mSelected);
startActivity(moveIntent);
}
});
ImageGallery.java:
public static ArrayList<Model_images> al_images = new ArrayList<>();
ArrayList<Integer> selectedImages = new ArrayList<>();
boolean boolean_folder;
Adapter_PhotosFolder obj_adapter;
GridView gv_folder;
private static final int REQUEST_PERMISSIONS = 100;
int int_position;
selectedImages = getIntent().getIntegerArrayListExtra("selected_images");
if (selectedImages != null) {
Toast.makeText(ImageGallery.this, "This code gets executed", Toast.LENGTH_SHORT)
.show();
new LongOperation().execute();
}
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
for (int image : selectedImages) {
File sourceImage = new File(al_images.get(int_position).getAl_imagepath().get(image)); //returns the image File from model class to be moved.
File destinationImage = new File(al_images.get(int_position).getStr_folder(), ".jpeg");
try {
copyOrMoveFile(sourceImage, destinationImage, true);
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
//Method to move the file
private void copyOrMoveFile(File file, File dir, boolean isCopy) throws IOException {
File newFile = new File(dir, file.getName());
FileChannel outChannel = null;
FileChannel inputChannel = null;
try {
outChannel = new FileOutputStream(newFile).getChannel();
inputChannel = new FileInputStream(file).getChannel();
inputChannel.transferTo(0, inputChannel.size(), outChannel);
inputChannel.close();
if (!isCopy)
file.delete();
} finally {
if (inputChannel != null) inputChannel.close();
if (outChannel != null) outChannel.close();
}
}
}
You have to use Intent.ACTION_MEDIA_SCANNER_SCAN_FILE for updating media store.
Inside AsyncTask -> onPostExecute method fetch latest images from MediaStore
private class LongOperation extends AsyncTask<String, Void, File> {
#Override
protected File doInBackground(String... params) {
for (String imagePath : selectedImages) {
File sourceImage = new File(imagePath); //returns the image File from model class to
// be// moved.
File destinationImage = new File(al_images.get(int_position).getDirectoryPath() +
File.separator + sourceImage.getName());
try {
moveFile(sourceImage, destinationImage, true);
return destinationImage;
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(File file) {
super.onPostExecute(file);
getBaseContext().sendBroadcast(new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
fn_imagespath(); // Call method to fetch latest images.
}
}, 1000); // additional delay time of 1 sec to update media scanner
}
}
Just a better method to move file
private void moveFile(File file_Source, File file_Destination, boolean isCopy) throws IOException {
FileChannel source = null;
FileChannel destination = null;
if (!file_Destination.exists()) {
file_Destination.createNewFile();
}
try {
source = new FileInputStream(file_Source).getChannel();
destination = new FileOutputStream(file_Destination).getChannel();
long count = 0;
long size = source.size();
while ((count += destination.transferFrom(source, count, size - count)) < size) ;
if (!isCopy) {
file_Source.delete();
}
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
Not much changes in code added MediaScannerConnection. Give it a try .
private class LongOperation extends AsyncTask<String, Void, Integer> {
#Override
protected Integer doInBackground(String... params) {
int movedCount=0;
for (int i=0;i<selectedImages.size();i++) {
File sourceImage = new File(al_images.get(int_position).getAl_imagepath().get(i));
File destinationImage = new File(al_images.get(int_position).getStr_folder(), ".jpeg");
try {
boolean isMoved= copyOrMoveFile(sourceImage, destinationImage, true);
if(isMoved) {
movedCount++;
callMediaScanner(ImageGallery.this, destinationImage.getAbsolutePath());
}
} catch (IOException e) {
e.printStackTrace();
}
}
return movedCount;
}
#Override
protected void onPostExecute(Integer val) {
super.onPostExecute(val);
// Here you have to modify return type of doInBackground as per your convineance
if(val.intValue()==selectedImages.size()){
Log.e("Moved","Allfile moved");
}else{
Log.e("Moved","Some file missing");
}
}
public boolean copyOrMoveFile(File localFile, File destinationFile, boolean isCopy) {
FileChannel outputChannel = null;
FileChannel inputChannel = null;
try {
outputChannel = new FileOutputStream(destinationFile).getChannel();
inputChannel = new FileInputStream(localFile).getChannel();
inputChannel.transferTo(0, inputChannel.size(), outputChannel);
inputChannel.close();
if (!isCopy)
localFile.delete();
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
if (inputChannel != null) inputChannel.close();
if (outputChannel != null) outputChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
}
public void callMediaScanner(Context context, String path) {
MediaScannerConnection.scanFile(context,
new String[] { path }, null,null);
}
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();
}
}
});
}
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