Is there some pattern on Random() method? - android

I started making a project where there are goats! Yeah Goats.
Currently there is only one function, when I click a goat, it create another goat in a Random position.
I realized that there is a pattern of positions:
Here is the code:
public class GameActivity extends Activity {
private int[] arrGoats = new int[5];
private RelativeLayout battlefield;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
battlefield = (RelativeLayout) findViewById(R.id.rel_battlefield);
arrGoats[0] = R.drawable.amarelo;
arrGoats[1] = R.drawable.azul;
arrGoats[2] = R.drawable.branco;
arrGoats[3] = R.drawable.verde;
arrGoats[4] = R.drawable.vermelho;
criarCabra(60, 100);
}
private void criarCabra(float x, float y) {
int cabraImg = arrGoats[new Random().nextInt(4)];
ImageView cabra = new ImageView(this);
cabra.setImageResource(cabraImg);
cabra.setX(x);
cabra.setY(y);
LayoutParams params = (LayoutParams) new LayoutParams(MarginLayoutParams.WRAP_CONTENT,
MarginLayoutParams.WRAP_CONTENT);
params.width = 150;
params.height = 120;
cabra.setLayoutParams(params);
cabra.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
criarCabra(new Random().nextInt(2000), new Random().nextInt(1000));
}
});
battlefield.addView(cabra);
}
}
I would like to know why this pattern is being created although I'm using Random().NextInt() to define goats positions.
Am I crazy?

First, you're creating a new Random object each time. In Android, the initial seed is derived from current time and the identity hash code:
public Random() {
// Note: Using identityHashCode() to be hermetic wrt subclasses.
setSeed(System.currentTimeMillis() + System.identityHashCode(this));
}
For two objects created in sequence, the identity hash codes are close to each other. On my Android KitKat Dalvik VM, I get identity hash codes that differ only by 32.
The currentTimeMillis() does not provide much difference to the seeds either.
The random itself is a linear congruential generator of the form
random[i+1] = a * random[i] + b (mod c)
where random[0] is the seed and a, b and c are parameters.
Based on this answer, similar seeds indeed produce similar results in linear congruential generators:
The reason you're seeing similar initial output from nextDouble given similar seeds is that, because the computation of the next integer only involves a multiplication and addition, the magnitude of the next integer is not much affected by differences in the lower bits.
Hence, your two successively generated Randoms with default seeds will produce values that seem to be correlated and make your goats get positioned on a line.
To fix it, use the same Random object and/or a more random pseudorandom generator than a linear congruential one.

You are creating new instances of Random with every call to criarCabra and every invocation of onClick. Create a single static instance of Random, then re-use it.
Unless you really know what you're doing and have a very good reason to be doing it, the best practice is to only create one instance of Random per program and then poll it whenever you need additional values.

Related

Dynamic creation of layout and swapping them in android

I want a create a quiz app in android in which I want to dynamically change the questions for every 60 seconds in the same layout where the number of question vary dynamically.
I planned to do a quiz system which creates layout dynamically and changes it between some interval.
I tried with a countdown Timer but it's not accurate.
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_student_main);
String[] fr={"National Bird Of India?","How is your life?","What's yourFavourite dish","Whats your hobby","Whats your skin color"};
String s="";
int i;
i=0;
int seconds=10000;
CountDownTimer countDownTimer = new CountDownTimer((fr.length*seconds)+seconds, seconds)
{
#Override
public void onTick(long l)
{
String s = String.valueOf(l);
char[] f = s.toCharArray();
textView.setText(String.valueOf(i+1));
textView2.setText(fr[i]);
if(!s.equals(String.valueOf(f[0])))
{
textView2.setText(fr[i]);
i++;
}
else
{
s=String.valueOf(f[0]);
}
}
#Override
public void onFinish()
{
Intent intent=new Intent(getBaseContext(),Finish_quiz.class);
startActivity(intent);
finish();
}
};
countDownTimer.start();
}
Your question is very vague but looks like fragments are what you need. Assuming you know about Fragments in Android, they are designed for the exact purpose of changing your UI look and feel on the go within the same container (which in Android terminology is the Activity component).
So consider you have 50 questions and all of them roughly falls under 5 segments requiring you to design 5 different layouts. So what you do is define 5 different fragments with their distinct look and feel. Albeit you can always reuse individual UI components among fragments which is what you should do, thus requiring you to write lesser code.
Now when you want to display a different UI for the next question, you can just replace the current fragment in the UI. For performance sake, you can create instance of all the 5 fragments type in your activity start and just go on replacing the current viewable fragment.
Please read upon - https://developer.android.com/training/basics/fragments/fragment-ui.html

