【发布时间】:2017-03-28 17:10:45
【问题描述】:
我正在编写一个安卓应用程序,通过多项选择来测试我的饮料食谱。按下选择后,应用程序会为正确答案着色并生成一个新问题。然而,经过几轮后,它挂起,我找不到原因。我在下面发布了代码和布局。
package com.example.frances.rocksdrinks;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class Menu extends AppCompatActivity {
String[] allDrinks = {"BOURBON ON THE ROCKS", "SCOTCH ON THE ROCKS", "TOP SHELF SCOTCH ON THE ROCKS", "BLACK RUSSIAN", "SICILIAN KISS",
"GOD MOTHER", "GOD FATHER", "RUSTY NAIL", "NUTTY IRISHMAN", "STINGER", "KAMIKAZE", "PURPLE HOOTER", "WINDEX",
"RASPBERRY KAMIKAZE", "MUDSLIDE", "AFTER FIVE", "B~51", "B~52", "B~53", "OATMEAL COOKIE"};
Map<String, String> liquor = new HashMap<String, String>()
{{
put("bourbon on the rocks", "1 1/2 oz Bourbon Whiskey");
put("scotch on the rocks", "1 1/2 oz Scotch Whiskey");
put("top shelf scotch on the rocks", "1 1/2 oz Scotch Whiskey");
put("black russian", "1 1/4 oz Vodka & 3/4 oz Kahlua");
put("sicilian kiss", "1 1/4 oz Southern Comfort & 3/4 oz Amaretto");
put("god mother", "1 1/4 oz Vodka & 3/4 oz Amaretto");
put("god father", "1 1/4 oz Scotch & 3/4 oz Amaretto");
put("rusty nail", "1 1/4 oz Scotch & 3/4 oz Drambuie");
put("Nutty Irishman", "1 1/4 oz Baileys & 3/4 oz Frangelico");
put("stinger", "1 1/4 oz Brandy & 3/4 oz White Creme De Menthe");
put("kamikaze", "1 1/4 oz Vodka & 3/4 oz Triple Sec");
put("purple hooter", "1 1/4 oz Vodka & 3/4 oz Chambord");
put("windex", "1 1/4 oz Vodka & 3/4 oz Blue Curacao");
put("raspberry kamikaze", "1 1/4 oz Raspberry Vodka & 3/4 oz Triple Sec");
put("mudslide", "1/2 oz Kahlua & 1/2 oz Baileys & 1/2 oz Vodka");
put("after five", "1/2 oz Kahlua & 1/2 oz Baileys & 1/2 oz Peppermint Schnapps");
put("b~51", "1/2 oz Kahlua & 1/2 oz Baileys & 1/2 oz Frangelico");
put("b~52", "1/2 oz Kahlua & 1/2 oz Baileys & 1/2 oz Grand Marnier");
put("b~53", "1/2 oz Kahlua & 1/2 oz Baileys & 1/2 oz Amaretto");
put("oatmeal cookie", "1/2 oz Kahlua & 1/2 oz Baileys & 1/2 oz Goldschlager");
}};
Map<String, String> mixer = new HashMap<String, String>()
{{
put("bourbon on the rocks", "");
put("scotch on the rocks", "");
put("top shelf scotch on the rocks", "");
put("black russian", "");
put("sicilian kiss", "");
put("god mother", "");
put("god father", "");
put("rusty nail", "");
put("Nutty Irishman", "");
put("stinger", "");
put("kamikaze", "");
put("purple hooter", "");
put("windex", "");
put("raspberry kamikaze", "");
put("mudslide", "");
put("after five", "");
put("b~51", "");
put("b~52", "");
put("b~53", "");
put("oatmeal cookie", "");
}};
Map<String, String> garnish = new HashMap<String, String>()
{{
put("bourbon on the rocks", "None");
put("scotch on the rocks", "None");
put("top shelf scotch on the rocks", "None");
put("black russian", "None");
put("sicilian kiss", "None");
put("god mother", "None");
put("god father", "None");
put("rusty nail", "Lemon Twist");
put("Nutty Irishman", "None");
put("stinger", "Mint Leaf");
put("kamikaze", "Splash Lime Juice");
put("purple hooter", "Splash Lime Juice");
put("windex", "Splash Lime Juice");
put("raspberry kamikaze", "Splash Lime Juice");
put("mudslide", "None");
put("after five", "None");
put("b~51", "None");
put("b~52", "None");
put("b~53", "None");
put("oatmeal cookie", "None");
}};
Random r = new Random();
TextView choice1, choice2, choice3, choice4, answer, question;
String ans;
int qIndex;
String[] choices;
TextView correct;
Handler handler;
TextView pressed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
choice1 = (TextView) findViewById(R.id.choice1);
choice2 = (TextView) findViewById(R.id.choice2);
choice3 = (TextView) findViewById(R.id.choice3);
choice4 = (TextView) findViewById(R.id.choice4);
answer = (TextView) findViewById(R.id.answer);
question = (TextView) findViewById(R.id.question);
handler = new Handler();
createQuestion();
createAnswers();
question.setTextSize(21);
}
public void choice(View v)
{
pressed = (TextView) findViewById(v.getId());
answer.setVisibility(View.VISIBLE);
if (pressed.getText().toString() == choices[0])
{
pressed.setTextColor(Color.parseColor("#00BF00"));
answer.setText("CORRECT!");
answer.setTextColor(Color.parseColor("#00BF00"));
}
else
{
pressed.setTextColor(Color.parseColor("#F60000"));
answer.setText("WRONG!");
answer.setTextColor(Color.parseColor("#F60000"));
correct.setTextColor(Color.parseColor("#00BF00"));
}
handler.postDelayed(new Runnable() {
@Override
public void run() {
pressed.setTextColor(Color.parseColor("#777777"));
correct.setTextColor(Color.parseColor("#777777"));
answer.setVisibility(View.GONE);
createQuestion();
createAnswers();
}
}, 3000);
}
//if answer is a recipe, use 20sp as font size
private void createQuestion()
{
String[] qs = {"Which drink contains ", "What garnish does drink contain", "What mixer does drink use",
"Which of the following describes a drink"};
int i = r.nextInt(allDrinks.length);
ans = allDrinks[i];
qIndex = r.nextInt(qs.length);
String q = "";
if (qIndex != 0)
{
q = qs[qIndex].replace("drink", ans);
}
else
{
q = qs[qIndex] + liquor.get(ans.toLowerCase());
if (!mixer.get(ans.toLowerCase()).isEmpty())
{
q += " + " + mixer.get(ans.toLowerCase());;
}
if (!garnish.get(ans.toLowerCase()).equals("None"))
{
q += " + " + garnish.get(ans.toLowerCase());
}
}
question.setText(q + "?");
}
private void createAnswers()
{
choices = new String[4];
int count = 1;
String a = "";
if (qIndex == 3)
{
choices[0] = liquor.get(ans.toLowerCase());
if (!mixer.get(ans.toLowerCase()).isEmpty())
{
choices[0] += ", " + mixer.get(ans.toLowerCase());
}
if (!garnish.get(ans.toLowerCase()).equals("None"))
{
choices[0] += ", " + garnish.get(ans.toLowerCase());
}
while (count != 4)
{
int i = r.nextInt(allDrinks.length);
if (allDrinks[i] != ans)
{
a = liquor.get(allDrinks[i].toLowerCase());
if (!mixer.get(ans.toLowerCase()).isEmpty())
{
a += ", " + mixer.get(allDrinks[i].toLowerCase());
}
if (!garnish.get(allDrinks[i].toLowerCase()).equals("None"))
{
a += ", " + garnish.get(allDrinks[i].toLowerCase());
}
if (!Arrays.asList(choices).contains(a))
{
choices[count] = a;
count++;
}
}
}
}
else if (qIndex == 0)
{
choices[0] = ans;
while (count != 4)
{
int i = r.nextInt(allDrinks.length);
if (allDrinks[i] != ans)
{
a = allDrinks[i];
if (!Arrays.asList(choices).contains(a))
{
choices[count] = a;
count++;
}
}
}
}
else if (qIndex == 1)
{
String[] g = {"Splash Coke", "Splash Grenadine", "Splash Sprite", "None"};
choices[0] = garnish.get(ans.toLowerCase());
while (count != 4)
{
int i = r.nextInt(g.length);
if (g[i] != choices[0])
{
a = g[i];
if (!Arrays.asList(choices).contains(a))
{
choices[count] = a;
count++;
}
}
}
}
else
{
choices[0] = mixer.get(ans.toLowerCase());
while (count != 4)
{
int i = r.nextInt(allDrinks.length);
if (mixer.get(allDrinks[i].toLowerCase()) != choices[0])
{
a = mixer.get(allDrinks[i].toLowerCase());
if (!Arrays.asList(choices).contains(a))
{
choices[count] = a;
count++;
}
}
}
}
TextView[] cs = {choice1, choice2, choice3, choice4};
cs = shuffle(cs);
correct = cs[0];
for (int i = 0; i<4; i++)
{
if (qIndex == 3)
{
cs[i].setTextSize(12);
}
else
{
cs[i].setTextSize(18);
}
cs[i].setText(choices[i]);
}
}
private TextView[] shuffle(TextView[] arr)
{
int index;
TextView temp;
for (int i = arr.length - 1; i > 0; i--)
{
index = r.nextInt(i + 1);
temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
}
return arr;
}
}
这是布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/question"
android:layout_width="wrap_content"
android:layout_height="140sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20sp"
android:textSize="25sp"
android:layout_marginLeft="20sp"
android:layout_marginRight="20sp"
android:gravity="center"
android:textColor="@color/black"
android:text="Which drink contains 1/2 oz Jagermeister1/2 oz Peach Schnapps + Cranberry Juice"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300sp"
android:layout_marginTop="30sp">
<TextView
android:id="@+id/choice1"
android:layout_marginLeft="0sp"
android:background="@drawable/shadowsmall"
android:layout_width="180sp"
android:layout_height="130sp"
android:text="Screwdriver"
android:textSize="23sp"
android:textColor="#777777"
android:clickable="true"
android:onClick="choice"
android:gravity="center"/>
<TextView
android:id="@+id/choice2"
android:layout_marginLeft="180sp"
android:background="@drawable/shadowsmall"
android:layout_width="180sp"
android:layout_height="130sp"
android:text="Screwdriver"
android:textSize="23sp"
android:textColor="#777777"
android:clickable="true"
android:onClick="choice"
android:gravity="center"/>
<TextView
android:id="@+id/choice3"
android:layout_marginTop="130sp"
android:layout_marginLeft="0sp"
android:background="@drawable/shadowsmall"
android:layout_width="180sp"
android:layout_height="130sp"
android:text="Screwdriver"
android:textSize="23sp"
android:textColor="#777777"
android:clickable="true"
android:onClick="choice"
android:gravity="center"/>
<TextView
android:id="@+id/choice4"
android:layout_marginTop="130sp"
android:layout_marginLeft="180sp"
android:background="@drawable/shadowsmall"
android:layout_width="180sp"
android:layout_height="130sp"
android:text="1 oz vodka, 50/50 orange and cranberry, lime"
android:textSize="23sp"
android:onClick="choice"
android:textColor="#777777"
android:clickable="true"
android:gravity="center"/>
</RelativeLayout>
<TextView
android:layout_marginTop="-40sp"
android:id="@+id/answer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="30sp"
android:textColor="@color/green"
android:textStyle="bold"/>
</LinearLayout>
logcat 开始挂起时会给出这个输出
03-28 12:51:05.460 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 9.490ms
03-28 12:51:15.605 29897-29913/com.example.frances.rocksdrinks I/art: Background sticky concurrent mark sweep GC freed 14222(509KB) AllocSpace objects, 0(0B) LOS objects, 24% free, 1825KB/2MB, paused 5.062ms total 11.585ms
03-28 12:51:23.159 29897-29913/com.example.frances.rocksdrinks I/art: WaitForGcToComplete blocked for 10.660ms for cause Background
03-28 12:52:48.768 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 6.314ms
03-28 12:52:58.857 29897-29913/com.example.frances.rocksdrinks I/art: Background sticky concurrent mark sweep GC freed 30454(1094KB) AllocSpace objects, 0(0B) LOS objects, 38% free, 1708KB/2MB, paused 5.259ms total 13.447ms
03-28 12:54:07.970 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.891ms
03-28 12:54:24.523 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.254ms
03-28 12:54:45.569 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.900ms
03-28 12:54:49.078 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 8.536ms
03-28 12:54:57.595 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.742ms
03-28 12:55:30.525 29897-29912/com.example.frances.rocksdrinks I/art: WaitForGcToComplete blocked for 7.450ms for cause HeapTrim
03-28 12:55:34.194 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.670ms
03-28 12:55:56.904 29897-29913/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.412ms
03-28 12:56:09.293 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 6.397ms
03-28 12:56:37.481 29897-29913/com.example.frances.rocksdrinks I/art: Background sticky concurrent mark sweep GC freed 29570(1064KB) AllocSpace objects, 0(0B) LOS objects, 38% free, 1688KB/2MB, paused 10.745ms total 18.296ms
03-28 12:56:42.810 29897-29913/com.example.frances.rocksdrinks W/art: Suspending all threads took: 6.896ms
03-28 12:57:03.446 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 8.611ms
03-28 12:57:10.750 29897-29912/com.example.frances.rocksdrinks I/art: WaitForGcToComplete blocked for 9.071ms for cause HeapTrim
03-28 12:57:38.029 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.944ms
03-28 12:57:45.548 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.624ms
03-28 12:58:00.093 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.481ms
03-28 12:58:10.900 29897-29912/com.example.frances.rocksdrinks I/art: WaitForGcToComplete blocked for 7.327ms for cause HeapTrim
03-28 12:59:42.489 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 7.841ms
03-28 13:00:01.148 29897-29912/com.example.frances.rocksdrinks I/art: WaitForGcToComplete blocked for 6.726ms for cause HeapTrim
03-28 13:00:18.072 29897-29913/com.example.frances.rocksdrinks I/art: Background sticky concurrent mark sweep GC freed 26985(971KB) AllocSpace objects, 0(0B) LOS objects, 35% free, 1757KB/2MB, paused 6.471ms total 14.159ms
03-28 13:00:21.155 29897-29912/com.example.frances.rocksdrinks I/art: WaitForGcToComplete blocked for 7.892ms for cause HeapTrim
03-28 13:00:41.162 29897-29912/com.example.frances.rocksdrinks I/art: WaitForGcToComplete blocked for 5.154ms for cause HeapTrim
03-28 13:02:48.702 29897-29908/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.836ms
03-28 13:02:53.694 29897-29913/com.example.frances.rocksdrinks W/art: Suspending all threads took: 5.996ms
我无法从我的代码中找出问题所在。这是当前应用程序中的唯一活动。谢谢。
更新: 我发现如果我删除 createAnswers 函数,它会停止挂起,但我还没有弄清楚它为什么会导致挂起。
已解决: 事实证明,由于岩石饮料没有混合器(混合器哈希图中的所有条目都是空字符串),它会影响 createAnswers 中的 else 语句,我在其中为混合器问题创建答案。我不知道为什么它会造成内存泄漏,但我删除了它,现在它可以正常工作了。
【问题讨论】:
-
为什么需要 Handler?
-
处理程序使屏幕暂停 3 秒,以便用户在更新到新问题之前可以看到正确答案。