Android GraphView and Mediaplayer falling out of synchronization - java
I'm working on a project, where I need to show the pitches of the words (from the song) in a GraphView. I wrote a program that would get the pitches from a song and create a .txt file from it.
Then I wrote a class, that reads the file and creates a list from it. So in the end I would have a list that consists of words and word contains pitches. In the MakePitchesList you can see what the pitches output from a song looks like. I have 0,14:23281,61 on every line. The first part of the line is timeOccurance meaning, when this pitch was heard and the second part is the pitch itself. So in this example the timeOccurance would be 0,14 and pitch at that given time 23281,61.
Here are the three classes that make a wordsList out of a pitch .txt file.
public class Pitch{
float occuranceTime;
float pitch;
public void setOccuranceTime(float occuranceTime) {
this.occuranceTime = occuranceTime;
}
public float getOccuranceTime() {
return occuranceTime;
}
public void setPitch(float pitch) {
this.pitch = pitch;
}
public float getPitch() {
return pitch;
}
}
public class MakePitchesList {
String[] pitches;
List<Pitch> listOfPitches = new ArrayList<Pitch>();
public List<Pitch> getListOfPitches(){
getPitches();
for (String pitchString: pitches) {
Pitch pitch = new Pitch();
makeListOfPitches(pitch, pitchString);
}
return listOfPitches;
}
public void makeListOfPitches(Pitch pitch, String pitchString){
pitch.setPitch(getPitchesInfo(pitchString, 1));
pitch.setOccuranceTime(getPitchesInfo(pitchString, 0));
listOfPitches.add(pitch);
}
public String[] getPitches() {
pitches = pitchesRaw.split("\\r?\\n");
return pitches;
}
private float getPitchesInfo(String pitch, int position){
String[] frequencyAndTime = pitch.split("\\:");
if(position == 0){
return Float.parseFloat(frequencyAndTime[0].replace(',', '.'));
}
if(position == 1){
return Float.parseFloat(frequencyAndTime[1].replace(',', '.'));
}
else return 0;
}
String pitchesRaw =
"0,14:23281,61\n" +
"0,23:53,65\n" +
"0,37:72,53\n" +
"0,56:86,09\n" +
"0,60:88,58\n" +
"0,65:87,45\n" +
"0,70:87,11\n" +
"0,74:89,56\n" +
"0,79:96,22\n" +
"0,84:23288,24\n" +
"0,88:103,92\n" +
"0,93:107,46\n" +
"0,98:108,02\n" +
"1,02:107,51\n" +
"1,07:104,92\n" +
"1,11:105,94\n" +
"1,16:106,40\n" +
"1,21:104,43\n" +
"1,25:104,93\n" +
"1,30:108,01\n" +
"1,35:316,81\n" +
"1,39:103,98\n" +
"1,44:23297,42\n" +
"1,49:23357,42\n" +
"1,53:23359,74\n" +
"1,58:23393,04\n" +
"1,63:23244,18\n" +
"1,67:23220,51\n" +
"1,72:23250,06\n" +
"1,76:23288,84\n" +
"1,81:23241,81\n" +
"1,86:23295,22\n" +
"1,90:23268,04\n" +
"1,95:23252,78\n" +
"2,00:23224,22\n" +
"2,04:23429,71\n" +
"2,09:23214,58\n" +
"2,14:23240,70\n" +
"2,18:23237,71\n" +
"2,23:23231,22\n" +
"2,28:23222,77\n" +
"2,32:23239,73\n" +
"2,37:23235,98\n" +
"2,41:23222,16\n" +
"2,46:23224,01\n" +
"2,51:23214,26\n" +
"2,55:23223,20\n" +
"2,60:23234,11\n" +
"2,65:23221,65\n" +
"2,69:23213,45\n" +
"2,74:23217,44\n" +
"2,79:23235,93\n" +
"2,83:11122,79\n" +
"2,88:23234,58\n" +
"2,93:23229,52\n" +
"2,97:23255,48\n" +
"3,02:23254,44\n" +
"3,07:23355,41\n" +
"3,44:105,48\n" +
"3,48:115,45\n" +
"3,53:117,78\n" +
"3,58:127,36\n" +
"3,62:131,24\n" +
"3,67:130,33\n" +
"3,72:131,93\n" +
"3,76:127,32\n" +
"3,81:117,18\n" +
"3,85:117,80\n" +
"3,90:117,15\n" +
"3,95:121,04\n" +
"3,99:131,22\n" +
"4,04:130,38\n" +
"4,09:130,34\n" +
"4,13:129,57\n" +
"4,18:120,38\n" +
"4,23:121,06\n" +
"4,32:100,12\n" +
"4,37:23483,16\n" +
"4,41:112,95\n" +
"4,46:23448,04\n" +
"4,50:23396,09\n" +
"4,55:23292,90\n" +
"4,60:117,21\n" +
"4,64:116,58\n" +
"4,69:116,62\n" +
"4,74:119,18\n" +
"4,78:131,19\n" +
"4,83:130,34\n" +
"4,88:129,59\n" +
"4,92:132,64\n" +
"4,97:129,68\n" +
"5,02:132,71\n" +
"5,06:133,57\n" +
"5,11:128,94\n" +
"5,15:131,09\n" +
"5,20:132,75\n" +
"5,25:129,68\n" +
"5,29:131,26\n" +
"5,34:131,22\n" +
"5,39:130,38\n" +
"5,43:146,01\n" +
"5,48:140,43\n" +
"5,57:23450,16\n" +
"5,62:130,46\n" +
"5,67:132,02\n" +
"5,71:23243,22\n" +
"5,76:23456,28\n" +
"5,85:23246,64\n" +
"5,90:23274,97\n" +
"5,94:23310,30\n" +
"5,99:23229,71\n" +
"6,08:23214,33\n" +
"6,13:23221,53\n" +
"6,18:23263,48\n" +
"6,22:23213,17\n" +
"6,27:23235,04\n" +
"6,32:23222,02\n" +
"6,36:23214,90\n" +
"6,41:23230,05\n" +
"6,46:23212,55\n" +
"6,50:23221,33\n" +
"6,55:23226,70\n" +
"6,59:23217,07\n" +
"6,64:23272,07\n" +
"6,69:11102,74\n" +
"6,73:23263,38\n" +
"6,78:23217,53\n" +
"6,97:23243,63\n" +
"7,11:23214,11\n" +
"7,15:23229,58\n" +
"7,20:23225,70\n" +
"7,24:23244,82\n" +
"7,29:23243,09\n" +
"7,34:23249,66\n" +
"7,38:23226,67\n" +
"7,43:23246,31\n" +
"7,48:23258,55\n" +
"7,52:23230,34\n" +
"7,57:23225,60\n" +
"7,62:23280,25\n" +
"7,66:23238,08\n" +
"7,71:23221,47\n" +
"7,85:117,87\n" +
"7,89:117,19\n" +
"7,94:117,21\n" +
"7,99:117,21\n" +
"8,03:116,57\n" +
"8,08:119,10\n" +
"8,13:44,01\n" +
"8,17:129,52\n" +
"8,22:132,72\n" +
"8,27:143,19\n" +
"8,31:141,13\n" +
"8,36:139,35\n" +
"8,45:132,82\n" +
"8,50:129,76\n" +
"8,54:130,43\n" +
"8,68:94,20\n" +
"8,78:132,70\n" +
"8,82:130,43\n" +
"8,87:129,60\n" +
"8,92:130,56\n" +
"8,96:128,92\n" +
"9,01:119,19\n" +
"9,06:118,45\n" +
"9,10:103,41\n" +
"9,15:103,41\n" +
"9,20:103,89\n" +
"9,24:106,46\n" +
"9,29:214,93\n" +
"9,33:23427,95\n" +
"9,38:23356,01\n" +
"9,43:106,41\n" +
"9,47:100,57\n" +
"9,52:106,39\n" +
"9,57:104,40\n" +
"9,61:99,70\n" +
"9,66:106,42\n" +
"9,71:103,50\n" +
"9,75:104,47\n" +
"9,80:106,97\n" +
"9,85:99,68\n" +
"9,89:23454,22\n" +
"9,94:23299,56\n" +
"9,98:23275,30\n" +
"10,03:23222,72\n" +
"10,08:23246,09\n" +
"10,12:23221,14\n" +
"10,17:23240,54\n" +
"10,22:23246,81\n" +
"10,26:23224,74\n" +
"10,31:23249,41\n" +
"10,36:23214,79\n" +
"10,40:23213,46\n" +
"10,45:23259,51\n" +
"10,50:23217,39\n" +
"10,54:23215,36\n" +
"10,59:23224,87\n" +
"10,63:23242,27\n" +
"10,68:23270,82\n" +
"10,73:23243,19\n" +
"10,77:23222,75\n" +
"10,82:23268,78\n" +
"10,87:23321,62\n" +
"10,91:23259,65\n" +
"11,05:23226,24\n" +
"11,10:23222,92\n" +
"11,15:23218,83\n" +
"11,19:23211,71\n" +
"11,24:11112,28\n" +
"11,28:23261,03\n" +
"11,33:23265,31\n" +
"11,38:23245,92\n" +
"11,42:57,09\n" +
"11,61:103,45\n" +
"11,66:103,91\n" +
"11,70:102,02\n" +
"11,75:107,96\n" +
"11,80:105,43\n" +
"11,84:104,46\n" +
"11,89:116,64\n" +
"11,94:115,99\n" +
"11,98:114,77\n" +
"12,03:121,72\n" +
"12,07:123,16\n" +
"12,12:125,12\n" +
"12,17:128,85\n" +
"12,21:120,37\n" +
"12,26:116,52\n" +
"12,31:130,55\n" +
"12,35:131,06\n" +
"12,40:131,89\n" +
"12,45:128,88\n" +
"12,49:23397,75\n" +
"12,59:118,45\n" +
"12,63:116,54\n" +
"12,68:119,70\n" +
"12,72:115,45\n" +
"12,77:115,30\n" +
"12,82:119,86\n" +
"12,86:116,59\n" +
"12,91:114,13\n" +
"12,96:119,04\n" +
"13,00:118,47\n" +
"13,05:115,38\n" +
"13,10:128,92\n";
}
public class MakeWordsList {
List<Pitch> pitches;
public List<List<Pitch>> getWordsList(List<Pitch> pitchList) {
return makeWordsList(pitchList);
}
List<Pitch> oneWord = new ArrayList<>();
List<List<Pitch>> wordList = new ArrayList<>();
public List<List<Pitch>> makeWordsList(List<Pitch> pitchList){
pitches = pitchList;
int pauseCounter = 0;
for (int i = 0; i < pitchList.size(); i++) {
if(pitchList.get(i).getPitch() > 10000){
pauseCounter++;
} else {
if(pauseCounter > 0){
if(pauseCounter >= 5){
wordList.add(oneWord);
oneWord = new ArrayList<>();
}
pauseCounter = 0;
}
oneWord.add(pitchList.get(i));
}
}
if(oneWord.size() > 0){
wordList.add(oneWord);
}
return wordList;
}
}
Now from that wordsList I create a scrollable GraphView that on paper would look something like this.
Now I have set the boundaries for the GraphView: MinX = -0.8; MaxX = 0.4. This way I'm showing 1 sec at a time on screen. Then I start a thread so it would change the coordinates of the GraphView by 0.1 every 100ms, which should add up as 1 every sec.
Here it is in code:
public class MainActivity extends AppCompatActivity {
final static double GRAPH_STARTING_X = -0.8;
final static double GRAPH_ENDING_X = 0.4;
List<java.util.List<Pitch>> wordsList;
private Viewport graphViewPort;
private Handler handler;
private Runnable runnable;
private GraphView graph;
private DataPoint[] points;
private LineGraphSeries<DataPoint> series;
private int seriesNr;
private double orderNr = GRAPH_STARTING_X;
private ImageButton playRecordButton;
private List<Pitch> pitchesList;
private int songIndex;
private MediaPlayer mediaPlayer;
private boolean isPlaying = false;
#SuppressLint("ClickableViewAccessibility")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Get Textview and Button
playRecordButton = (ImageButton) findViewById(R.id.playRecord);
//Initialize pitches and words
MakePitchesList listOfPithes = new MakePitchesList();
MakeWordsList listOfWords = new MakeWordsList();
pitchesList = listOfPithes.getListOfPitches();
wordsList = listOfWords.getWordsList(pitchesList);
//Initialize graph
graph = (GraphView) findViewById(R.id.graph);
initGraph();
//ViewPort
graphViewPort = graph.getViewport();
//Handler
handler = new Handler();
playRecordButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(!isPlaying){
playMedia(songIndex);
//Start moving graph
//Moved to PlayMedia - setOnPreparedListen
// drawAndMoveGraph();
isPlaying = true;
} else if(isPlaying){
//Move graph to starting position
resetGraph();
//Stop Playing audio
stopAudio();
isPlaying = false;
}
}
});
}
//Moves the graph every 100ms by 0.1 which results in 1 every second
private void drawAndMoveGraph() {
runnable = new Runnable() {
public void run() {
graphViewPort.setMinX(orderNr);
graphViewPort.setMaxX(orderNr + 1);
graph.invalidate();
if (pitchesList.size() != orderNr) {
orderNr = orderNr + 0.1;
}
handler.postDelayed(this, 100);
}
};
runnable.run();
}
//Load up and paint the graph
private void initGraph() {
for (int i = 0; i < wordsList.size(); i++) {
seriesNr = 0;
points = new DataPoint[wordsList.get(i).size()];
for (Pitch pitch : wordsList.get(i)) {
points[seriesNr] = new DataPoint(pitch.getOccuranceTime(), pitch.getPitch());
seriesNr++;
}
series = new LineGraphSeries<>(points);
series.setThickness(15);
graph.addSeries(series);
}
//VocalTestPoints - Just for vocal testing
PointsGraphSeries<DataPoint> series = new PointsGraphSeries<>(new DataPoint[]{
new DataPoint(0, 50),
new DataPoint(0, 75),
new DataPoint(0, 100),
new DataPoint(0, 125),
new DataPoint(0, 150),
new DataPoint(0, 175),
new DataPoint(0, 200),
new DataPoint(0, 225),
new DataPoint(0, 250),
new DataPoint(0, 275),
});
series.setSize(5);
series.setColor(Color.YELLOW);
graph.addSeries(series);
// set manual X bounds
graph.getViewport().setYAxisBoundsManual(true);
graph.getViewport().setMinY(-50);
graph.getViewport().setMaxY(400);
graph.getViewport().setXAxisBoundsManual(true);
graph.getViewport().setMinX(GRAPH_STARTING_X);
graph.getViewport().setMaxX(GRAPH_ENDING_X);
graph.getViewport().setScrollable(true);
}
// Play the chosen song and start moving the graph
private void playMedia(int songIndex) {
Uri uri = Uri.parse("android.resource://com.example.thermaltakei7.testsinging/" + R.raw.perfect);
mediaPlayer = new MediaPlayer();
//Reset so that the MediaPlayer is not pointing to another data source
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(getApplicationContext(), uri);
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
drawAndMoveGraph();
}
});
}
//Stop audio from playing
private void stopAudio() {
mediaPlayer.stop();
mediaPlayer.release();
}
//Reset graph to its initial position
private void resetGraph() {
handler.removeCallbacks(runnable);
graphViewPort.setMinX(GRAPH_STARTING_X);
graphViewPort.setMaxX(GRAPH_ENDING_X);
graph.invalidate();
orderNr = GRAPH_STARTING_X;
}
}
To sum up what the code does: it gets the wordsList from the pitches, initializes the graph, starts listening button click. When button is clicked, it starts moving graph as described above and plays audio.
The problem is that the audio and moving graphView go out of sync. For the first 10sec or so it works like it should but then the lines start falling behind. I would really appreciate if someone took their time to understand all of this mess.
Maybe picture of the actual final graphView will also help. .
Blue line is the first incoming word.
The audio's timing and line should meet at "0".
I have also created a small sample that only contains the classes and topics mentioned above.
It can be accessed from here:
https://github.com/richardboss/testSinging
This code containst a song in its raw folder so it's a bit bigger than it should be, but this was the fastest way to show a demo of what I was trying to say.
Any ideas, suggestions, help is really welcome. Or comments on the code style.
Related
2 variables aren't being compensated for time whilist offline, where as one other variable is
This is supposed to basically make the user's variables continue to increment whilist offline. $money is working fine, but it's not adding anything to $employeeupgrade1level or $employerupgrade1level and I've been trying to figure out why for hours. I'm not sure whether I'm simply overlooking something or the problem is more than that, but the the full source code's here: http://125.63.48.169/other%20stuff/business%20builder/code.txt Posting whole script because it's probably full of things I'm overlooking, and it'd be too much to put here. public void timer() { Handler handler = new Handler(); handler.postDelayed(new Runnable() { #Override public void run() { $money = $money + $employeeupgrade1earnings; $employercounter = (600 / $employerupgrade1level)*18; $managercounter = (600 / $managerupgrade1level)*18; if ($employerupgrade1level >= 1) { $employeeupgrade1level = $employeeupgrade1level + (1 / $employercounter); $employeeupgrade1earnings = $employeeupgrade1level / 10; } if ($managerupgrade1level >= 1) { $employerupgrade1level = $employerupgrade1level + (1 / $managercounter); $employerupgrade1earnings = $employerupgrade1level; } if ($cantafford == 1) { Toast.makeText(getApplicationContext(), ("Can't afford this! You only have " + df.format($money) + " BB!"), Toast.LENGTH_SHORT).show(); $cantafford = 0; } if ($isonmainpage == 0) { TextView cost = (TextView) findViewById(R.id.employeeupgradecost); TextView amount = (TextView) findViewById(R.id.employeeupgradeamount); TextView earnings = (TextView) findViewById(R.id.employeeupgradeearnings); earnings.setText("You earn " + df.format($employeeupgrade1earnings) + " BBs every second."); cost.setText("Costs " + df.format($employeeupgrade1cost) + " Business Bucks."); amount.setText("You have " + noDecimals.format($employeeupgrade1level) + " casual workers."); TextView cost2 = (TextView) findViewById(R.id.employerupgradecost); TextView amount2 = (TextView) findViewById(R.id.employerupgradeamount); TextView earnings2 = (TextView) findViewById(R.id.employerupgradeearnings); earnings2.setText("You earn "+$employerupgrade1level+" casual worker(s) every 3 hours."); cost2.setText("Costs " + df.format($employerupgrade1cost) + " Business Bucks."); amount2.setText("You have " + noDecimals.format($employerupgrade1level) + " casual employers."); } updatemoney(); timer(); } }, 1000); } public void offlineEarnings() { SharedPreferences sharedpreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); lastTime = sharedpreferences.getString("currentTime", currentTime); currentTime = String.valueOf(System.currentTimeMillis()); timeDifference = (Double.valueOf(currentTime)) - Double.valueOf(lastTime); timeDifferenceMinutes = (timeDifference / 1000) / 60; timeDifferenceSeconds = Double.valueOf(timeDifference) / 1000; $offlineMoneyEarned = ($employeeupgrade1level / 10) * timeDifferenceSeconds; $money = $money + $offlineMoneyEarned; $managercounter = (600 / $managerupgrade1level)*18; $employercounter = (600 / $employerupgrade1level) * 18; if ($employercounter > 0) { Double $offlineEmployeesEarned = Double.valueOf(Math.round(timeDifferenceSeconds / $employercounter)); $employeeupgrade1level = $offlineEmployeesEarned + $employeeupgrade1level; } else $offlineEmployeesEarned = 0; if ($managercounter > 0) { Double $offlineEmployeesEarned = Double.valueOf(Math.round(timeDifferenceSeconds / $managercounter)); $managerupgrade1level = $offlineEmployeesEarned + $managerupgrade1level; } else $offlineEmployersEarned = 0; drawEarnings(); } public void drawEarnings(){ if (debugmode == 1) { SimpleDateFormat DateFormatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); //get string String timeSinceLastPlayed = "Time since you last played: " + noDecimals.format(timeDifferenceSeconds) +" seconds ("+ df.format((timeDifferenceSeconds/60)) + " minutes or " + df.format(((timeDifferenceSeconds / 60)/60)) + " hours.)"; String dateLastPlayed = "Date of last session: " + DateFormatter.format(new Date(Long.valueOf(lastTime))); String offlineMoneyEarned = "Money earned since last session: " + df.format($offlineMoneyEarned) + "."; String offlineEmployeesEarned = "Employees earned since last session: " + $offlineEmployeesEarned + ". "; String offlineEmployersEarned = "Employers earned since last session: " + $offlineEmployersEarned + ". "; //get textview TextView tvTimeSinceLastPlayed = (TextView) findViewById(R.id.timeSinceLastPlayed); TextView tvDateLastPlayed = (TextView) findViewById(R.id.dateLastPlayed); TextView tvOfflineMoneyEarned = (TextView) findViewById(R.id.offlineMoneyEarned); TextView tvOfflineEmployeesEarned = (TextView) findViewById(R.id.offlineEmployeesEarned); TextView tvOfflineEmployersEarned = (TextView) findViewById(R.id.offlineEmployersEarned); //set text string tvTimeSinceLastPlayed.setText(timeSinceLastPlayed); tvDateLastPlayed.setText(dateLastPlayed); tvOfflineEmployeesEarned.setText(offlineEmployeesEarned); tvOfflineMoneyEarned.setText(offlineMoneyEarned); tvOfflineEmployersEarned.setText(offlineEmployersEarned); //make text visible tvOfflineEmployeesEarned.setVisibility(View.VISIBLE); tvOfflineMoneyEarned.setVisibility(View.VISIBLE); tvDateLastPlayed.setVisibility(View.VISIBLE); tvTimeSinceLastPlayed.setVisibility(View.VISIBLE); tvOfflineEmployersEarned.setVisibility(View.VISIBLE); } } public void buyEmployeeUpgrade1(View view) { if ($money >= $employeeupgrade1cost) { $money = $money - $employeeupgrade1cost; $employeeupgrade1level = $employeeupgrade1level + 1; $employeeupgrade1earnings = $employeeupgrade1level / 10; $allupgrades = $employeeupgrade1earnings + $allupgrades; double $randomCost = 1.05 + (1.4 - 1.05) * random.nextDouble(); $employeeupgrade1cost = $employeeupgrade1cost * $randomCost; //employee upgrade TextView cost = (TextView) findViewById(R.id.employeeupgradecost); TextView amount = (TextView) findViewById(R.id.employeeupgradeamount); TextView earnings = (TextView) findViewById(R.id.employeeupgradeearnings); earnings.setText("You earn " + noDecimals.format($employeeupgrade1earnings) + " BBs every second."); cost.setText("Costs " + df.format($employeeupgrade1cost) +" Business Bucks."); amount.setText("You have " + noDecimals.format($employeeupgrade1level) + " casual workers."); } else $cantafford = 1; } public void buyEmployerUpgrade1(View view) { if ($money >= $employerupgrade1cost) { $money = $money - $employerupgrade1cost; $employerupgrade1level = $employerupgrade1level + 1; double $randomCost = 1.05 + (1.4 - 1.05) * random.nextDouble(); $employerupgrade1cost = $employerupgrade1cost * $randomCost; $employercounter = (600 / $employerupgrade1level) * 18; $employerupgrade1earnings = $employerupgrade1level; TextView cost = (TextView) findViewById(R.id.employerupgradecost); TextView amount = (TextView) findViewById(R.id.employerupgradeamount); TextView earnings = (TextView) findViewById(R.id.employerupgradeearnings); earnings.setText("You earn "+$employerupgrade1level+" casual worker(s) every 3 hours."); cost.setText("Costs " + df.format($employerupgrade1cost) + " Business Bucks."); amount.setText("You have " + noDecimals.format($employerupgrade1level) + " casual employers."); } else $cantafford = 1; } public void buyManagerUpgrade1(View view) { if ($money >= $managerupgrade1cost) { $money = $money - $managerupgrade1cost; $managerupgrade1level = $managerupgrade1level + 1; double $randomCost = 1.05 + (1.4 - 1.05) * random.nextDouble(); $managerupgrade1cost = $managerupgrade1cost * $randomCost; $managercounter = (600 / $managerupgrade1level) * 18; $managerupgrade1earnings = $managerupgrade1level; TextView cost = (TextView) findViewById(R.id.managerupgradecost); TextView amount = (TextView) findViewById(R.id.managerupgradeamount); TextView earnings = (TextView) findViewById(R.id.managerupgradeearnings); earnings.setText("You earn "+noDecimals.format($managerupgrade1level)+"casual employer(s) every 3 hours."); cost.setText("Costs " + df.format($managerupgrade1cost) + " Business Bucks."); amount.setText("You have " + noDecimals.format($managerupgrade1level) + " casual managers."); } else $cantafford = 1; }
So I've fixed it. New offlineEarnings() code is this; public void offlineEarnings() { SharedPreferences sharedpreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); lastTime = sharedpreferences.getString("currentTime", currentTime); currentTime = String.valueOf(System.currentTimeMillis()); timeDifference = (Double.valueOf(currentTime)) - Double.valueOf(lastTime); timeDifferenceMinutes = (timeDifference / 1000) / 60; timeDifferenceSeconds = Double.valueOf(timeDifference) / 1000; $offlineMoneyEarned = ($employeeupgrade1level / 10) * timeDifferenceSeconds; $money = $money + $offlineMoneyEarned; if ($employerupgrade1level > 0) { $offlineEmployeesEarned = (Double.valueOf(Math.round(timeDifferenceSeconds) / $employercounter)); $employeeupgrade1level = $offlineEmployeesEarned + $employeeupgrade1level; } else $offlineEmployeesEarned = 0; if ($managerupgrade1level > 0) { $offlineEmployersEarned = (Double.valueOf(Math.round(timeDifferenceSeconds) / $managercounter)); $employerupgrade1level = $offlineEmployeesEarned + $employerupgrade1level; } else $offlineEmployersEarned = 0; drawEarnings(); }
List View Footer is leaving spaces and not getting removed
I am using list view footer which is just a button. Whenever i am updating the list with load more button it add extra space at the bottom. Also i am trying to remove the footer when all d data is loaded. Initialing the button in oncreate btnLoadMore = new Button(getActivity()); btnLoadMore.setText("Load More"); btnLoadMore.setWidth(700); btnLoadMore.setHeight(30); Then in post Execute mainAdapter = new SimpleAdapter( getActivity(), mainfooditems, R.layout.list_mealiteml, new String[] {KEY_FLFOODNAME,KEY_FLCALORIES,KEY_FLFOODID,KEY_FLFAT,KEY_FLCARBS,KEY_FLPROTEIN,KEY_FLBRAND,KEY_FLSERVING}, new int[] { R.id.nameone,R.id.uiduid,R.id.mtvfoodid,R.id.fatoutputval,R.id.carbsoutval,R.id.proteinsoutval,R.id.tvbrandnameone,R.id.tvservingone }); // updating listview listMain.addFooterView(btnLoadMore); listMain.setAdapter(mainAdapter); mainAdapter.notifyDataSetChanged(); state3(); And state3 is as follows: public void state3(){ search.clearFocus(); setListViewHeightBasedOnChildren(listMain); setListViewHeightBasedOnChildren(listCustom); setListViewHeightBasedOnChildren(listRecent); tvError.setVisibility(View.INVISIBLE); tvMessage.setVisibility(View.INVISIBLE); finalfoodidint=Integer.parseInt(finalfoodid); if(finalfoodidint > oldlastid){ System.out.println("1.5 + " + finalfoodidint); System.out.println("1.6 + " + oldlastid); } else if(finalfoodidint == oldlastid){ //listMain.removeFooterView(btnLoadMore); listMain.removeFooterView(btnLoadMore); System.out.println("1.7 + " + finalfoodidint); System.out.println("1.8 + " + oldlastid); } else{ listMain.removeFooterView(btnLoadMore); System.out.println("1.9 + " +finalfoodidint); System.out.println("1.10 + " + oldlastid); } }
Try calling notifyDataSetChanged() on the list when you remove an header. Try adding this line at the end of public void state3() listMain.getAdapter().notifyDataSetChanged();
I changed my code in public void state3 to public void state3(){ search.clearFocus(); listMain.removeFooterView(btnLoadMore); tvError.setVisibility(View.INVISIBLE); tvMessage.setVisibility(View.INVISIBLE); finalfoodidint=Integer.parseInt(finalfoodid); if(finalfoodidint > oldlastid){ listMain.addFooterView(btnLoadMore); System.out.println("1.5 + " + finalfoodidint); System.out.println("1.6 + " + oldlastid); } else if(finalfoodidint == oldlastid){ //listMain.removeFooterView(btnLoadMore); listMain.removeFooterView(btnLoadMore); System.out.println("1.7 + " + finalfoodidint); System.out.println("1.8 + " + oldlastid); } else{ listMain.removeFooterView(btnLoadMore); System.out.println("1.9 + " +finalfoodidint); System.out.println("1.10 + " + oldlastid); } listMain.setAdapter(mainAdapter); mainAdapter.notifyDataSetChanged(); setListViewHeightBasedOnChildren(listMain); setListViewHeightBasedOnChildren(listCustom); setListViewHeightBasedOnChildren(listRecent); } Also changed post execute to mainAdapter = new SimpleAdapter( getActivity(), mainfooditems, R.layout.list_mealiteml, new String[] {KEY_FLFOODNAME,KEY_FLCALORIES,KEY_FLFOODID,KEY_FLFAT,KEY_FLCARBS,KEY_FLPROTEIN,KEY_FLBRAND,KEY_FLSERVING}, new int[] { R.id.nameone,R.id.uiduid,R.id.mtvfoodid,R.id.fatoutputval,R.id.carbsoutval,R.id.proteinsoutval,R.id.tvbrandnameone,R.id.tvservingone }); // updating listview state3();
change your "setListViewHeightBasedOnChildren" method like below. public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition return; } int totalHeight = 0; int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST); for (int i = 0; i < listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); listView.requestLayout(); }
How to pass a file into another class when uploaded with JFileChooser
I am trying to take in a file from a JFileChooser that I can then pass into my TextStatistics class. I can't seem to keep reference to the file... Any help would be greatly appreciated. Thanks! ProcessText.java: public class ProcessText extends JPanel implements ActionListener { static private final String newline = "\n"; JButton openButton; JButton calculate; JTextArea log; JFileChooser fc; public ProcessText() { super(new BorderLayout()); log = new JTextArea(5, 20); log.setMargin(new Insets(5, 5, 5, 5)); log.setEditable(false); JScrollPane logScrollPane = new JScrollPane(log); JPanel buttonPanel = new JPanel(); // use FlowLayout buttonPanel.add(openButton); buttonPanel.add(calculate); // Add the buttons and the log to this panel. add(buttonPanel, BorderLayout.PAGE_START); add(logScrollPane, BorderLayout.CENTER); } public void actionPerformed(ActionEvent e) { File file = null; TextStatistics stat = null; if (e.getSource() == openButton) { int returnVal = fc.showOpenDialog(ProcessText.this); if (returnVal == JFileChooser.APPROVE_OPTION) { file = fc.getSelectedFile(); stat = new TextStatistics(file); } } if (e.getSource() == calculate) { log.append(stat.toString()); } } /** Returns an ImageIcon, or null if the path was invalid. */ protected static ImageIcon createImageIcon(String path) { java.net.URL imgURL = ProcessText.class.getResource(path); if (imgURL != null) { return new ImageIcon(imgURL); } else { System.err.println("Couldn't find file: " + path); return null; } } private static void createAndShowGUI() { // Create and set up the window. JFrame frame = new JFrame("FileChooserDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Add content to the window. frame.add(new ProcessText()); // Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { // Schedule a job for the event dispatch thread: // creating and showing this application's GUI. SwingUtilities.invokeLater(new Runnable() { public void run() { // Turn off metal's use of bold fonts UIManager.put("swing.boldMetal", Boolean.FALSE); createAndShowGUI(); } }); } } TextStatistics.java public class TextStatistics implements TextStatisticsInterface { public Scanner fileScan; public int[] countLetters = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // gives the starting values for count of each letter. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //initial amount of each letter. countLetters[0] corresponds to 'a' //countLetters[1] to 'b' and so on. public int[] length = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //keeps word frequency lengths 0, 0, 0, 0, 0, 0, 0 }; int lineCount = 0; //keeps track of lines int wordCount = 0; //keeps track of words int charCount = 0; //keeps track of characters double avg = 0; double avgFinal = 0; //average word length String strLine = ""; String largestWord; File file; ArrayList<Integer> line; //line with longest word length /** * reads in one file at a time and one line at a time to determine the * statistics described above. * * #author Ryleigh More */ public TextStatistics(File file) { Scanner scan; try { scan = new Scanner(file); this.file = file; line = new ArrayList<Integer>(); int largestIndex = 0; while (scan.hasNextLine()) { strLine = scan.nextLine().toLowerCase(); lineCount++; charCount += strLine.length() + 1; StringTokenizer tokenizer = new StringTokenizer(strLine, " , .;:'\"&!?-_\n\t12345678910[]{}()##$%^*/+-"); for (int i = 0; i < strLine.length(); i++) { char theLetter = strLine.charAt(i); if (theLetter >= 'a' && theLetter <= 'z') countLetters[theLetter - 'a']++; while (tokenizer.hasMoreTokens()) { String theWord = tokenizer.nextToken(); int currentWordLength = theWord.length(); if (currentWordLength > largestIndex) { largestWord = theWord; largestIndex = currentWordLength; line.clear(); } if (largestWord.equals(theWord)) { line.add(lineCount); } if (currentWordLength < 23 && currentWordLength > 0) { length[currentWordLength]++; } wordCount++; } } } for (int j = 1; j < length.length; j++) avg += (length[j] * j); avgFinal = avg / wordCount; scan.close(); } catch (FileNotFoundException e) { System.out.println(file + " does not exist"); } } /** * puts all the statistics in a String for printing by the ProcessText * class. * * #return s * #author Ryleigh Moore */ public String toString() { DecimalFormat two = new DecimalFormat("#0.00"); String s = "Statistics for " + file + "\n" + "======================================================\n" + lineCount + " Lines\n" + wordCount + " Words\n" + charCount + " Characters\n" + "-----------------------------------------" + "\na= " + countLetters[0] + "\t n= " + countLetters[13] + "\nb= " + countLetters[1] + "\t o= " + countLetters[14] + "\nc= " + countLetters[2] + "\t p= " + countLetters[15] + "\nd= " + countLetters[3] + "\t q= " + countLetters[16] + "\ne= " + countLetters[4] + "\t r= " + countLetters[17] + "\nf= " + countLetters[5] + "\t s= " + countLetters[18] + "\ng= " + countLetters[6] + "\t t= " + countLetters[19] + "\nh= " + countLetters[7] + "\t u= " + countLetters[20] + "\ni= " + countLetters[8] + "\t v= " + countLetters[21] + "\nj= " + countLetters[9] + "\t w= " + countLetters[22] + "\nk= " + countLetters[10] + "\t x= " + countLetters[23] + "\nl= " + countLetters[11] + "\t y= " + countLetters[24] + "\nm= " + countLetters[12] + "\t z: " + countLetters[25] + "\n-----------------------------------------" + "\n Length Frequency" + "\n ------- ---------"; for (int q = 1; q < length.length; q++) { if (length[q] > 0) s += "\n\t" + q + " =\t" + length[q]; } s += "\nThe average word length = " + two.format(avgFinal) + "\nThe longest word is '" + largestWord + "' and is on line " + line + "\n======================================================"; return s; }
public void actionPerformed(ActionEvent e) { File file = null; TextStatistics stat = null; if (e.getSource() == openButton) { int returnVal = fc.showOpenDialog(ProcessText.this); if (returnVal == JFileChooser.APPROVE_OPTION) { file = fc.getSelectedFile(); stat = new TextStatistics(file); } } if (e.getSource() == calculate) { log.append(stat.toString()); } } The thing is, when you press the openButton, it creates the new TextStatisics but that's it. It doesn't append the text the the JTextArea. You only do that with the press of calculate. So when openButton is pressed, the local TextStatistics is created, then nothing is don't with it, so it's tossed out. When calculate is pressed, the log tries to append a null TextStatistics. So you can either append the TextStatistics stat to the log inside of the if (e.getSource() == openButton) { or make TextStatistics stats a global class member that will persist between button presses. So when openButton is pressed, TextStatisitcs stat will persist to a calculate button press.
Every time actionPerformed runs, it makes a new variable stat and sets it to null. But you actually want two different calls to actionPerformed to use the same copy of the variable. I would recommend moving the declaration TextStatistics stat = null; out of actionPerformed and putting it at the top of the class, before all the methods, so that stat becomes a field of the class. That way, its value will survive from one actionPerformed call to the next.
Dynamic textviews not have perfect click listener or touch Listener
this is my method to implement number of textview as per the word in sentence. each word have click event or touch event. static ArrayList<TextView> sentence(String[] arr, LinearLayout linelay_wordIn1) { if (linelay_wordIn1.getChildCount() > 0) linelay_wordIn1.removeAllViews(); if (allTextView != null) { allTextView.remove(txt); allTextView.clear(); System.out.println("hello remove all textview here"); } else { System.out.println("hello all textview array is null here"); } String str1 = ""; for (int i = 0; i < arr.length; i++) { str1 = str1 + arr[i].toString(); System.out.println(" senctence separte in word " + arr[i] + " words" + arr.length); } /* listview for getting textview */ System.out.println("sentence " + str1.toString() + "str1 length :: " + str1.length()); txt = new TextView[arr.length]; LinearLayout.LayoutParams lp; lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.CENTER; // lp.setMarginStart(arr.length); for (int j = 0; j < arr.length; j++) { txt[j] = new TextView(contextG); txt[j].setId(j); txt[j].setBackgroundResource(Color.TRANSPARENT); txt[j].setTextSize(60); txt[j].setTypeface( Typeface.createFromAsset(contextG.getAssets(), "TIMES.TTF"), Typeface.BOLD); txt[j].setText(arr[j]); txt[j].setLayoutParams(lp); txt[j].setTextColor(Color.BLACK); txt[j].setOnTouchListener(myListner); System.out.println("txt[j]" + j + "id " + txt[j].getId()); allTextView.add(txt[j]); /* add textview into arraylist */ linelay_wordIn1.addView(txt[j], j); } return allTextView; } my touch Listener code is here public static OnTouchListener myListner = new OnTouchListener() { #Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub TextView tv = (TextView) v; //Layout layout = ((TextView) v).getLayout(); String str = tv.getText().toString(); int x = (int) event.getX(); int y = (int) event.getY(); //if (layout != null) { //int line = layout.getLineForVertical(y); //int characterOffset = layout.getOffsetForHorizontal(line, x); //Log.i("index", "" + characterOffset); //} System.out.println(" str of sentence :: " + str.toString()); if (Music.playing()) { // do nothing } else { try { /* Music renew for memory leak problems */ Music.renewMediaPlayer(); /*--------------------*/ if (str.equalsIgnoreCase("I ")) { Music.play(contextG, sent_audio1[0]); } else if (str.equals("like ")) { Music.play(contextG, sent_audio1[1]); } else if (str.equals("to ")) { Music.play(contextG, sent_audio1[2]); } else if (str.equals("ski.")) { Music.play(contextG, sent_audio1[3]); tooltip(tool1, 0, 3, x, y);// tool1 is for guide text // array // and 0 // for index } else if (str.equals("When ")) { Music.play(contextG, sent_audio2[0]); tooltip(tool2, 0, 0, x, y); } else if (str.equals("the ")) { Music.play(contextG, sent_audio2[1]); tooltip(tool2, 0, 1, x, y); } else if (str.equals("snow ")) { Music.play(contextG, sent_audio2[2]); tooltip(tool2, 0, 2, x, y); } else if (str.equals("falls, ")) { Music.play(contextG, sent_audio2[3]); } else if (str.equals("head ")) { Music.play(contextG, sent_audio2[5]); tooltip(tool2, 1, 5, x, y); } else if (str.equals("slopes.")) { float x1 = event.getX(); float y1 = event.getY(); Music.play(contextG, sent_audio2[8]); tooltip(tool2, 2, 8, x1, y1); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } return true; } }; here : number words store in string array to set as text in textviews /* sentence here */ static String[] words1 = { "I ", "like ", "to ", "ski." }; static String[] words2 = { "When ", "the ", "snow ", "falls, ", "I ", "head ", "to ", "the ", "slopes." }; static String[] words3 = { "My ", "Children ", "join ", "me ", "on ", "the ", "trip ", "to ", "the ", "hills. " }; static String[] words4 = { "We ", "ride ", "in ", "cable ", "cars ", "to ", "the ", "top ", "of ", "the ", "hill. " }; static String[] words5 = { "The ", "snow ", "sparkles ", "in ", "the ", "sunshine ", "as", "we ", "ski ", "the ", "trails. " }; static String[] words6 = { "I ", "pass ", "many ", "novice ", "skiers ", "as ", "they ", "struggle ", "to ", "stay ", "up. " }; static String[] words7 = { "I ", "try ", "to ", "watch ", "out ", "as ", "I ", "whiz ", "by. " }; static String[] words8 = { "If ", "I ", "do ", "not, ", "I ", "will ", "fall ", "too. " }; here is : one method to show another toast on textview array x and y position on each and every click. static void tooltip(String[] arr, int toolstringindex, int placeindex, float x, float y) { FrameLayout layout = new FrameLayout(contextG); layout.setBackgroundResource(R.drawable.tool_tip_img); TextView tv = new TextView(contextG); // set the TextView properties like color, size etc tv.setTextColor(Color.BLACK); tv.setTextSize(40); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( android.widget.FrameLayout.LayoutParams.WRAP_CONTENT, android.widget.FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.TOP); lp.leftMargin = 10; tv.setLayoutParams(lp); // set the text you want to show in Toast tv.setText(arr[toolstringindex]); layout.addView(tv); // // int[] values = new int[2]; float viewx = allTextView.get(placeindex).getX(); float viewy = allTextView.get(placeindex).getY(); // // int x = values[0]; // // int y = values[1]; System.out.println(" hello x::" + x + 50 + "y :: " + y); Toast toast = new Toast(contextG); toast.setGravity(Gravity.CENTER_VERTICAL, (int) x, (int) y - 80); toast.setDuration(Toast.LENGTH_LONG); toast.setView(layout); toast.show(); } now actual problem is that x and y position not coming perfectly .its showing somewhere else on screen so, i didnt get it what to do? if any one have better idea for this please let me to implement this . some line of code will be helpful to me.please help me. Thanks in advance
Change this: LinearLayout.LayoutParams lp; lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.CENTER; to this: LinearLayout.LayoutParams lp; lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.NO_GRAVITY; lp.setMargins(x, y, maxX, maxY); the maxX and maxY are irrelevant just set them to text width and height.
Android change color of a string without XML
I would like to change the color of the string "title" from a json object and put it in a listview with an array adapter without XML. I have tried a lot of examples of stackoverflow, but I am not sure, if the array adapter, which I am using, is the right one. When I was testing the examples I always became the same exception: RuntimeException: Unable to start activity ComponentInfo Any suggestions? Thank you! public class TermineDetail extends ListActivity { static JSONArray jArray; static JSONObject jObject; ArrayAdapter<String> adapter; static int clickedPosition; static String title; public void getJsonArrayAndClickedPosition(JSONArray array, int position) { this.jArray = array; this.clickedPosition = position; System.out.println("clickedPosition " + clickedPosition); } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); adapter = new ArrayAdapter<String>(this.getBaseContext(), R.layout.listview_simple_layout, this.getJsonResource()); } public ArrayList<String> getJsonResource() { ArrayList<String> listItems = new ArrayList<String>(); try { for (int i = 0; i < jArray.length(); i++) { if (i == clickedPosition) { jObject = jArray.getJSONObject(i); title = (String) jObject.get("title"); TextView tv = (TextView) findViewById(R.id.text_simple_listview); tv.setText(Html.fromHtml("Your big island <b>ADVENTURE!</b>")); listItems.add("\n" + "\n" + jObject.getString("title") + "\n" + "\n" + "\n" + "Datum: " + jObject.getString("termin") + "\n" + "\n" + "Uhrzeit: " + jObject.getString("time") + "\n" + "\n" + "Beschreibung: " + jObject.getString("text") + "\n" + "\n" + "Location: " + jObject.getString("location") + "\n" + "\n" + "Kontaktperson: " + jObject.getString("contactperson") + "\n" + "\n" + "Kontaktdaten: " + jObject.getString("contactdata") + "\n" + "\n"); setListAdapter(adapter); } } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return listItems; } }
Have you added your activity to your manifest file?