I have a little question concerning the usage of
Android Resouce by ID / Change image onClick / no change of imageView
I have established my images picked randomly here, using:
#Override
public void onClick(View v) {
Log.d("MYAPP", "Like-Button clicked");
/*imageViewMeasurement.setImageResource(R.drawable.p13);*/
TypedArray images = getResources().obtainTypedArray(R.array.images_primes);
int chosenImageNumber = (int) (Math.random() * images.length());
// setImageResource to the random chosenImageNumber
imageViewMeasurement.setImageResource(images.getResourceId(chosenImageNumber, R.color.colorPrimaryDark));
images.recycle();
// Confirmation if the random generator picked a Number from the array
String chosenImageNumberTest = String.valueOf(chosenImageNumber);
Log.d("MYAPP Choice Number", chosenImageNumberTest);
}
This runs through an array of 40 images and will be repeated one time. So every image will be shown two times (?).
That's the question:
When I use a pool of 40 images randomly for 80 picks, do I get every image two times (draw with cover), or is every try a new random out of those 40 images (draw without replacement), so the reult could be number 1 for 4 times and number 38 for 0 times? Is there an other function that prevents to such a behaviour?
Best,
tigercode
As I understand your code, you would NOT get every image twice, you would get some images multiple times and some images might not even come at all.
Don't use Random if you don't actually want Random. By the laws of probability you'd only have a chance of getting the same image twice, not a certainty.
You could use a boolean array to keep track of which numbers have already been used (if index n is true this means the number has already been taken e.g.).
Edit: The comment below from vims liu is right. It's much more efficient run time wise to define a list of indexes and shuffle the list.
So better use the following solutions, even if it won't make a big differences considering your numbers are quite small.
List<Integer> indexes = Arrays.asList(1,2,3,4,5,6,7,8,9,10); //...
Collections.shuffle(indexes);
You can then iterate through the indexes list and use the current number as current index.
Sorry for answering late, and sorry for a beginner question, I'm new to android developing.
I changed my code (and write my comment what I understood it does:
#Override
public void onClick(View v)
Log.d("MYAPP", "Like-Button clicked");
// 1. Get the array of images in the images_primes XML-List AS int (number of every image in array)
TypedArray images = getResources().obtainTypedArray(R.array.images_primes);
// 2. Takes an array-list and shuffles it
List<Integer> indexes = Arrays.asList(1,2,3,4,5,6,7,8,9,10); //...
Collections.shuffle(indexes);
// Great, it shuffles! ;-)
Log.d("MYAPP", indexes);
// 3. takes the number from the shuffled image list
int chosenImageNumber = (int) (indexes);
// 2. Old code: picks a number out of the image array from 1. / commented out
//int chosenImageNumber = (int) (Math.random() * images.length());
// 4. setImageResource to the random chosenImageNumber
imageViewMeasurement.setImageResource(images.getResourceId(chosenImageNumber, R.color.colorPrimaryDark));
images.recycle();
// Confirmation if the random generator picked a Number from the array
String chosenImageNumberTest = String.valueOf(chosenImageNumber);
Log.d("MYAPP Choice Number", chosenImageNumberTest);
}
Step 1: Open the list of images (as items), use it as array (1,2,3)
Step 2: Have a second number of arrays (possible to connect 1 and 2), SHUFFLE! :-)
Step 3: Here is my problem. If I got that right, I get a string-list from step 2, which numbers I can't use as Int (Error "Integer to int" won't work) -> result should be a number (?)
Step 4: Number from 3 should be used to pick out an image from list / array from 1.
I think, there is a thinking error on my side.
Thanks for your help in advance,
tigercode
Related
I need an idea on doing this. I'm not good at math.
Maybe it have build in function which i haven't found yet.
I have an array which consists of 2048 data.
I need to get on 250 value out of this.
I'm thinking of
2048/250 = 8.19
which means, I take value on each increment of 8 position in an array.
Is there a function to do this?
Not that I'm aware of, I think the problem is to balance iterations and the randomness of the sampling.
So the naive approach
dataSet.indexedMapNotNull { i, data ->
if (i % 8 == 0) data else null
}
That would run through all the array, so you only need 250 iterations, not dataSet.size iterations. So what about if we iterate 250 times and for each of those we take the 8th times of it
val sample = mutableListOf<DataType>()
for (i in 1..250) {
val positionInDataSet = (i * 8) - 1 //minus one adjust the index for the size
val case = dataSet[positionInDataSet]
sample.add(case)
}
Another alternative would be to simply use copy methods from collections, but the problem is you lose your sampling
dataSet.subArray(0, 250)
Sub-array didn't sample the data in a pseudo-random way but only got the first 250 and that would be biased. The upside is usually array copies methods are a log of N.
Another option would be to randomize things even more by not getting data each 8 but a random position until we hit our desired sample size.
val sample = mutableSetOf<DataType>()
while (sample.size != 250) {
val randomPosition = Random.nextInt(0, dataSet.size)
val randomSelection = dataSet[randomPosition]
sample.add(randomeSelection)
}
Here we use a set, because a Set guarantee unique elements, so you have completely random 250 elements from your data set. The problem with this is that randomness on the position could make the same randomPosition more than once, so you iterate on the data set more than 250 times, this could even be factorial which in larger data sets it would happen and is considered the lowest performance.
I have is how to generate random images without repeating , as an example driving in an array 15 images and 7 images to send imageview but that are not repeated .
int[] img={ R.drawable.ima1,R.drawable.ima2,R.drawable.ima3,R.drawable.ima4,R.drawable.ima5,R.drawable.ima6,R.drawable.ima7,R.drawable.ima8,R.drawable.ima9,R.drawable.ima10,R.drawable.ima11,R.drawable.ima12,R.drawable.ima13,R.drawable.ima14,R.drawable.ima15};
int [] game= new int[7];
Random numerRan = new Random();
for (int i=0;i<game.length ;i++)
{
int num= numerRan.nextInt(17);
int x= img[num];
game[i]=img[num];
}
img1.setImageResource(juego[0]);
img2.setImageResource(juego[1]);
img3.setImageResource(juego[2]);
img4.setImageResource(juego[3]);
img5.setImageResource(juego[4]);
img6.setImageResource(juego[5]);
img7.setImageResource(juego[6]);
img8.setImageResource(juego[7]);
When I press the button control images to the score rando the position that was generated . The problem I have is that images are repeated.
I am using 2 arrangements the first is to save all the images and the second keep the random images that will assign imageview .
Instead of using an int[] array, use a List<Integer> instead, such as an ArrayList<Integer>.
That way, you'll be able to use Collections#shuffle(), which will have the desired effect. It'll randomly permute your list, in a non-repeating way. All you'll have to do later is to iterate on that List.
For more info, please refer to the Collections documentation.
You can also convert that array to a List, like the following:
List<Integer> myList = Arrays.asList(img);
For more info about that, take a look at this question.
I have completed a phonegap app which pools gps cordinate data every 10 sec to the server. now according to the calculations 8 hours of tracking it will store around 8*60*6=2880 records per user. my current requirement is limited to use of 20 user. (basically it tracks a users rout travelled)
There are two parts to the question:
what is the best way to store the data and retrieve it as fast as possible.
is it possible to display 2880 coordinates at a time on google maps API v3 ? if not, what is the best way to display the rout traveled?
I am having good results with 90 or so points, for one of my demos, but the enormous 2880 records per user per 8 hours is what worries me.
Thanks
EDIT 1
Although this is an old question , I recently worked on a project where I displayed about 10K points on the map, I hope my observations would help the future visitors:
The google maps as if now do not have a hard limit on the number of points you can display on the client side.
The number of points you can display on the client side is entirely dependent on the client side `Hardware` , bigger the number of points using a jpeg or gif marker , slower will be the renders , when moving around or zooming in and out
To have huge number of pointers on the map with a minimal performance hit, precomputing the number of points needed to be rendered before and after pan or zoom occurs will help a lot.
So here is a possible solution:
First of all, you need to find out how many points Google Maps API can handle and still show the line. I think this will just take some testing or researching. Anyways once you find your magical number of points to display to plot your path then take that number and multiply it by 2/3.
For instance if a good path needs have say 90 points then calculate 90*2/3
The reason for 2/3 is that the following loop will return a max number of points that is averagely equal to 3/2 times the variable we use so using. 60 would give us on average 90 plots. There is a case where the most returned plots would be (2 * (magical number of points)) - 1 for instance say we want on average of 90 points then we could in some rare cases have (2*(90*2/3))-1 = 119 points You will just have to do some testing after implementation to make sure that your magical number of points works good for maps with 2/3 of the magical number of points and 2 * magical number of points -1. I hope this isn't too confusing... I tried to explain as best I can.
The rest of this is going to be sudo code. You will have to adapt it for whatever language you connect to MySQL with:
//get the total number of rows returned
var total_rows = mysql->num_rows;
//calculate max to be 2/3 times your magic number for max plots, i.e. 90
var max_plots = 90*2/3;
//define empty plots array to fill with coordinates
var plots = array();
//check if total_rows is less than max_plots then:
if(total_rows > max_plots){
//find the quotient of the the divident total_rows and the divisor max_plots rounded down to the nearest whole int
var quotient = floor(total_rows/max_plots);
//define variable i to use in loop
var i = 1;
//loop through returned rows
while(row = mysql->fetch_row()){
//return only rows that are the first, last, or are dividable by the quotient evenly; Note: if your language supports it, use the Modulus operator like (i % quotient) == 0 for the last or statement.
if(i == 1 || 1 == total_rows || (i - (i * (floor(i/quotient)))) == 0){
//set plots to use on map
plots[] = array(
'lat' => row['lat'],
'lon' => row['lon'],
);
}
//increment counting variable
i++;
}
// else if total_rows less than or equal to max_plots retrieve all plots
} else {
while(row = mysql->fetch_row()){
plots[] = array(
'lat' => row['lat'],
'lon' => row['lon'],
);
}
}
This may not be the best way as it still requires to retrieve all of the rows from the database, but it does solve how to only print a selected maximum amount evenly spaced on the Google map.
Note: Be sure that your query orders the rows by an auto incrementing key or some other way so that the plots will be in order that they were entered into the database.
The most detailed maps would be a map with (2 * magic_plot_number) - 1 and your least details map would contain magic_plot_number or if lower, the number of total_plots. That being said an 8 hour tracking would plot a path with points every 7 minutes and 51 seconds totaling 61 points over 8 hours using the magic plot number of 90. The more plots the closer number of points will be to 2/3 * the magic plot number
I hope this helps you with this situation.
For my specific purposes, I need to generate a whole number between 1 and 120 inclusive (which I can do no problem).
Once that number has been generated, I need to pull it from the pool so it can't be generated again.
Continue this process until all numbers are exhausted, at which point, the pool fills back up and we start over again.
How could I go about doing this?
Generate the whole list of numbers from 1 to 120. Shuffle the list. Take the first element (and remove it)
List<Integer> list = new LinkedList<Integer>();
for (int i = 1; i <= 120; i++) {
list.add(i)
}
Collections.shuffle(list);
...
int random = list.remove(0);
...
int otherRandom = list.remove(0);
Check for list.empty() in case you run out of numbers. If empty, create the list again and shuffle it.
The obvious way to do it is to fill a list with all numbers between 1 and 120, then when you need a random number, generate one between 1 and the list count, take the item from the list at that index, return it to the caller and then remove it from the list. Once the list is empty, refill and keep picking indices.
I believe that all you need is to shuffle an array or a collection. You can refer to this question for example.
I've managed to get my allocations down to next to nothing using DDMS (great tool), this has drastically reduced my GCs to about 1 or 2 every 3 minutes. Still, I'm not happy because those usually cause a noticeable delay in the game (on some phones) when you interact with it.
Using DDMS, I know what the allocations are, they are Strings being converted from integers used to display game information to the HUD.
I'm basically doing this:
int playerScore = 20929;
String playerScoreText = Integer.toString(playerScore);
canvas.drawText(playerScoreText, xPos, yPos);
This happens once each frame update and the HUD system is modular so I plug things in when I need and this can cause 4 or 5 hud elements to allocate Strings and AbstractStringBuilders in DDMS.
Any way to reduce these further or eliminate all the String allocations and just reuse a String object?
Thanks,
Albert Pucciani
Reading your question reminded me of one of Robert Greens articles that I read quite some time ago. It discusses your problem almost identically. http://www.rbgrn.net/content/290-light-racer-20-days-32-33-getting-great-game-performance . Skip down to day 33 and start reading.
Remember the last int score and its string representation. On a new frame check if the score is the same. If the same, then no need to create a new string - just use the old one.
Here's what I've done in the past. This will eliminate string allocations.
I create a char[] of a size that will be at least as large as the maximum number of characters you will need to display on the screen. This means that you should select a maximum high score that is achievable in the game. The way you have it now let's you display a score as high as 2^31-1 which is insanely huge, it's not practical with respect to the game. Keep in mind, this is your game, so it's ok to limit the max score to something more reasonable in the context of the game. Pick a number that will virtually be impossible to achieve. Setting this limit will then set you up to be able to not have to muck around with converting large integers to String objects.
Here's what's required:
First, you need to be able to separate the digits in an integer and convert them to char without creating String objects. Let's say you want to convert the integer of 324 into three separate characters '3','2','4' to be placed in the text char[]. One way you can do this is by taking the value 324 and do a mod 10 to get the lowest digit. So 324%10 = 4. Then divide the value by ten and do another mod 10 to get the next digit. So (324/10)%10 = 2, and (324/100)%10 = 3.
int score = 324;
int firstPlaceInt = score%10; // firstPlace will equal 4
int tensPlaceInt = (score/10)%10; // tensPlace will equal 2
int hundresPlaceInt = (score/100)%10; // hundredsPlace will equal 3
You will have to do the above in a loop, but this expresses the idea of what you're trying to do here.
Next, with these digits you can then convert them to chars by referencing a character map. One way to do this is you can create this character map by making a char[] of size 10 and placing values 0 - 9 in indexes 0 - 9.
char[] charMap = {'0','1','2','3','4','5','6','7','8','9',};
So doing this:
int score = 324;
char firstPlace = charMap[score%10];
char tenslace = charMap[(score/10)%10];
char hundredsPlace = charMap[(score/100)%10];
Will create the chars you need for the 3 digits in score.
Now, after all that, I would limit the highest score to say 99,999 (or whatever makes sense in your game). This means the largest "string" I would need to display is "Score: xx,xxx". This would require a char[] (call it text for this example) of size 13. Initialize the first 7 characters with "Score: ", these will never need to change.
char[] text = new char[13];
text[0] = 'S';
text[1] = 'c';
text[2] = 'o';
text[3] = 'r';
text[4] = 'e';
text[5] = ':';
text[6] = ' ';
The next 6 will vary based on the score. Note, that you may not necessarily fill in all 6 of those remaining characters, therefore you need to create an int (call it scoreCount for this example) which will tell you how many characters in the text char[] are actually relevant to the current score in the game. Let's say I need to display "Score: 324", this only takes 10 chars out of the 13. Write the 3 chars for the score of 324 into char[7] to char[9], and set scoreCount to 10 to indicate the number of valid characters in the char[].
int scoreCount = 7;
text[9] = charMap[score%10]; // This is firstPlace
text[8] = charMap[(score/10)%10]; // This is tensPlace
text[7] = charMap[(score/100)%10]; // This is hundredsPlace
scoreCount = 10;
You will probably have to do the above in a loop, but this should express the general idea of what you're trying to do here.
After that, you can just use drawText (char[] text, int index, int count, float x, float y, Paint paint). index will be 0, and count will be scoreCount which indicates how many characters in text should be drawn. In the example above, it doens't matter what's in text[10] to text[12], it's considered invalid. You can continue to update text[] using the character map, and this should not create any objects.
I hope this helps. The code above isn't very robust, but I wrote it out as more of an expression of the ideas I'm trying to convey. You will have to create your own loops and manage the data properly within your code, but this sums up the mechanics of what needs to happen to avoid the use of Strings/StringBuilder/StringBuffer/etc.