This is a android quiz app code snippet which load the question from text file.
I want to shuffle the question and answer after every next click so how can i implement random function ?
https://github.com/gitssk/quizfun/blob/master/src/ssk/quizfun/QuizFunActivity.java
https://github.com/gitssk/quizfun/blob/master/res/raw/questions.txt
private void loadQuestions() throws Exception {
try {
InputStream questions = this.getBaseContext().getResources()
.openRawResource(R.raw.questions);
bReader = new BufferedReader(new InputStreamReader(questions));
StringBuilder quesString = new StringBuilder();
String aJsonLine = null;
while ((aJsonLine = bReader.readLine()) != null) {
quesString.append(aJsonLine);
}
Log.d(this.getClass().toString(), quesString.toString());
JSONObject quesObj = new JSONObject(quesString.toString());
quesList = quesObj.getJSONArray("Questions");
Log.d(this.getClass().getName(),
"Num Questions " + quesList.length());
} catch (Exception e){
} finally {
try {
bReader.close();
} catch (Exception e) {
Log.e("", e.getMessage().toString(), e.getCause());
}
}
}
https://github.com/gitssk/quizfun/blob/master/src/ssk/quizfun/QuizFunActivity.java
I will refrain from posting much code because I think you should attempt it on your own. It is seriously not that tough. I will give you an approach though.
You have quesList = quesObj.getJSONArray("Questions");. So quesList is the list of questions that is a JSONArray. You want to shuffle this. Just do this:
Get the length of the quesList array. Let's call it len.
Create a simple arrayList called quesOrder containing integers 0 to len.
List<Integer> quesOrder = new ArrayList<>();
for (int i = 0; i <= len; i++)
{
quesOrder.add(i);
}
Once you have the quesOrder array. Just do Collections.shuffle(quesOrder);. Now when you get questions from your quesList array, just get the index from quesOrder list. And you will have a randomized selection. Put it together in a function for convenience.
Related
yesterday I published my application which I tested on my phone and worked as intended. When my friends downloaded it using 3G and not WiFi my application failed to download all the content and as a result it crashed. I used a headless fragment which runs an AsyncTask in order to download the content (which is some photos) my guess is that it took a lot of time for some photos and skipped them, throwing some timeOut exception. My question is would this be avoided if instead of an fragment I used a service to run my AsyncTask and download the content?
private ArrayList<Monument> processJsonData(JSONObject jsonObj) throws IOException{
try{
JSONArray posts=jsonObj.getJSONArray(TAG_POSTS);
ArrayList<Monument> monuments = new ArrayList<Monument>();
for (int i=0; i<posts.length(); i++){
JSONArray attachments = c.optJSONArray(TAG_ATTACHMENTS);
if(attachments!=null){
int lengthSize;
if(attachments.length()<3)
lengthSize=attachments.length();
else
lengthSize=3;
for(int j=0;j<lengthSize;++j){
JSONObject atta = attachments.getJSONObject(j);
JSONObject images = atta.optJSONObject(TAG_IMAGES);
if(images!=null){
JSONObject medium = images.getJSONObject(TAG_MEDIUM);
String url_image = medium.getString(TAG_URL_IMAGE);
String id = atta.getString("id");
String filename =title.replace(" ","")+id+".nomedia";
File destination = new File(MyApplication.getPhotoStorage() ,filename);
URL url = new URL (url_image);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream(destination);
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
localPhotosUrl.add(destination.getAbsolutePath());
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Edit so I made these changes in my code now I'm dealing with the connectionTimeout exception but I can't catch it properly
#Override
protected String doInBackground(String... args) {
JSONParser jParser = new JSONParser();
JSONObject jsonObj = jParser.getJSONFromUrl(url);
Log.d("check1",url);
try {
listOfObjects.addAll(processJsonData(jsonObj));
} catch (Exception e) {
e.printStackTrace();
onDownloadFailed(this);
} finally {
jsonObj=null;
}
return "done";
}
protected void onDownloadFailed(downloadUrl task) {
System.out.println(task.tag+" failed to download");
if(dtask1.cancel(true))
Log.d("TASK1", "Canceled");
if(dtask2.cancel(true))
Log.d("TASK2", "Canceled");
if(dtask3.cancel(true))
Log.d("TASK3", "Canceled");
if(dtask4.cancel(true))
Log.d("TASK4", "Canceled");
mCallbacks.onDownloadFailed();
}
private ArrayList<Monument> processJsonData(JSONObject jsonObj) throws IOException, SocketException, JSONException{
JSONArray attachments = c.optJSONArray(TAG_ATTACHMENTS);
if(attachments!=null){
int lengthSize;
if(attachments.length()<3)
lengthSize=attachments.length();
else
lengthSize=3;
for(int j=0;j<lengthSize;++j){
JSONObject atta = attachments.getJSONObject(j);
JSONObject images = atta.optJSONObject(TAG_IMAGES);
if(images!=null){
JSONObject medium = images.getJSONObject(TAG_MEDIUM);
String url_image = medium.getString(TAG_URL_IMAGE);
String id = atta.getString("id");
String filename =title.replace(" ","")+id+".nomedia";
File destination = new File(MyApplication.getPhotoStorage() ,filename);
try{
URL url = new URL (url_image);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream(destination);
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
localPhotosUrl.add(destination.getAbsolutePath());
}catch (SocketException e) {
throw new SocketTimeoutException();
}
}
}
}
Alright, so I don't know much about JSON, but that shouldn't affect this answer as a whole I don't think. It looks like your issue could be solved by better use of Exception handling.
At the moment you are not really handling the exception at all, merely catching it and printing the stack trace. Also, because the entire method is inside one try{ } statement the method is exiting if there is a problem dealing with any one of the attachments. Instead, you could include a try{ } block inside of your for loop. This way, if any one of the loop blocks failed (due to say an unstable connection), you can use the catch block to j--; and then Thread.sleep(4000);. That way, when an exception is thrown in the loop it will be caught, the loop will be jumped back to try the same section again, and there will be a pause to to wait for a better connection.
Example (Not tested);
for (int j = 0; j < lengthSize; ++j) {
try{
JSONObject atta = attachments.getJSONObject(j);
JSONObject images = atta.optJSONObject(TAG_IMAGES);
if (images != null) {
JSONObject medium = images.getJSONObject(TAG_MEDIUM);
String url_image = medium.getString(TAG_URL_IMAGE);
String id = atta.getString("id");
String filename = title.replace(" ", "") + id + ".nomedia";
File destination = new File(MyApplication.getPhotoStorage(), filename);
URL url = new URL(url_image);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream(destination);
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
localPhotosUrl.add(destination.getAbsolutePath());
}
}catch (Exception e){
Thread.sleep(4000);
j--;
}
}
You may also want to create a counter to see how many attempts have been made. If the code makes too many attempts you can then assume that it will never work and return from the method.
I hope this helps. Let me know how you get on.
Also, as an aside you should never really catch Exception. Better to catch the specific exception/s you are expecting so that you can deal with them differently depending on the Exception subtype. You don't want to catch a RunTimeException and try to handle it when there may be no effective way of doing so.
No. This won't be avoided. You cannot expect a connection to last for a long time. Anything can happen on the phone (battery exhausted, network signal lost, etc.)
You must code your app so that it properly checks if it has all the resources available and to retry (or better, resume) downloads that failed.
To increase your chances, break your resources in relatively small downloads instead of a huge file. Then the user does not have to download all from scratch when using 3G for instance.
Keep getting ArrayIndexOutOfBoundsException when trying to display a specific item form array list data displays fine in logcat but then after displaying throws exception at top please help is the code kind of new to android
public void loadData(){
InputStream file = ourContext.getResources().openRawResource(R.raw.cashpot);
BufferedReader reader = new BufferedReader(new InputStreamReader(file));
String line ="";
ArrayList<String> values = new ArrayList<String>();
try {
while((line = reader.readLine()) != null) {
values.add(line);
// String[] strings = line.split(",");
/*for(String s : strings) {
values.add(s);
}*/
}
reader.close();
//for(String s : values) Log.d("CSV Test", s);
for(int i = 0; i < values.size();i++){
String[] data = values.get(i).split(",");
Log.d("Test String",data[2] );
}
} catch (IOException e) {
e.printStackTrace();
}
}
Your some lines do not have comma(,)(or 1 comma) and you are trying to split them by comma and storing it in to data array. and you are accessing data[2] location. which might not been created that's why you are getting this exception.
There might not be a 3rd element in your array ,that is created after the split on ",".
You can print value of data before accessing data[2](that might not exist).
Or you can Debug your program and proceed step by step and monitoring the value of each variable.
I am desperatly trying to fix a bug that:
always happens in my emulator for Android versions 2.2, 2.3
never happens in emulator android versions 4.*
never happens in a real device (android 4.*)
It is the following IndexOutOfBoundsException exception:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{<myapppackage>}: java.lang.IndexOutOfBoundsException:
Invalid index 39, size is 0
In my app I am fecthing data from a json file that I am displaying as text. I've isoleted where the bug is coming from, it is when I call this method:
public String getItemValue(int id, String s) {
List<JsonItems> list = new ArrayList<JsonItems>();
try {
// CONVERT RESPONSE STRING TO JSON ARRAY
JSONArray ja = new JSONArray(s);
// ITERATE THROUGH AND RETRIEVE
int n = ja.length();
for (int i = 0; i < n; i++) {
// GET INDIVIDUAL JSON OBJECT FROM JSON ARRAY
JSONObject jo = ja.getJSONObject(i);
// RETRIEVE EACH JSON OBJECT'S FIELDS
JsonItems ji = new JsonItems();
ji.id = jo.getInt("id");
ji.text= jo.getString("text");
list.add(ji);
}
} catch (Exception e) {
e.printStackTrace();
}
return list.get(id).text;
}
My class JsonItems is very basic:
public class JsonItems{
int id;
String text;
}
Sample from my json file:
[
{"id":0,"text":"some text 0"},
{"id":1,"text":"some text 1"},
{"id":2,"text":"some text 2"}
]
Here is how I process content of my json file into a String
public static String fromJsonFileToString(String fileName, Context c) {
//JSONArray jArray = null;
String text = "";
try {
InputStream is = c.getAssets().open(fileName);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
text = new String(buffer);
} catch (IOException e) {
throw new RuntimeException(e);
}
return text;
}
Once again I repeat: the IndexOutOfBoundsException NEVER happens on a device with Android 4.* , it only happens when I test the app on emulators with Android 2.*
Any idea where it is coming from?
Thanks
First problem:
You are not reading your input stream correctly. Calling available literally does just that - it returns you the amount of data that is available to be read, when the call is made. This number may, or may not represent the entire content of the file.
Reading material for you:
How to Read a File in Java.
Writing and Creating Files
Note that there are helper libraries like Apache Commons IO that make it possible to read file contents in a single line of code (IOUtils.toString(inputStream)). Android doesn't support Java 7 yet but a noteworthy alternative is available in that release, with the Files.readAllLines method. In any case, you can make the below shown changes to your file reading code and it should work better:
public static String fromFileToString(String fileName, Context context) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
context.getAssets().open(fileName)));
String line = null;
StringBuilder builder = new StringBuilder(1024);
while ((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Second problem:
You do not do any bound check, to make sure that the argument you pass into your 'search' method:
public String getItemValue(int id, String s)
Does not exceed the length of the list of items you eventually calculate:
return list.get(id).text;
// ^
// -------------
// 'id' could be larger than the list size!
In any case, your current design doesn't at all match what you are really trying to do, aka, to determine the element in the JSON array that has an 'id' field matching what you supply to the method. You need to process the JSON data as a map, in order to be able to do this.
public String getItemValue(int id, String json) {
if(json == null || json.trim().equals("")) return null;
Map<Integer, JsonItems> map = new HashMap<Integer, JsonItems>(4);
try {
JSONArray ja = new JSONArray(json);
int n = ja.length();
for (int i = 0; i < n; i++) {
JSONObject jo = ja.getJSONObject(i);
JsonItems ji = new JsonItems();
ji.id = jo.getInt("id");
ji.text = jo.getString("text");
map.put(Integer.valueOf(ji.id, ji);
}
} catch(NumberFormatException nfe) {
throw new IllegalArgumentException("Invalid JSON format");
} catch (Exception e) {
throw new RuntimeException(e);
}
JsonItems item = map.get(id);
return item != null ? item.text : null;
}
Some quick notes:
JsonItems should be called JsonItem, to conform to good Java naming standards
You should really parse and store your JSON just once, to improve performance
You are really only using a minimal subset of your JSON data, you could actually determine the matching node within your for loop and directly return its value, without having to use an intermedia Java bean object
It's my first question, but I'll try to ask it well. Anyway, I'm trying to read data from a text file in Android, but for some reason it keeps returning nothing - namely, IndexOutOfBounds exception. All relevant code:
public Question getNextQuestion(int num) {
Log.d(TAG, array.toString());
return array.get(num+1);
}
public ArrayList<Question> getData(String str) throws NumberFormatException, IOException {
Log.d(TAG, "STARTING getData");
Log.d(TAG, str);
ArrayList<Question> a = new ArrayList<Question>();
String[] strline = str.split("//");
for (int j = 0; j < strline.length; j++) {
if (strline[j] == null) {
strline[j] = "TESTING";
Log.d(TAG, strline[j]);
}
}
int num = 0;
int x = 0;
String y = strline[x];
while (x == 0 || y != null) {
num++;
String[] data = y.split("//");
Log.d(TAG, y);
if (data.length >= 7) {
a.add(new Question(Integer.parseInt(data[0]), data[1], data[2], data[3], data[4], data[5], Integer.parseInt(data[6])));
Log.d(TAG, a.get(a.size()).getText());
}
else if (data.length >= 3) {
a.add(new Question(Integer.parseInt(data[0]), data[1], data[2]));
Log.d(TAG, a.get(a.size()).getText());
}
x++;
if (x < strline.length)
y = strline[x];
else
break;
}
for (int i=0; i<a.size(); i++){
Log.d(TAG, a.get(i).getText());
}
Log.d(TAG, "ENDING getdata");
return a;
}
public ArrayList<Question> openFile() throws IOException {
Log.d(TAG, "STARTING openFile()");
//FileReader fr = new FileReader("data/data/scibowl.prog/questionsb.txt");
FileInputStream fis;
String storedString = "";
try {
fis = openFileInput("questionsb.txt");
DataInputStream dataIO = new DataInputStream(fis);
String strLine = null;
while ((strLine = dataIO.readLine()) != null) {
storedString = storedString + strLine;
}
dataIO.close();
fis.close();
}
catch (Exception e) {
}
array = getData(storedString);
Log.d(TAG, "DID open file, ending openFile()");
return array;
}
This will print in LogCat:
onCreate done
STARTING openFile()
STARTING getData
ENDING getdata
DID open file, ending openFile()
right before Toast.makeText
[]
Caused by: java.lang.IndexOutOfBoundsException: Invalid location 1, size is 0
at java.util.ArrayList.get(ArrayList.java:341)
at scibowl.prog.Round.getNextQuestion(Round.java:55)
at scibowl.prog.RoundView.<init>(RoundView.java:26)
at scibowl.prog.Round.onCreate(Round.java:35)
I've tried practically everything from StringBuffers to FileInputStreams to BufferedReaders, and read the related Android documentation, though feel free to tell me I'm not reading it hard enough. Does anybody know why I keep getting arrays with no elements?
Text file for reference, albeit slightly edited to conform with the blockquote rules:
1//On the standard electromagnetic spectrum, which frequency is between gamma rays and ultraviolet rays?//Radio waves//Microwaves//X-rays//Infrared waves//1
2//Which waves on the electromagnetic spectrum roughly encompasses frequencies of 10^9 Hz to 10^12 Hz?//Visible Light//Gamma Rays//Ultraviolet Rays//Microwaves//3
3//Approximately what percentage of the US’s power comes from coal?//30%//40%//50%//60%//0
4//If a 100-kilogram person starts walking from rest and accelerates to 4.0 m/s over 2 seconds at constant acceleration, how much work does he do?//600 J//800 J//1200 J//2000 J//1
Your logcat suggests it is crashing on line 55 in the method getNextQuestion, which I believe is:
return array.get(num+1);
Also, your logcat suggests that you're trying to access a value in the array that doesn't exist. Meaning you're trying to retrieve the item at index 1 (the second item, I believe), but the size of your array is 0, so there are no items that you can get.
So chances are that in getData you're failing to actually return an ArrayList like you intend. Or the ArrayList you return is empty.
So All I'm trying to do is create a dynamic expandableListView Currently It works if I just do the groupViews. The problem comes in when I have to populate the children of those groupViews.. I don't know if I'm doing something wrong, or if theres another better way to do it. If anyone knows please let me know. I'm open to anything.
Currently I'm pulling my data off a server and the error I'm getting is java null pointer exception. So I'm thinking it might have something to do with how big I specified my array sizes?
private static String[][] children = new String[7][4];
private static String[] groups = new String[7];
Here is the rest of the code when I try to populate the View.
public void getData(){
try {
int tempGroupCount = 0;
URL food_url = new URL (Constants.SERVER_DINING);
BufferedReader my_buffer = new BufferedReader(new InputStreamReader(food_url.openStream()));
temp = my_buffer.readLine();
// prime read
while (temp != null ){
childrenCount = 0;
// check to see if readline equals Location
//Log.w("HERasdfsafdsafdsafE", temp);
// start a new location
if (temp.equalsIgnoreCase("Location"))
{
temp = my_buffer.readLine();
groups[tempGroupCount] = temp;
tempGroupCount++;
Log.w("HERE IS TEMP", temp);
}
temp = my_buffer.readLine();
while (temp.equalsIgnoreCase("Location") == false){
Log.w("ONMG HEHREHRHERHER", temp);
children[groupCount][childrenCount] = "IAJHSDSAD";
childrenCount++;
temp = my_buffer.readLine();
}
groupCount++;
}
my_buffer.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("IO EXCEPTION", "Exception occured in MyExpandableListAdapter:" + e.toString());
}
}
to me it looks like an error in the loop - as you are reading another line without checking is it null
your while loop should look something like this methinks:
// prime read
while (temp != null ){
int childrenCount = 0;
// check to see if readline equals Location
// start a new location
//Log.w("HERasdfsafdsafdsafE", temp);
if (temp.equalsIgnoreCase("Location"))
{
temp = my_buffer.readLine();
groups[tempGroupCount] = temp;
tempGroupCount++;
Log.w("HERE IS TEMP", temp);
}
//>>remove following line as that one isn't checked and
//>>you are loosing on a line that is potentialy a child
//temp = my_buffer.readLine();
//>>check do you have first item to add subitems
else if (tempGroupCount>0){
while (temp.equalsIgnoreCase("Location") == false){
Log.w("ONMG HEHREHRHERHER", temp);
children[tempGroupCount-1][childrenCount] = "IAJHSDSAD";
childrenCount++;
temp = my_buffer.readLine();
}
//>>next counter is probably not need but can't see if you're using it somewhere else
//groupCount++;
}
I would first replace strings array to some 2d collection for example arraylist2d ( you can google it ) so you could easally add and remove data from list. If you created adapter that extends BaseExpandableListAdapter everything should be handled without any problems.
About NULLPointer, could you paste stacktrace or more info on which line it occurs ?