How to manage shinobichart life-cyle in a Fragment with JSON data on lineseries? Android

I am asking this question because, this is quiet no clear to me why my graph does not get update each time the user select to parse data for 1day or 1week or 1month basis. A similar How to update/remove/insert new series/data in Shinobi Line Chart in android?
I attempted the answer provided by a member called Kai, apparently he works for shinobicontrols.
You may also also note that I have implemented the shinobichart library inside a GraphFragment that seats in a view pager, which imports android.android.support.v4.app.Fragment;
ViewPagerAdapter class imports
import android.support.v4.app.FragmentPagerAdapter;
and the fragment transaction that calls the GraphFragment class budles an array of graph data from another activity that parses the JSON graphdata. I am trying to make this question clear so that when you read my code atleast you get an idea that the problem is not the JSON data because is pulled accordingly based on 1week, 1day or 1month. The issues is that Shinobichart does remove the series and its data but does not plot new parsed data. I read shinobichart user-guide how to handle chart-life cycle but was unable to find the solution I want. I also read ChartFragment handle onPause and onResume for the developer and I wonder If the same applies to SupportChartFragment.
Here is my GraphFragment that integrates shinobichart.Hope someone can help. Thank you in advance.
public class GraphFragment extends Fragment implements OnClickListener,
ShinobiChart.OnCrosshairActivationStateChangedListener{
private static final int CROSSHAIR_INACTIVE_COLOR = Color.argb(255, 240, 240, 240);
private static final int CROSSHAIR_ACTIVE_COLOR = Color.argb(150, 0, 0, 0);
Context context;
String label_x[];
ArrayList<DataAssetGraph> alAssetGraph = new ArrayList<DataAssetGraph>();
Button btnOneDayG, btnOneWeekG, btnOneMonthG;
String endDate;
String assetId;
ProgressDialog dialog;
ShinobiChart shinobiChart;
LineSeries series;
SupportChartFragment chartFragment;
String startDate;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = null;
view = inflater.inflate(R.layout.fragment_chart, null);
initView(view);
if (getArguments() != null) {
alAssetGraph = (ArrayList<DataAssetGraph>) getArguments()
.getSerializable(WebElement.RECORDS);
if (alAssetGraph != null && alAssetGraph.size() > 0) {
// DrawGraph(alAssetGraph);
// Only setup the chart the first time the activity is created
if (savedInstanceState == null) {
// Log.d("Init Graph", "Retrieve"+ alAssetGraph);
chartFragment =
(SupportChartFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.chart);
shinobiChart = chartFragment.getShinobiChart();
// TODO: replace <license_key_here> with you trial license key
shinobiChart.setLicenseKey("sCVfKPnWajLtffqMjAxNTA0MThzdGVybmx5QHJpZ2h0Y2xpY2t" +
"tZWRpYS5jby56YQ==rveipQf9y4819/K4wLwWKR86Q1RIViUBTLEhBXAwh6q5zW53TgYi" +
"JcIUvc3S7DhTfH4KzUNeol9Rc5rXrzLOBnzP0TStc8n+eytCBhUFEgR21Cv7gq1dLEvOu" +
"tLENUwUtZ6Crk+Z8syIKEuyfZ8/1gtPvHIc=BQxSUisl3BaWf/7myRmmlIjRnMU2cA7q+" +
"/03ZX9wdj30RzapYANf51ee3Pi8m2rVW6aD7t6Hi4Qy5vv9xpaQYXF5T7XzsafhzS3hbBo" +
"kp36BoJZg8IrceBj742nQajYyV7trx5GIw9jy/V6r0bvctKYwTim7Kzq+YPWGMtqtQoU=" +
"PFJTQUtleVZhbHVlPjxNb2R1bHVzPnh6YlRrc2dYWWJvQUh5VGR6dkNzQXUrUVAxQnM5b2" +
"VrZUxxZVdacnRFbUx3OHZlWStBK3pteXg4NGpJbFkzT2hGdlNYbHZDSjlKVGZQTTF4S2Zwe" +
"WZBVXBGeXgxRnVBMThOcDNETUxXR1JJbTJ6WXA3a1YyMEdYZGU3RnJyTHZjdGhIbW1BZ21PTT" +
"dwMFBsNWlSKzNVMDg5M1N4b2hCZlJ5RHdEeE9vdDNlMD08L01vZHVsdXM+PEV4cG9uZW50Pk" +
"FRQUI8L0V4cG9uZW50PjwvUlNBS2V5VmFsdWU+");
// Create the series
createLineSeries(alAssetGraph);
// Add this Activity as a listener for any crosshair changes
shinobiChart.setOnCrosshairActivationStateChangedListener(this);
}
} else {
}
}
return view;
}
private void initView(View view)
{
btnOneDayG=(Button)view.findViewById(R.id.btnOneDayG);
btnOneWeekG=(Button)view.findViewById(R.id.btnOneWeekG);
btnOneMonthG=(Button)view.findViewById(R.id.btnOneMonthG);
btnOneDayG.setSelected(true);
btnOneDayG.setOnClickListener(this);
btnOneMonthG.setOnClickListener(this);
btnOneWeekG.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnOneDayG:
btnOneWeekG.setSelected(false);
btnOneMonthG.setSelected(false);
if(!btnOneDayG.isSelected())
{
btnOneDayG.setSelected(true);
startDate=GlobalData.getDateBeforeOneDay();
getGraphHistory(startDate);
System.out.println("Btn Date 1 day: %tc"+startDate);
}
break;
case R.id.btnOneWeekG:
btnOneDayG.setSelected(false);
btnOneMonthG.setSelected(false);
if(!btnOneWeekG.isSelected())
{
btnOneWeekG.setSelected(true);
startDate=GlobalData.getDateBeforeOneWeek();
getGraphHistory(startDate);
System.out.println("Btn Date 1 week: %tc"+startDate);
}
break;
case R.id.btnOneMonthG:
btnOneWeekG.setSelected(false);
btnOneDayG.setSelected(false);
if(!btnOneMonthG.isSelected())
{
btnOneMonthG.setSelected(true);
startDate=GlobalData.getDateBeforeOneMonth();
getGraphHistory(startDate);
System.out.println("Btn Date 1 Month: %tc"+startDate);
}
break;
default:
break;
}
}
private void createLineSeries(ArrayList<DataAssetGraph> alGraph) {
// TODO Auto-generated method stub
shinobiChart.getSeries();
// remove Series
while (shinobiChart.getSeries().size() > 0) {
shinobiChart.removeSeries(shinobiChart.getSeries().get(0));
}
// remove Axis
while (shinobiChart.getAllXAxes().size() > 0) {
shinobiChart.removeXAxis(shinobiChart.getAllXAxes().get(0));
}
while (shinobiChart.getAllYAxes().size() > 0) {
shinobiChart.removeYAxis(shinobiChart.getAllYAxes().get(0));
}
// Create the X-axis, showing ticks daily with a custom format and
// clipping the tick at the far right
DateTimeAxis xAxis = new DateTimeAxis();
// xAxis.setTitle("Date/Time");
xAxis.enableGesturePanning(true);
xAxis.enableGestureZooming(true);
xAxis.getDoubleTapBehavior();
// Create the Y-axis, clipping the tick at the top
NumberAxis yAxis = new NumberAxis();
// yAxis.setTitle("Temperature");
yAxis.enableGesturePanning(true);
yAxis.enableGestureZooming(true);
// Declare length of graph array
int length=alGraph.size();
LineSeries series = new LineSeries();
series.getStyle().getPointStyle().setPointsShown(false);
DataAdapter<Date, Double> data = new SimpleDataAdapter<Date, Double>();
for(int i=0;i<length;i++)
{
String dateString=alGraph.get(i).x_cord;
double y_cord= alGraph.get(i).y_cord;
Date x_cord=convertToDate(dateString);
data.add(new DataPoint<Date, Double>(x_cord, y_cord));
}
// reload and redraw the graph
series.setDataAdapter(data);
series.setCrosshairEnabled(true);
shinobiChart.addSeries(series, xAxis, yAxis);
series.getStyle().setLineColor(Color.WHITE);
System.out.println("Add Series");
// Style the chart and the crosshair
shinobiChart.getStyle().setPlotAreaBackgroundColor(
GraphFragment.CROSSHAIR_ACTIVE_COLOR);
shinobiChart.getCrosshair().getStyle().setLineColor(Color.BLUE);
shinobiChart.getStyle().setBackgroundColor(Color.WHITE);
// shinobiChart.getStyle().setPlotAreaBackgroundColor(Color.BLACK);
shinobiChart.getStyle().getBackgroundColor();
shinobiChart.getXAxis().getStyle().getGridlineStyle().setGridlinesShown(true);
shinobiChart.getYAxis().getStyle().getGridlineStyle().setGridlinesShown(true);
// Remember to redraw the chart to make the changes visible
shinobiChart.redrawChart();
}
private Date convertToDate(String dateString)
{
Date convertedDate= new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
try
{
convertedDate = dateFormat.parse(dateString);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
return convertedDate;
}
private void getGraphHistory(String start_date)
{
System.out.println("Get graph History: %tc"+ start_date);
dialog= new ProgressDialog(getActivity());
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage("Retrieving graph...");
dialog.setCanceledOnTouchOutside(false);
dialog.show();
endDate=GlobalData.getCurrentDate();
assetId=ComponentActivity.assetId;
new LoadAssetGraphTask(getActivity(),assetId, start_date,endDate)
{
#Override
protected void onPostExecute(ArrayList<DataAssetGraph> result)
{
super.onPostExecute(result);
if(dialog.isShowing())
dialog.dismiss();
if(result!=null && result.size()>0)
{
createLineSeries(result);
System.out.println("onPostExecute Called");
}
};
}.execute();
//}
}
#Override
public void onCrosshairActivationStateChanged(ShinobiChart chart) {
// Set the plot area background color depending on the crosshair's
// activation state
if (chart.getCrosshair().isActive()) {
chart.getStyle().setPlotAreaBackgroundColor(GraphFragment.CROSSHAIR_ACTIVE_COLOR);
chart.getLegend().getStyle().setTextColor(Color.WHITE);
}
else {
chart.getStyle().setPlotAreaBackgroundColor(GraphFragment.CROSSHAIR_INACTIVE_COLOR);
chart.getLegend().getStyle().setTextColor(Color.BLACK);
}
// Remember to redraw the chart to make the color change visible
chart.redrawChart();
}
I appreciate that it is some time since you have asked this. As it is unanswered, I will try to provide an answer, also in case other people ask similar questions.
Can you please post the rest of your code as it is difficult to get the full picture of what your code is doing? For example your layout files, Activity file and your LoadAssetGraphTask file.
In the meantime, I have created a simple application which has one main activity which contains a ViewPager. I have extended SupportChartFragment and I hold 3 charts in the ViewPager. I have 3 buttons in my Activity, which load 3, 6 and 12 months of data to the chart.
I have kept my data quite simple for the purposes of this exercise, I simply hard code it.
I was successful in being able to dynamically re-load my data upon clicking the buttons.
You can see my app on GitHub here:
https://github.com/Kai2k/ViewPagerChartFragment
I can make several observations about your code:
To reload your chart you do not necessarily need to remove your axes and the Series. Having said that, every time you add a data point to your DataAdapter, a full draw of the chart is invoked which may hamper performance. As such you may like to detach your DataAdapter from your Series, update your data and then re-attach it.
I notice you have made your Fragment implement OnClickListener. I noticed using this approach the chart was not initially updated, but in fact another chart within the ViewPager (which was currently off-screen) was updated instead. I notice that as I paged though my pages within the ViewPager, all of the contained charts were updated. At this point in time I am no expert on how the ViewPager class internally handles the creation and destruction of fragments, but this may certainly be an area to investigate further.
When I set the click listener in the Activity and 'push' the command to reload to the current fragment, it works.
You may also have an issue with your LoadAssetGraphTask, which I believe is an AsyncTask. Obviously I cannot see this code at present so I do not know what this class will be doing. Have you tried a simpler approach first, with dummy data within your Fragment (as I have) to rule out any issue with the AsyncTask?
SupportChartFragment and ChartFragment do handle life cycle call backs for you, so you do not need to override onPause or onResume. You may have issues however if you try to nest your Fragment inside another Fragment, because ChartFragment/SupportChartFragment is retained across Activity re-creation and the Android framework does not allow retained Fragments within other Fragments. If your use-case dictates this you may find using a ChartView a more suitable approach. In this case you would need to handle life cycle call backs.
If you wish to use the ChartFragment or SupportChartFragment, another approach might be to extend the class directly, rather than extend Fragment. This is the approach which I have taken in my app. With this approach you are less likely to encounter inflation issues when inflating nested fragments.
I hope that this helps. Thanks, Kai.
Disclaimer - I work for Shinobicontrols.

use array as a public array to save random number generation

I want to generate random number without duplicate, and i get this code
ArrayList<Integer> numbers = new ArrayList<Integer>();
Random randomGenerator = new Random();
int random = randomGenerator.nextInt(16)+1;
if (!numbers.contains(random))
{
numbers.add(random);
}
I want to use this code to generate an random id to choose which question to be displayed from database. When i answer the question, it should be generate a new random id. But if I used all the code above, the array becomes a new one, and it will not know what id has been generated before.
If I put the ArrayList<Integer> numbers = new ArrayList<Integer>(); on onCreate and the other codes in a public int random(), the numbers in cannot read the array that i have created on onCreate.
I want to ask, can I create the ArrayList<Integer> as a public array, so i just should declare it once on onCreate method and the whole class can use this array.
You can declare the ArrayList outside the onCreate method and initialize it inside that method.
Then happily use it in your activity.
So, this:
ArrayList<Integer> numbers = new ArrayList<Integer>();
goes UP in your code, after the class declaration (after the first { in your class)
and this:
Random randomGenerator = new Random();
int random = randomGenerator.nextInt(16)+1;
if (!numbers.contains(random))
{
numbers.add(random);
}
Can be put in your onCreate method
Declare your array separately from the handling it, for instance as the global class one.
public class ClassName {
ArrayList<Integer> name;
#Override
public void onCreate(...){
name = new ArrayList<Integer>();
}
public void yourMethod(...){
//your operations
}
}
In that way you can keep your array. I wouldn't create a public array, because if you define it as global and private, you have an access to it from the whole class. If you want to get access from other classes in a package, just create usual method:
public ArrayList<Integer> getArrayList(){
return name;
}
btw, I'd use Set<Integer> (here are docs) to solve that problem, because it doesn't allow you add duplicated items, so you may get rid of redundant if statement.

Divide two values obtained from EditText ad divide them by each other

Is it possible in Java code to divide two obtained values from two EditText boxes in an android app, and then divide them by each other to create a result?
Pretty much, the consumer of my application will be asked for two DIFFERENT, numerical values to be inputted into each box.
What I want to do with each value is produce a mathematical sum.
E.g.
If the first EditText box contains "22"
and the second EditText contains "11"
I want to be able to take those two values and divide them by each other to produce a value which I can further use.
In this case, that value produced would be 2.
22 / 11 = 2
I've already imported these two values into another Class (labeled DataHelper) through className.insert(stringName).
public class DataHelper extends Activity{
public static void insert(String firstFB, String firstRL) {
// TODO Auto-generated method stub
}
}
That's the Class for DataHelper with the two String values.
I have tried using IEEEremainder(x, y), but I don't know exactly how to use it since I am a novice at this language.
Can anyone give me some help with this? Any help at all will be appreciated.
Regards,
Mike.
if under standing rigtig you cut due
int one = int value1 / int vlaue2;
but then when you get the value from a edittext you get a string so you need to convert it to a int first int a = new Integer("value from edittext").intValue();
I believe you want something like this:
public class DataHelper extends Activity{
public static void insert(String firstFB, String firstRL) {
int fb = Integer.parseInt(firstFB);
int rl = Integer.parseInt(firstRL);
int division = fb / rl; // Or use double if needed
}
}

random number generator

I m trying to make a random number generator in android. My code has to start generating numbers in sets of 3 after clicking the "generate" button. So far i've coded a generator that can produce finite sets of 3 numbers each. What i want to create is a dynamic generator that keeps generating numbers.CODE:
`
public class Plot2Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Random myRandom = new Random();
Button buttonGenerate = (Button)findViewById(R.id.generate);
final TextView textGenerateNumber = (TextView)findViewById(R.id.generatenumber);
buttonGenerate.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
ArrayList<Object> Arry1 = new ArrayList<Object>();
for(int i=0;i<5;i++){
ArrayList<Integer> Arry = new ArrayList<Integer>();
for(int k=0;k<3;k++){
Arry.add(myRandom.nextInt(100));
}
Arry1.add(Arry);
}
textGenerateNumber.setText(String.valueOf(Arry1));
}
});
}
}
Do the same process in a loop and update an array from a background thread. For background thread look below link this may help you.
However if you don't want to generate frequently, Put a sleep() in your background thread for a second and than let it update your Array.
http://developer.android.com/reference/android/os/AsyncTask.html
Happy coding,
Krio
Article which may help,
http://www.dailygeek.de/using-asynctask-to-update-a-listactivity/
Above article shows how you can update your ListActivity in similar fashion you may update your Array.
Lets say create an activity which has AsycTask, and create a separate class such as,
public class RandomNumbers{}
Above class will have an Array list of numbers being generated,
And update this class's object from Background which eventually available to your UI Thread too. I hope I and clear enough.

Categories

Resources