You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android应用初始视图加载失败致崩溃的技术求助

Fixing GuessMaster App Crash & Missing Initial View Issue

Let's break down why your app is crashing on launch and fix each problem step by step:

Key Issues Causing the Crash

  • No layout inflated: You never called setContentView(R.layout.your_layout_file) in onCreate—this means the app has no view hierarchy to load, which is the root cause of the "no initial view" problem.
  • Uninitialized UI components: All your TextView, Button, EditText, and ImageView variables are declared but never assigned via findViewById, leading to NullPointerExceptions when you try to use them.
  • Empty entities array: You created the entities array in the constructor but never called addEntity to populate it. When genRandomEntityId tries to generate a random index with numOfEntities = 0, it throws an IllegalArgumentException (since Random.nextInt(0) is invalid).
  • Incomplete method code: The welcomeToGame method cuts off mid-Toast call, causing a syntax error.
  • Premature UI access: playGame tries to clear userIn before the UI is initialized, which will crash the app.

Corrected Code Implementation

First, make sure you have a corresponding layout XML file (let's assume it's activity_guess_master.xml with all the required UI elements: entityName, ticketsum, guessButton, userIn, btnclearContent, entityImage).

Here's the fixed GuessMasterActivity class:

public class GuessMasterActivity extends AppCompatActivity {
    private TextView entityName;
    private TextView ticketsum;
    private Button guessButton;
    private EditText userIn;
    private Button btnclearContent;
    private ImageView entityImage;
    
    private String answer;
    private int numOfEntities;
    private Entity[] entities;
    private int numOfTickets;
    private int currentTicketWon = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Inflate the layout first—this is mandatory for loading views
        setContentView(R.layout.activity_guess_master);
        
        // Initialize all UI components here
        entityName = findViewById(R.id.entityName);
        ticketsum = findViewById(R.id.ticketsum);
        guessButton = findViewById(R.id.guessButton);
        userIn = findViewById(R.id.userIn);
        btnclearContent = findViewById(R.id.btnclearContent);
        entityImage = findViewById(R.id.entityImage);
        
        // Initialize game data
        numOfEntities = 0;
        numOfTickets = 0;
        entities = new Entity[100];
        
        // Add all entities to the game
        addEntity(new Politician("Justin Trudeau", new Date("December", 25, 1971), "Male", "Liberal", 0.25));
        addEntity(new Singer("Celine Dion", new Date("March", 30, 1968), "Female", "La voix du bon Dieu", new Date("November", 6, 1981), 0.5));
        addEntity(new Person("myCreator", new Date("September", 1, 2000), "Female", 1));
        addEntity(new Country("United States", new Date("July", 4, 1776), "Washington D.C.", 0.1));
        
        // Set click listeners for buttons
        guessButton.setOnClickListener(v -> playGame());
        btnclearContent.setOnClickListener(v -> userIn.setText(""));
        
        // Start the game with the welcome alert
        Entity firstEntity = entities[genRandomEntityId()];
        welcomeToGame(firstEntity);
    }

    public void addEntity(Entity entity) {
        if (numOfEntities < entities.length) {
            entities[numOfEntities++] = entity.clone();
        }
    }

    public void playGame() {
        if (userIn == null) return; // Guard clause to avoid NPE
        
        String userInput = userIn.getText().toString().trim();
        if (userInput.equalsIgnoreCase("quit")) {
            finish(); // Use finish() instead of System.exit(0) for proper Android lifecycle handling
            return;
        }
        
        int entityId = genRandomEntityId();
        Entity currentEntity = entities[entityId];
        
        try {
            Date userDate = new Date(userInput);
            evaluateGuess(currentEntity, userDate);
        } catch (IllegalArgumentException e) {
            // Handle invalid date input
            Toast.makeText(this, "Please enter a valid date format", Toast.LENGTH_SHORT).show();
        }
    }

    private void evaluateGuess(Entity entity, Date userDate) {
        if (userDate.precedes(entity.getBorn())) {
            showAlert("Incorrect", "Try a later date", () -> Toast.makeText(this, "Loading...", Toast.LENGTH_SHORT).show());
        } else if (entity.getBorn().precedes(userDate)) {
            showAlert("Incorrect", "Try an earlier date", () -> Toast.makeText(this, "Loading...", Toast.LENGTH_SHORT).show());
        } else {
            currentTicketWon = entity.getAwardedTicketNumber();
            numOfTickets += currentTicketWon;
            ticketsum.setText(String.valueOf(numOfTickets));
            
            showAlert("You Won", "Bingo! " + entity.closingMessage(), () -> {
                Toast.makeText(this, "You won " + currentTicketWon + " tickets", Toast.LENGTH_SHORT).show();
                ContinueGame();
            });
        }
    }

    private void showAlert(String title, String message, Runnable onDismiss) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(title)
               .setMessage(message)
               .setNegativeButton("Ok", (dialog, which) -> {
                   if (onDismiss != null) {
                       onDismiss.run();
                   }
               });
        builder.create().show();
    }

    public void ImageSetter(String entName) {
        if (entityImage == null) return;
        
        switch(entName) {
            case "Justin Trudeau":
                entityImage.setImageResource(R.drawable.justint);
                break;
            case "Celine Dion":
                entityImage.setImageResource(R.drawable.celidion);
                break;
            case "United States":
                entityImage.setImageResource(R.drawable.usaflag);
                break;
            case "myCreator":
                entityImage.setImageResource(R.drawable.pic);
                break;
            default:
                // Set a default image if entity name doesn't match
                entityImage.setImageResource(R.drawable.default_image);
                break;
        }
    }

    public void ContinueGame() {
        int entityId = genRandomEntityId();
        Entity entity = entities[entityId];
        String entName = entity.getName();
        ImageSetter(entName);
        entityName.setText(entName);
        userIn.setText(""); // Clear input for next guess
    }

    public int genRandomEntityId() {
        if (numOfEntities == 0) {
            throw new IllegalStateException("No entities added to the game");
        }
        Random randomNumber = new Random();
        return randomNumber.nextInt(numOfEntities);
    }

    public void welcomeToGame(Entity entity) {
        AlertDialog.Builder welcomealert = new AlertDialog.Builder(this);
        welcomealert.setTitle("GuessMaster Game v3")
                   .setMessage(entity.welcomeMessage())
                   .setCancelable(false)
                   .setNegativeButton("START_GAME", (dialog, which) -> {
                       Toast.makeText(this, "Game is Starting... Enjoy!", Toast.LENGTH_SHORT).show();
                       ContinueGame();
                   });
        welcomealert.create().show();
    }
}

Additional Fixes & Best Practices

  1. Use onCreate for initialization: Android activities should initialize views and game data in onCreate, not the constructor—this follows standard Android lifecycle practices.
  2. Avoid System.exit(0): Call finish() instead to close the activity properly, as System.exit() can cause unexpected behavior in the Android framework.
  3. Add guard clauses: Added checks for null UI components and empty entities to prevent NullPointerExceptions and illegal state errors.
  4. Refactored alert logic: Created a reusable showAlert method to reduce code duplication.
  5. Handle invalid dates: Added a try-catch block to handle cases where the user enters an invalid date format.
  6. Pass entity name to ImageSetter: Modified ImageSetter to accept the entity name as a parameter, avoiding reliance on a global variable that might be null.

内容的提问来源于stack exchange,提问作者manfire

火山引擎 最新活动