I have an application which connects to an external sensor via Bluetooth Low Energy. I have the data coming in as a dynamic string which I have split into three strings, then I have the strings converted into doubles.
I have been trying to graph the doubles dynamically for weeks now with various chart libraries such as
aChartEngine
AndroidPlot
and ChartDroid
I decided to go with aChartEngine mainly because I found a dynamic sample app that graphs random data. I have been trying to implement this sample app into mine. Then I am hoping to adapt it to graph my sensor data doubles.
Here is the code I am trying to implement at the moment:
public class XYChartBuilder extends Activity {
public static final String TYPE = "type";
private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset();
private XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
private XYSeries mCurrentSeries;
private XYSeriesRenderer mCurrentRenderer;
private String mDateFormat;
private Button mNewSeries;
private Button mAdd;
private GraphicalView mChartView;
private int index = 0;
static double x = 0;
static double y = 0;
protected Update mUpdateTask;
#Override
protected void onRestoreInstanceState(Bundle savedState) {
super.onRestoreInstanceState(savedState);
mDataset = (XYMultipleSeriesDataset) savedState
.getSerializable("dataset");
mRenderer = (XYMultipleSeriesRenderer) savedState
.getSerializable("renderer");
mCurrentSeries = (XYSeries) savedState
.getSerializable("current_series");
mCurrentRenderer = (XYSeriesRenderer) savedState
.getSerializable("current_renderer");
mDateFormat = savedState.getString("date_format");
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("dataset", mDataset);
outState.putSerializable("renderer", mRenderer);
outState.putSerializable("current_series", mCurrentSeries);
outState.putSerializable("current_renderer", mCurrentRenderer);
outState.putString("date_format", mDateFormat);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_opengl_acc);
mRenderer.setApplyBackgroundColor(true);
mRenderer.setBackgroundColor(Color.argb(100, 50, 50, 50));
mRenderer.setAxisTitleTextSize(16);
mRenderer.setChartTitleTextSize(20);
mRenderer.setLabelsTextSize(15);
mRenderer.setLegendTextSize(15);
mRenderer.setMargins(new int[] { 20, 30, 15, 0 });
mRenderer.setZoomButtonsVisible(true);
mRenderer.setPointSize(10);
mRenderer.setXTitle("TIME");
mRenderer.setYTitle("y");
mRenderer.setShowGrid(true);
String seriesTitle = "Series " + (mDataset.getSeriesCount() + 1);
XYSeries series = new XYSeries(seriesTitle);
mDataset.addSeries(series);
mCurrentSeries = series;
XYSeriesRenderer renderer = new XYSeriesRenderer();
mRenderer.addSeriesRenderer(renderer);
renderer.setPointStyle(PointStyle.CIRCLE);
renderer.setFillPoints(true);
mCurrentRenderer = renderer;
mUpdateTask = new Update();
mUpdateTask.execute(this);
}
#Override
protected void onResume() {
super.onResume();
if (mChartView == null) {
LinearLayout layout = (LinearLayout) findViewById(R.id.chart);
mChartView = ChartFactory.getLineChartView(this, mDataset,
mRenderer);
mRenderer.setClickEnabled(true);
mRenderer.setSelectableBuffer(100);
mChartView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SeriesSelection seriesSelection = mChartView
.getCurrentSeriesAndPoint();
double[] xy = mChartView.toRealPoint(0);
if (seriesSelection == null) {
Toast.makeText(XYChartBuilder.this,
"No chart element was clicked",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(
XYChartBuilder.this,
"Chart element in series index "
+ seriesSelection.getSeriesIndex()
+ " data point index "
+ seriesSelection.getPointIndex()
+ " was clicked"
+ " closest point value X="
+ seriesSelection.getXValue() + ", Y="
+ seriesSelection.getValue()
+ " clicked point value X="
+ (float) xy[0] + ", Y="
+ (float) xy[1], Toast.LENGTH_SHORT)
.show();
}
}
});
mChartView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
SeriesSelection seriesSelection = mChartView
.getCurrentSeriesAndPoint();
if (seriesSelection == null) {
Toast.makeText(XYChartBuilder.this,
"No chart element was long pressed",
Toast.LENGTH_SHORT);
return false; // no chart element was long pressed, so
// let something
// else handle the event
} else {
Toast.makeText(XYChartBuilder.this,
"Chart element in series index "
+ seriesSelection.getSeriesIndex()
+ " data point index "
+ seriesSelection.getPointIndex()
+ " was long pressed",
Toast.LENGTH_SHORT);
return true; // the element was long pressed - the event
// has been
// handled
}
}
});
mChartView.addZoomListener(new ZoomListener() {
public void zoomApplied(ZoomEvent e) {
String type = "out";
if (e.isZoomIn()) {
type = "in";
}
System.out.println("Zoom " + type + " rate "
+ e.getZoomRate());
}
public void zoomReset() {
System.out.println("Reset");
}
}, true, true);
mChartView.addPanListener(new PanListener() {
public void panApplied() {
System.out.println("New X range=["
+ mRenderer.getXAxisMin() + ", "
+ mRenderer.getXAxisMax() + "], Y range=["
+ mRenderer.getYAxisMax() + ", "
+ mRenderer.getYAxisMax() + "]");
}
});
layout.addView(mChartView, new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
boolean enabled = mDataset.getSeriesCount() > 0;
} else {
mChartView.repaint();
}
}
private int generateRandomNum() {
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(100);
return randomInt;
}
protected class Update extends AsyncTask<Context, Integer, String> {
#Override
protected String doInBackground(Context... params) {
int i = 0;
while (true) {
try {
Thread.sleep(50);
x = x + 5;
y = generateRandomNum();
publishProgress(i);
i++;
} catch (Exception e) {
}
}
// return "COMPLETE!";
}
// -- gets called just before thread begins
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mCurrentSeries.add(x, y);
if (mChartView != null) {
mChartView.repaint();
}
Bitmap bitmap = mChartView.toBitmap();
try {
File file = new File(Environment.getExternalStorageDirectory(),
"test" + index++ + ".png");
FileOutputStream output = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 100, output);
} catch (Exception e) {
e.printStackTrace();
}
}
// -- called if the cancel button is pressed
#Override
protected void onCancelled() {
super.onCancelled();
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
}
and I have "joined it" to the relevant page on the app in the xml layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".demo.DemoAccelerometerSensorActivity" >
<sample.ble.sensortag.demo.DemoGLSurfaceView
android:id="#+id/gl"
android:layout_width="match_parent"
android:layout_height="93dp" />
<requestFocus />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="Now Recording Data to file. Press button to add name to file" />
<TextView
android:id="#+id/AccValues"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Accelerometer"
android:textAppearance="?android:textAppearanceLarge" />
<Button
android:id="#+id/baddNametoFile"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_gravity="left"
android:layout_marginTop="250dp"
android:layout_weight="1"
android:background="#c0c0c0"
android:text="Add Name to File" />
<Button
android:id="#+id/Stop"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_gravity="right"
android:layout_marginTop="250dp"
android:layout_weight="1"
android:background="#FF0000"
android:text="Stop Recording" />
<EditText
android:id="#+id/ETName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="190dp"
android:ems="10"
android:hint="Name Here"
android:inputType="textCapWords"
android:maxWidth="200dp" />
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="81dp"
android:layout_margin="10dp"
android:textAppearance="?android:textAppearanceMedium" />
<LinearLayout
android:id="#+id/chart"
android:layout_width="600dp"
android:layout_height="match_parent"
android:layout_marginTop="430dp"
android:orientation="vertical" >
</LinearLayout>
The problem I have implementing the project is that it does not show up in the app at all.
There are no errors. It just doesn't display. I am just wondering if anyone can help. Or if you know any other basic dynamic graph tutorials, maybe for implementing into an existing project. I am 15 (edit - 16 now) and have only started java in the last couple of months. I am still only at the basics. If you post any code could you please explain it.
Thanks in advance,
The problem is with your layout, it is not designed well.
Use something like the following. You may need to adjust few things.
Your layout is not showing properly on small screen devices.I have edited ur layout and now its showing on small devices also.Please adjust height and other things according to ur requirement.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/AccValues"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Accelerometer"
android:textAppearance="?android:textAppearanceLarge" />
<View
android:id="#+id/gl"
android:layout_width="match_parent"
android:layout_height="100dp" />
<requestFocus />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Now Recording Data to file. Press button to add name to file" />
<EditText
android:id="#+id/ETName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Name Here"
android:inputType="textCapWords"
android:maxWidth="200dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="#+id/baddNametoFile"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="left"
android:layout_weight="1"
android:background="#c0c0c0"
android:text="Add Name to File" />
<Button
android:id="#+id/Stop"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="right"
android:layout_weight="1"
android:background="#FF0000"
android:text="Stop Recording" />
</LinearLayout>
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ABSGS "
android:textAppearance="?android:textAppearanceMedium" />
<LinearLayout
android:id="#+id/chart"
android:layout_width="match_parent"
android:layout_height="164dp"
android:orientation="vertical" >
</LinearLayout>
</LinearLayout>
</FrameLayout>
Related
So I want to read the input of an EditText field. It is not working. I debugged it and I saw, that the EditText view was listed there. But when I printed it to the console, it was empty. I don't know why, because I did put a text in it. Also, the ID is right, and I really don't know what's wrong
Here is the View where the EditText is:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".counters.AddCounter">
<TextView
android:id="#+id/txtNewCounter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/allerta"
android:text="#string/addNewCounter"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btnSaveCounter"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="#font/allerta"
android:text="#string/save"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/txtCounterName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:fontFamily="#font/allerta"
android:text='#string/newCounterName'
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtNewCounter" />
<EditText
android:id="#+id/inpuTextNewCounterName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="10dp"
android:contentDescription="#string/name"
android:ems="10"
android:hint="#string/name"
android:inputType="textPersonName"
android:singleLine="true"
android:text="Cookies don't"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtCounterName" />
<TextView
android:id="#+id/txtCounterEntryValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:fontFamily="#font/allerta"
android:text="#string/entryNum"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/inpuTextNewCounterName" />
<EditText
android:id="#+id/numEntryNum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:ems="10"
android:hint="#string/number"
android:inputType="number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txtCounterEntryValue" />
</androidx.constraintlayout.widget.ConstraintLayout>
Here is my code to evaluate the form:
public class AddCounter extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_counter);
//Setting save button action listener
findViewById(R.id.btnSaveCounter).setOnClickListener(new ActionListeners().getSaveCounter());
}
public static void evaluateCounter(View view) throws NoNameException, NumberOutOfBoundException {
//Getting context
Context context = view.getContext();
//Counter Name
View viewEdit = View.inflate(context, R.layout.activity_add_counter, null);
EditText counterName = viewEdit.findViewById(R.id.inpuTextNewCounterName);
System.out.println("Cookies fly like:" + counterName.getText().toString() + "!");
//Input to string
String name = counterName.getText().toString();
//If no name was specified exception thrown
if (name.equals("")) {
throw new NoNameException(context.getString(R.string.noNameSpecified));
}
//get entry number
EditText numberView = View.inflate(context, R.layout.activity_add_counter, null).findViewById(R.id.numEntryNum);
//Number
int number = 0;
//If nothing specified
if (!(numberView.getText().toString().equals(""))) {
if (Integer.parseInt(numberView.getText().toString()) > 1000 || Integer.parseInt(numberView.getText().toString()) < -1000) {
throw new NumberOutOfBoundException(context.getString(R.string.numOutOfBound));
}
}
//New Counter Object
Counter counter = new Counter(number, name);
//storing counter
ToJson toJson = new ToJson();
toJson.storeCounter(counter, context);
}
}
As you can see here, this if-statement is always true.
To look, what the text looks like, I printed out a text:
System.out.println("Cookies fly like:" + counterName.getText().toString() + "!");
I did put a word in the input and the output is empty, as you can see here:
I/System.out: Cookies fly like:!
Here is my ActionListener:ยจ
public class ActionListeners {
private OnClickListener saveCounter = v -> {
try {
//Evaluate Counter
AddCounter.evaluateCounter(v);
} catch (NoNameException e) {
//If no name was specified
CounterMethods.makeSnackbar(v, Snackbar.LENGTH_SHORT, HapticFeedbackConstants.REJECT, v.getContext().getString(R.string.noNameSpecified));
e.printStackTrace();
} catch (NumberOutOfBoundException e) {
//If entry is higher or lower than available
CounterMethods.makeSnackbar(v, Snackbar.LENGTH_SHORT, HapticFeedbackConstants.REJECT, v.getContext().getString(R.string.numOutOfBound));
}
};
public OnClickListener getSaveCounter() {
return this.saveCounter;
}
}
As you can see, I did set the text to "Cookies can't fly" in the xml file, however, if I change the text to something different in the app, the output is the text I did set in the XML.
I/System.out: Cookies fly like:Cookies can't fly!
What is the problem?
try this
public class AddCounter extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_counter);
//declare Counter Name EditText
EditText counterName = findViewById(R.id.inpuTextNewCounterName);
//declare btnSaveCounter Button
Button btnSaveCounter = findViewById(R.id.btnSaveCounter);
//declare get entry number EditText
EditText numberView = findViewById(R.id.numEntryNum);
//btnSaveCounter setOnClickListener
btnSaveCounter.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
//Input to string
String name = counterName.getText().toString();
System.out.println("Cookies fly like:" + name + "!");
//If no name was specified
if (name.equals("")){
System.out.println( "getString(R.string.noNameSpecified)" );//todo
}
//If nothing specified
String numbrv = numberView.getText().toString();
if (!(numbrv.equals(""))){
if (Integer.parseInt(numbrv) > 1000 || Integer.parseInt(numbrv) < -1000) {
System.out.println( "getString(R.string.numOutOfBound)" );//todo
}
}
//Number
int number = 0;
//New Counter Object
Counter counter = new Counter(number, name);
//storing counter
ToJson toJson = new ToJson();
toJson.storeCounter(counter, context);
} });
}
}
I'm new to android development and I'm stuck with the following issue:
I have objects in a listView. When an item in the list is clicked a detailed page with the information appears. This worked fine until at some point the text was displayed only sometimes. When I go back and click on the very same item the text might get displayed correctly again (or not). I have done a textView.getText() and it displays the correct text in the logcat but the user can't actually see this text displayed in the app (at least not always). I wasn't able to pinpoint the mistake and I cannot reproduce the mistake regularly.
FYI: The genre gets displayed always. But title and author only sometimes.
I am grateful for any help! If you have any codestyle/bestpractice remarks please add those to your answers.
Below you can find the relevant code.
Best,
Marc
Activity passing the data
public class BooksActivity extends AppCompatActivity {
private SQLiteDatabase db;
private final BooksDBOpenHelper dbHelper = new BooksDBOpenHelper(this, DBConstants.DB_NAME, null, 1);
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_books);
TextView header = this.findViewById(R.id.tv_header);
header.setText(R.string.books_list);
ImageButton backButton = this.findViewById(R.id.toolbar_back_button);
backButton.setOnClickListener(view -> finish());
}
#Override
protected void onStart() {
super.onStart();
db = dbHelper.getWritableDatabase();
ArrayList<CustomBookItem> bookItems = new ArrayList<>();
String table_name = DBConstants.Books.TABLE_NAME;
String[] columns = {
DBConstants.Books.COLUMN_NAME_TITLE,
DBConstants.Books.COLUMN_NAME_AUTHOR,
DBConstants.Books.COLUMN_NAME_GENRE,
DBConstants.Books.COLUMN_NAME_ON_LOAN,
DBConstants.ID
};
String where = null;
String[] where_args = null;
String group_by = null;
String having = null;
String order_by = null;
Cursor cursor = db.query(table_name, columns, where, where_args, group_by, having, order_by);
while (cursor.moveToNext()) {
bookItems.add(new CustomBookItem(
cursor.getString(0),
cursor.getString(1),
cursor.getString(2),
cursor.getString(3),
cursor.getString(4)
));
}
cursor.close();
ListView lvMainList = findViewById(R.id.lv_books_list);
CustomArrayAdapter customArrayAdapter = new CustomArrayAdapter(this, bookItems);
lvMainList.setAdapter(customArrayAdapter);
lvMainList.setOnItemClickListener((adapterView, view, pos, id) -> {
Log.i("BooksActivity", "item was clicked");
CustomBookItem bookItem = (CustomBookItem) adapterView.getAdapter().getItem(pos);
Intent intent = new Intent(this, BookActivity.class);
intent.putExtra(DBConstants.Books.COLUMN_NAME_TITLE, bookItem.getTitle());
intent.putExtra(DBConstants.Books.COLUMN_NAME_AUTHOR, bookItem.getAuthor());
intent.putExtra(DBConstants.Books.COLUMN_NAME_GENRE, bookItem.getGenre());
intent.putExtra(DBConstants.Books.COLUMN_NAME_ON_LOAN, bookItem.getOnLoan());
intent.putExtra(DBConstants.ID, bookItem.getId());
startActivity(intent);
});
customArrayAdapter.notifyDataSetChanged();
}
#Override
protected void onDestroy() {
super.onDestroy();
db.close();
}
}
Activity receiving the data
public class BookActivity extends AppCompatActivity {
private Resources resources;
private final BooksDBOpenHelper dbHelper = new BooksDBOpenHelper(this, DBConstants.DB_NAME, null, 1);
private SQLiteDatabase db;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_book);
this.resources = this.getResources();
TextView header = this.findViewById(R.id.tv_header);
header.setText(R.string.book);
ImageButton backButton = this.findViewById(R.id.toolbar_back_button);
backButton.setOnClickListener(view -> finish());
}
#Override
protected void onStart() {
super.onStart();
Intent intent = this.getIntent();
String id = intent.getStringExtra(DBConstants.ID);
TextView tvTitle = this.findViewById(R.id.book_title);
tvTitle.setText(intent.getStringExtra(DBConstants.Books.COLUMN_NAME_TITLE));
Log.d("BookActivity", tvTitle.getText().toString());
TextView tvAuthor = this.findViewById(R.id.book_author);
tvAuthor.setText(intent.getStringExtra(DBConstants.Books.COLUMN_NAME_AUTHOR));
Log.d("BookActivity", tvAuthor.getText().toString());
TextView tvGenre = this.findViewById(R.id.book_genre);
tvGenre.setText(intent.getStringExtra(DBConstants.Books.COLUMN_NAME_GENRE));
Log.d("BookActivity", tvGenre.getText().toString());
View loanBookButton = this.findViewById(R.id.loanBookButton);
View returnBookButton = this.findViewById(R.id.returnBookButton);
if (intent.getStringExtra(DBConstants.Books.COLUMN_NAME_ON_LOAN).equals("0")) {
returnBookButton.setBackgroundColor(this.resources.getColor(R.color.grayed_out));
returnBookButton.setEnabled(false);
} else {
loanBookButton.setBackgroundColor(this.resources.getColor(R.color.grayed_out));
loanBookButton.setEnabled(false);
}
loanBookButton.setOnClickListener(view -> loanBook(id));
returnBookButton.setOnClickListener(view -> returnBook(id));
}
public void returnBook(String id) {
this.db = this.dbHelper.getReadableDatabase();
this.db.execSQL("UPDATE " + DBConstants.Books.TABLE_NAME +
" SET " + DBConstants.Books.COLUMN_NAME_ON_LOAN + "='0' " +
"WHERE id=" + id);
this.finish();
}
public void loanBook(String id) {
this.db = this.dbHelper.getReadableDatabase();
this.db.execSQL("UPDATE " + DBConstants.Books.TABLE_NAME +
" SET " + DBConstants.Books.COLUMN_NAME_ON_LOAN + "='1' " +
"WHERE id=" + id);
this.finish();
}
}
Layout of sending activity
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/container_header_lyt"
layout="#layout/toolbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"/>
<ListView
android:id="#+id/lv_books_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/container_header_lyt"/>
</RelativeLayout>
Layout of receiving activity
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/container_header_lyt"
layout="#layout/toolbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"/>
<Button
android:id="#+id/loanBookButton"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginStart="64dp"
android:layout_marginTop="580dp"
android:layout_marginEnd="229dp"
android:layout_marginBottom="103dp"
android:text="#string/loan_book_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/returnBookButton"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginStart="229dp"
android:layout_marginTop="580dp"
android:layout_marginEnd="64dp"
android:layout_marginBottom="103dp"
android:text="#string/return_book_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/book_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="176dp"
android:layout_marginTop="174dp"
android:layout_marginEnd="176dp"
android:layout_marginBottom="487dp"
android:textAlignment="center"
android:textSize="32sp"
app:layout_constraintBottom_toTopOf="#+id/loanBookButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/book_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="176dp"
android:layout_marginTop="69dp"
android:layout_marginEnd="176dp"
android:layout_marginBottom="399dp"
android:textSize="28sp"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="#+id/loanBookButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/book_title" />
<TextView
android:id="#+id/book_genre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="176dp"
android:layout_marginTop="69dp"
android:layout_marginEnd="176dp"
android:layout_marginBottom="311dp"
android:textSize="28sp"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="#+id/loanBookButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/book_author" />
</androidx.constraintlayout.widget.ConstraintLayout>
Edit
I restructured the layout of the receiving activity by changing it from a constraint layout to a relative. I don't know why this worked but it fixed my problem.
I'm developing a ChatApp with the function of Audio Messages. The Recording and playing of this Audio Messages are working very well, but if i click on Play Button the Recyclerview is scrolling up. Anyone have an idea?
Sorry for my bad english, i'm from Germany ;)
AdapterChat.Java
private static final int MSG_TYPE_LEFT = 0;
private static final int MSG_TYPE_RIGHT = 1;
Context context;
List<ModelChat> chatList;
String imageUrl;
FirebaseUser fUser;
public AdapterChat(Context context, List<ModelChat> chatList, String imageUrl) {
this.context = context;
this.chatList = chatList;
this.imageUrl = imageUrl;
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
//inflate layouts: row_chat_left.xml for receiver, row_chat_right.xml for sender
if (i == MSG_TYPE_RIGHT) {
View view = LayoutInflater.from(context).inflate(R.layout.row_chat_right, viewGroup, false);
return new MyHolder(view);
}
else {
View view = LayoutInflater.from(context).inflate(R.layout.row_chat_left, viewGroup, false);
return new MyHolder(view);
}
}
public void add(ModelChat object) {
chatList.add(object);
add(object);
}
#SuppressLint("ClickableViewAccessibility")
#Override
public void onBindViewHolder(#NonNull final MyHolder myHolder, final int i) {
final String message = chatList.get(i).getMessage();
String timeStamp = chatList.get(i).getTimestamp();
String type = chatList.get(i).getType();
if (type.equals("text") || message.equals(R.string.message_was_deleted)) {
//text message
myHolder.messageTv.setVisibility(View.VISIBLE);
myHolder.messageIv.setVisibility(View.GONE);
myHolder.playAudioBtn.setVisibility(View.GONE);
myHolder.messageVoiceSb.setVisibility(View.GONE);
myHolder.sbCurrentTime.setVisibility(View.GONE);
myHolder.sbTotalDuration.setVisibility(View.GONE);
myHolder.messageTv.setText(message);
}
else if (type.equals("audio")) {
//audio message
myHolder.messageTv.setVisibility(View.GONE);
myHolder.messageIv.setVisibility(View.GONE);
myHolder.playAudioBtn.setVisibility(View.VISIBLE);
myHolder.messageVoiceSb.setVisibility(View.VISIBLE);
myHolder.sbCurrentTime.setVisibility(View.VISIBLE);
myHolder.sbTotalDuration.setVisibility(View.VISIBLE);
myHolder.voiceMessageUrl = message;
myHolder.getAdapterPosition();
myHolder.playAudioBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (myHolder.mediaPlayer.isPlaying()) {
myHolder.handler.removeCallbacks(myHolder.updater);
myHolder.mediaPlayer.pause();
myHolder.playAudioBtn.setImageResource(R.drawable.ic_play_btn);
}
else {
myHolder.mediaPlayer.start();
myHolder.playAudioBtn.setImageResource(R.drawable.ic_pause_btn);
myHolder.updateSeekbar();
}
}
});
myHolder.prepareMediaPlayer();
myHolder.messageVoiceSb.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
SeekBar seekBar = (SeekBar) view;
int playPosition = (myHolder.mediaPlayer.getDuration() / 100) * seekBar.getProgress();
myHolder.mediaPlayer.seekTo(playPosition);
myHolder.sbCurrentTime.setText(myHolder.milliSecondsToTimer(myHolder.mediaPlayer.getCurrentPosition()));
return false;
}
});
myHolder.mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
myHolder.messageVoiceSb.setSecondaryProgress(i);
}
});
myHolder.mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
myHolder.messageVoiceSb.setProgress(0);
myHolder.playAudioBtn.setImageResource(R.drawable.ic_play_btn);
myHolder.mediaPlayer.reset();
myHolder.prepareMediaPlayer();
}
});
}
else {
//image message
myHolder.messageIv.setVisibility(View.VISIBLE);
myHolder.messageTv.setVisibility(View.GONE);
myHolder.playAudioBtn.setVisibility(View.GONE);
myHolder.messageVoiceSb.setVisibility(View.GONE);
myHolder.sbCurrentTime.setVisibility(View.GONE);
myHolder.sbTotalDuration.setVisibility(View.GONE);
Picasso.get().load(message).placeholder(R.drawable.ic_image_black).into(myHolder.messageIv);
}
//set data
myHolder.messageTv.setText(message);
myHolder.timeTv.setText(timeStamp);
try {
Picasso.get().load(imageUrl).into(myHolder.profileIv);
}
catch (Exception e) {
}
myHolder.messageLayout.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
//show delete message confirm dialog
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.delete);
builder.setMessage("Are you sure to delete this message?");
//delete button
builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
deleteMessage(i);
}
});
//cancel delete button
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//dismiss dialog
dialog.dismiss();
}
});
//create and show dialog
builder.create().show();
return false;
}
});
//set seen/delivered status of message
if (i==chatList.size()-1) {
if (chatList.get(i).isSeen()) {
myHolder.isSeenTv.setText("Seen");
}
else {
myHolder.isSeenTv.setText("Delivered");
}
}
else {
myHolder.isSeenTv.setVisibility(View.GONE);
}
}
private void deleteMessage(int position) {
final String myUID = FirebaseAuth.getInstance().getCurrentUser().getUid();
/*Logic:
* Get timeStamp of clicked message
* Compare the timeStamp of the clicked message with all messages in CHats
* Where both values matches, delete that message
* This will allow sender to delete his and receiver's message*/
String msgTimeStamp = chatList.get(position).getTimestamp();
final String type = chatList.get(position).getType();
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("Chats");
Query query = dbRef.orderByChild("timestamp").equalTo(msgTimeStamp);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds: dataSnapshot.getChildren()) {
/*if you want to allow sender to delete only his message then
* compare sender value with current user's uid
* if they match means its the message of sender that is trying to delete*/
if (ds.child("sender").getValue().equals(myUID)) {
if (type.equals("audio")) {
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("type", "text");
ds.getRef().updateChildren(hashMap);
} else if (type.equals("image")) {
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("type", "text");
ds.getRef().updateChildren(hashMap);
}
/*We can do one of two things here
* 1) Remove the message from chats
* 2) Set the value of message "This messages was deleted..." */
//1) Remove the message from Chats
//ds.getRef().removeValue();
//2) Set the value of message "This message was deleted..."
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("message", "This message was deleted...");
ds.getRef().updateChildren(hashMap);
Toast.makeText(context, "message deleted...", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(context, "You can delete only your messages...", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
#Override
public int getItemCount() {
return chatList.size();
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public int getItemViewType(int position) {
//get currently signed in user
fUser = FirebaseAuth.getInstance().getCurrentUser();
if (chatList.get(position).getSender().equals(fUser.getUid())) {
return MSG_TYPE_RIGHT;
}
else {
return MSG_TYPE_LEFT;
}
}
//view holder class
class MyHolder extends RecyclerView.ViewHolder {
//views
ImageView profileIv, messageIv;
ImageButton playAudioBtn;
SeekBar messageVoiceSb;
TextView messageTv, timeTv, isSeenTv, sbCurrentTime, sbTotalDuration;
LinearLayout messageLayout; //for click listener to show delete option
MediaPlayer mediaPlayer;
Handler handler = new Handler();
String voiceMessageUrl = null;
#SuppressLint("ClickableViewAccessibility")
public MyHolder(#NonNull View itemView) {
super(itemView);
//init views
profileIv = itemView.findViewById(R.id.profileIv);
messageIv = itemView.findViewById(R.id.messageIV);
messageTv = itemView.findViewById(R.id.messageTv);
messageVoiceSb = itemView.findViewById(R.id.messageVoiceSb);
playAudioBtn = itemView.findViewById(R.id.playAudioBtn);
sbCurrentTime = itemView.findViewById(R.id.sbCurrentTime);
sbTotalDuration = itemView.findViewById(R.id.sbTotalDuration);
timeTv = itemView.findViewById(R.id.timeTv);
isSeenTv = itemView.findViewById(R.id.isSeenTv);
messageLayout = itemView.findViewById(R.id.messageLayout);
mediaPlayer = new MediaPlayer();
messageVoiceSb.setMax(100);
}
private void prepareMediaPlayer() {
try {
mediaPlayer.setDataSource(voiceMessageUrl); //url of audio file to play
mediaPlayer.prepare();
sbTotalDuration.setText(milliSecondsToTimer(mediaPlayer.getDuration()));
} catch (Exception e) {
Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private Runnable updater = new Runnable() {
#Override
public void run() {
updateSeekbar();
long currentDuration = mediaPlayer.getCurrentPosition();
sbCurrentTime.setText(milliSecondsToTimer(currentDuration));
}
};
private void updateSeekbar() {
if (mediaPlayer.isPlaying()) {
messageVoiceSb.setProgress((int) (((float) mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration()) * 100));
handler.postDelayed(updater, 1000);
}
}
private String milliSecondsToTimer(long milliSeconds) {
String timerString = "";
String secondsString;
int hours = (int) (milliSeconds / (1000 * 60 * 60));
int minutes = (int) (milliSeconds % (1000 * 60 * 60)) / (1000 * 60);
int seconds = (int) ((milliSeconds % (1000 * 60 * 60)) % (1000 * 60) / 1000);
if (hours > 0) {
timerString = hours + ":";
}
if (seconds < 10) {
secondsString = "0" + seconds;
} else {
secondsString = "" + seconds;
}
timerString = timerString + minutes + ":" + secondsString;
return timerString;
}
}
chatActivity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/chatBackground"
tools:context=".ChatActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="#color/colorPrimaryDark"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/profileIv"
android:layout_width="35dp"
android:layout_height="35dp"
android:scaleType="centerCrop"
android:src="#drawable/ic_default"
app:civ_circle_background_color="#color/colorPrimaryDark"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_marginStart="20dp">
<!-- Receiver Name-->
<TextView
android:id="#+id/nameTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="His Name"
android:textColor="#color/colorWhite"
android:textSize="18sp"
android:textStyle="bold" />
<!-- Receiver Status i.e online or offline-->
<TextView
android:id="#+id/userStatusTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="online"
android:textColor="#color/colorWhite"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<ImageView
android:id="#+id/blockIv"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:src="#drawable/ic_unblocked_green"
android:visibility="invisible"/>
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
<!-- RecyclerView-->
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/chat_recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/toolbar"
android:layout_above="#id/chatLayout" />
<!-- send message edit text and button in layout-->
<LinearLayout
android:id="#+id/chatLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:background="#color/textInputBackground"
android:orientation="horizontal">
<!-- ImageButton: to send Image-->
<ImageButton
android:id="#+id/attachBtn"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#null"
android:src="#drawable/ic_attach_black" />
<!-- EditText: input message-->
<EditText
android:id="#+id/messageEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#null"
android:inputType="textCapSentences|textMultiLine"
android:padding="15dp"
android:hint="Start typing" />
<Chronometer
android:id="#+id/record_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:textSize="14sp"
android:textColor="#color/colorPrimary" />
<!-- Button: voice message-->
<ImageButton
android:id="#+id/recordBtn"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#null"
android:src="#drawable/ic_record_btn_stopped" />
<!-- Button: send message-->
<ImageButton
android:id="#+id/sendBtn"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#null"
android:src="#drawable/ic_send" />
</LinearLayout>
row_chat_right.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:id="#+id/messageLayout"
android:padding="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="end">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/profileIv"
app:civ_border_color="#null"
android:visibility="gone"
android:src="#drawable/ic_default_img" />
<TextView
android:id="#+id/messageTv"
android:layout_weight="1"
android:textSize="16sp"
android:textColor="#color/textColor"
android:background="#drawable/bg_sender"
android:padding="15dp"
android:text="His Message"
android:visibility="gone"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<ImageView
android:id="#+id/messageIV"
android:layout_width="200dp"
android:layout_height="200dp"
android:adjustViewBounds="true"
android:padding="15dp"
android:src="#drawable/ic_image_black"
android:scaleType="fitCenter"
android:background="#drawable/bg_sender" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/bg_sender"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/playAudioBtn"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="20dp"
android:background="#null"
android:src="#drawable/ic_play_btn" />
<SeekBar
android:id="#+id/messageVoiceSb"
android:visibility="gone"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/playAudioBtn"
android:padding="10dp"
android:layout_marginTop="10dp"
android:max="100"
android:progress="0" />
<TextView
android:id="#+id/sbCurrentTime"
android:visibility="gone"
android:text="0:00"
android:textStyle="bold"
android:textSize="12sp"
android:layout_marginStart="2dp"
android:layout_below="#id/messageVoiceSb"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/sbTotalDuration"
android:visibility="gone"
android:textStyle="bold"
android:text="0:10"
android:textSize="12sp"
android:layout_below="#id/messageVoiceSb"
android:layout_toEndOf="#id/messageVoiceSb"
android:layout_marginEnd="12dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
<TextView
android:id="#+id/timeTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:textAlignment="textEnd"
android:text="07/08/2020 23:00PM"
android:textColor="#color/textColor"
android:textSize="12sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/isSeenTv"
android:gravity="end"
android:textAlignment="textEnd"
android:text="delivered" />
Here is the Fix!!
<TextView
android:layout_width="match_parent" <-- This is what I changed
android:layout_height="wrap_content"/>
<SeekBar
android:layout_width="match_parent" <-- Check this as well
android:layout_height="wrap_content"/>
first of all, I'll explain the expected behavior of the App.
What does the App do?
When I run the App I see this view:
Now if you hit the "+" button you'll see this Dialog:
By clicking Add this entry will be added to a ListView. I added two items. This looks like this:
Expected Result
Now when I touch and hold the mic icon of the list items it should start recording audio through the device microphone and then save this recording with the name of the bold entry, that means e.g. the first recording will get the name A.3gp, the second one B.3gp and so on..
Actual Result (UPDATE 07.12.2017)
The current state is:
Every item in the list gets his "own" recording. That means if I touch and hold the microphone icon of the first item in the list, it is doing what it should do. The same goes for all other items on the list.
When I add the first item A, then touch its record icon, a file will be created with the name A.3gp (which is correct behavior).
When I add the second item B then do nothing and then add a third item C and touch the record icon for B, a file will be created with the name C.3gp (which is not a correct behavior, it should be B.3gp).
Now to the fun part.
Code (UPDATE 07.12.2017)
1. The Model
public class Word {
private String mForeignTranslation;
private String mDefaultTranslation;
private ImageView mRecordIconImageResourceId;
private MediaRecorder mMediaRecorder;
public Word(String foreignTranslation, String defaultTranslation, ImageView recordIconImageResourceId) {
this.mForeignTranslation = foreignTranslation;
this.mDefaultTranslation = defaultTranslation;
this.mRecordIconImageResourceId = recordIconImageResourceId;
}
public Word(String foreignTranslation, String defaultTranslation) {
this.mForeignTranslation = foreignTranslation;
this.mDefaultTranslation = defaultTranslation;
}
public String getDefaultTranslation() {
return mDefaultTranslation;
}
public String getForeignTranslation() {
return mForeignTranslation;
}
public ImageView getRecordIconImageResourceId() {
return mRecordIconImageResourceId;
}
public MediaRecorder getMediaRecorder() {
return mMediaRecorder;
}
public void setDefaultTranslation(String mDefaultTranslation) {
this.mDefaultTranslation = mDefaultTranslation;
}
public void setForeignTranslation(String mForeignTranslation) {
this.mForeignTranslation = mForeignTranslation;
}
public void setRecordIconImageResourceId(ImageView recordIconImageResourceId) {
this.mRecordIconImageResourceId = recordIconImageResourceId;
}
public void setMediaRecorder(MediaRecorder mMediaRecorder) {
this.mMediaRecorder = mMediaRecorder;
}
}
2. The Adapter
public class WordAdapter extends ArrayAdapter<Word> {
private ArrayList<Word> wordsArrayList = new ArrayList<>();
private MediaRecorder mediaRecorder = new MediaRecorder();
public WordAdapter(#NonNull Context context, ArrayList<Word> words) {
super(context, 0, words);
}
#NonNull
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View listItemView = convertView;
if (listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(R.layout.my_word_list_items,parent,false);
}
Word currentWord = getItem(position);
TextView foreignWord = listItemView.findViewById(R.id.myForeignWord);
foreignWord.setText(currentWord.getForeignTranslation());
TextView defaultWord = listItemView.findViewById(R.id.myDefaultWord);
defaultWord.setText(currentWord.getDefaultTranslation());
final ImageView recordIconImageView = listItemView.findViewById(R.id.recordIconImageView);
wordsArrayList = MyWordsActivity.getWordsArrayList();
recordIconImageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN: {
recordIconImageView.setImageResource(R.drawable.mic_red);
startAudioRecording();
break;
}
case MotionEvent.ACTION_UP: {
recordIconImageView.setImageResource(R.drawable.mic_black);
stopAudioRecording();
break;
}
}
return true;
}
});
return listItemView;
}
private ArrayList<Word> getWordsArrayList() {
return wordsArrayList;
}
private void startAudioRecording() {
if (wordsArrayList != null) {
Log.i("ArrayListe", wordsArrayList.toArray().toString());
getMediaRecorderReady();
try {
mediaRecorder.prepare();
mediaRecorder.start();
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
Toast.makeText(this.getContext(), "Recording started", Toast.LENGTH_SHORT).show();
}
}
private void stopAudioRecording() {
try {
mediaRecorder.stop();
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(this.getContext(), "Recording stopped", Toast.LENGTH_SHORT).show();
}
private void getMediaRecorderReady() {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
mediaRecorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+"speakmylanguage"+"/"+MyWordsActivity.getForeignWord()+".3gp");
}
}
3. The Activity
public class MyWordsActivity extends AppCompatActivity {
private static String defaultWord, foreignWord;
private static ArrayList<Word> wordsArrayList = new ArrayList<>();
WordAdapter wordAdapter;
// Main Activity Views
TextView hintTextView;
ListView myWordsListView;
FloatingActionButton floatingButtonAddNewWord;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_words);
// Init Main Activity Views
hintTextView = findViewById(R.id.hintTextView);
myWordsListView = findViewById(R.id.myWordsList);
floatingButtonAddNewWord = findViewById(R.id.fabAddNewWord);
floatingButtonAddNewWord.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final Dialog addNewWordsDialog = new Dialog(MyWordsActivity.this);
addNewWordsDialog.setContentView(R.layout.activity_add_new_words);
final EditText addForeignWordEditText = addNewWordsDialog.findViewById(R.id.addForeignWordEditText);
final EditText addDefaultWordEditText = addNewWordsDialog.findViewById(R.id.addDefaultWordEditText);
final Button addNewWordButton = addNewWordsDialog.findViewById(R.id.addNewWordButton);
addNewWordsDialog.show();
addNewWordButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!addDefaultWordEditText.getText().toString().equals("") &&
!addForeignWordEditText.getText().toString().equals("")) {
foreignWord = addForeignWordEditText.getText().toString();
defaultWord = addDefaultWordEditText.getText().toString();
wordsArrayList.add(new Word(foreignWord, defaultWord));
hintTextView.setVisibility(View.GONE);
addNewWordsDialog.dismiss();
} else {
Toast.makeText(MyWordsActivity.this, "Please enter two words", Toast.LENGTH_SHORT).show();
}
}
});
wordAdapter = new WordAdapter(MyWordsActivity.this, getWordsArrayList());
myWordsListView.setAdapter(wordAdapter);
}
});
}
public static String getDefaultWord() {
return defaultWord;
}
public static void setDefaultWord(String defaultWord) {
MyWordsActivity.defaultWord = defaultWord;
}
public static String getForeignWord() {
return foreignWord;
}
public static void setForeignWord(String foreignWord) {
MyWordsActivity.foreignWord = foreignWord;
}
public static ArrayList<Word> getWordsArrayList() {
return wordsArrayList;
}
}
4. The Layouts
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myRelativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/myWordsListItems"
android:layout_width="match_parent"
android:layout_height="88dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginStart="16dp"
android:orientation="vertical">
<TextView
android:id="#+id/myForeignWord"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="bottom"
android:textAppearance="?android:textAppearanceMedium"
android:textSize="24sp"
android:textStyle="bold"
tools:text="foreign word" />
<TextView
android:id="#+id/myDefaultWord"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top"
android:textAppearance="?android:textAppearanceMedium"
android:textSize="24sp"
tools:text="default word" />
</LinearLayout>
<ImageView
android:id="#+id/playIconImageView"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp"
android:clickable="true"
android:src="#drawable/play_icon" />
<ImageView
android:id="#+id/recordIconImageView"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="72dp"
android:clickable="true"
android:src="#drawable/mic_black" />
</RelativeLayout>
activity_my_words.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.yousef.mustafa.speakmylanguage.View.MyWordsActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="#string/app_name"
app:titleTextColor="#color/colorWhite" />
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myWordsList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar"
android:drawSelectorOnTop="true"
android:orientation="vertical"
tools:context=".View.MyWordsActivity" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fabAddNewWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_gravity="bottom|center"
android:layout_marginBottom="32dp"
android:tint="#color/colorWhite"
app:backgroundTint="#color/colorGrey"
app:srcCompat="#drawable/icon_add" />
<TextView
android:id="#+id/hintTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="155dp"
android:gravity="center"
android:text="#string/hint"
android:textSize="24sp"
android:textStyle="bold" />
</RelativeLayout>
activity_add_new_words.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorDialogBackground">
<LinearLayout
android:id="#+id/addNewWordLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="8dp"
android:layout_marginTop="12dp"
android:text="#string/add_word_title"
android:textColor="#color/colorBlack"
android:textSize="24sp"
android:textStyle="bold" />
<EditText
android:id="#+id/addForeignWordEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="4dp"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:layout_weight="5"
android:gravity="center_horizontal"
android:hint="#string/enter_foreign_word"
android:inputType="textPersonName|textCapWords"
android:textSize="24sp" />
<EditText
android:id="#+id/addDefaultWordEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:layout_marginTop="4dp"
android:layout_weight="5"
android:gravity="center_horizontal"
android:hint="#string/enter_default_word"
android:inputType="textPersonName|textCapWords"
android:textSize="24sp" />
<Button
android:id="#+id/addNewWordButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="#string/button_add"
android:textAllCaps="false"
android:textSize="18sp" />
</LinearLayout>
</RelativeLayout>
I would appreciate any help. Thanks in advance.
In the startAudioRecording() method of the Activity, you set the output filename from the foreignWord field. The problem is that the foreignWord field is set to the most recently added foreign word each time the user submits a word pair in the Add Word dialog. Thus each time the user starts a recording, the name of the output file will be set to the last foreign word added.
Instead of using fields for recordingImageView, foreignWord, defaultWord, foreignWord, audioSavePath, and mediaRecorder, you should make them local variables, and pass them as parameters to your record(), startAudioRecording(), stopAudioRecording() methods with the following steps:
Just delete those fields from the beginning of the class so that you see some compilation errors where the fields were used.
Where you see an undefined variable on the left side of an assignment, make the variable local (Ctrl+V in Android Studio).
Where you see an undefined variable elsewhere, make the variable a parameter of the method (Ctrl+P).
It should work after those changes.
`
Kindly move this snippet :
recordingImageView.setOnTouchListener(new View.OnTouchListener()
{
#Override public boolean onTouch(View view, MotionEvent motionEvent)
{
switch (motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
{ recordingImageView.setImageResource(g startAudioRecording(position);
break;
}
case MotionEvent.ACTION_UP:
{
recordingImageView.setImageResource(R.drawable.mic_black);
stopAudioRecording();
break;
}
}
return true;
}
});
In Adapter , getView(...) Below accessing recordImageView.
And put startAudioRecording() , stopAudioRecording() in same adapter or all relevant method for recording is to be in Adapter.
So by this you will get click on in each individual image view. Previously when you are fetching it will only take instance of any one image view.
Now update code on "startAudioRecording()" as:
private void startAudioRecording()
{
if (checkPermission())
{
if (wordsArrayList != null)
{
audioSavePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + wordsArrayList.get(position) + ".3gp";
getMediaRecorderReady();
}
}
}
Now your second point, saving its name by any name. Will cover by above code.
Thanks and happy coding
As the title says,
When using startLabel.setVisibility(View.GONE);
The app Crashes and I am not sure how to fix
The Java code below.
public class Main extends AppCompatActivity {
private TextView scoreLabel;
private TextView startLabel;
private ImageView box;
private ImageView orange;
private ImageView pink;
private ImageView black;
// Position
private int boxY;
private int boxX;
// Initialize Class
private Handler handler = new Handler();
private Timer timer = new Timer();
//Status Check
private boolean action_flg = false;
private boolean start_flg = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scoreLabel = (TextView) findViewById(R.id.scoreLabel);
scoreLabel = (TextView) findViewById(R.id.startLabel);
box = (ImageView) findViewById(R.id.box);
orange = (ImageView) findViewById(R.id.orange);
pink = (ImageView) findViewById(R.id.pink);
black = (ImageView) findViewById(R.id.black);
//Moves images to out of the screen
//orange.setX(-80.0f);
orange.setY(-80.0f);
// pink.setX(-80.0f);
pink.setY(-80.0f);
//black.setX(-80.0f);
black.setY(-80.0f);
boxY = 200;
}
public void changePos()
{
//Move box
if (action_flg == true)
{
// touching
boxY -= 20;
} else {
//released
boxY += 20;
}
box.setY(boxY);
}
public boolean onTouchEvent(MotionEvent me)
{
if (start_flg == false)
{
start_flg = true;
//Issue here with setting the visibility of the start
// startLabel.setVisibility(View.GONE);
timer.schedule(new TimerTask()
{
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
changePos();
}
});
}
// Changing these numbers slows down how fast the box moves.
}, 0, 100);
}else {
if(me.getAction() == MotionEvent.ACTION_DOWN)
{
action_flg = true;
}else if (me.getAction() == MotionEvent.ACTION_UP){
action_flg = false;
}
}
return true;
}
}
Here is the XML version of the code.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="me.scott.nathan.catchtheball.Main">
<TextView
android:id="#+id/scoreLabel"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Score : 300"
android:textSize="18sp"
android:paddingLeft="10dp"
android:gravity="center_vertical">
</TextView>
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/startLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tap to Start"
android:textSize="30sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="130dp"
/>
<ImageView
android:id="#+id/box"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/box"
android:layout_gravity="center_vertical"
/>
<ImageView
android:id="#+id/orange"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="#drawable/orange" />
<ImageView
android:id="#+id/black"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="#drawable/black" />
<ImageView
android:id="#+id/pink"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="#drawable/pink" />
</FrameLayout>
<!--
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.22" />
-->
</LinearLayout>
Anyone help appreciated to fix this issue, Thanks
Your startLabel is null (copy paste problem?^^). Replace this:
scoreLabel = (TextView) findViewById(R.id.startLabel);
with this:
startLabel = (TextView) findViewById(R.id.startLabel);