0

アプリを作っていますが、普通に使えばクラッシュすることもなく問題なく動きます。スワップされる 2 つのフラグメントを持つ 1 つのアクティビティがあり、1 つのアクティビティには 2 つのボタンがあります。アプリをしばらく (数時間) 使用せずにアプリを再度開いた場合、いずれかのボタンを押すとアプリがクラッシュします。これは、ホーム ボタンでアプリを終了した場合にのみ発生します。[戻る] を数回押して終了すると、この問題は発生しません。

アプリを開き、ホーム ボタンを押して Android のホーム画面に戻り、Advanced Task Killer アプリのボタンを押すと、このクラッシュを再現することもできます。アプリをもう一度開くと、中断したのと同じフラグメントで開き (奇妙なことに、タスク キラーを使用した後は新たに開始されると思います)、ボタンの 1 つを押すとアプリがクラッシュします。

編集:次のコードでアプリを再開すると、tempmainfrag が null として渡されていることが logcat でわかりました。これは、saveButtonClicked() と deleteButtonClicked() の両方で問題になります。

    /*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.android.fragments;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TimePicker;
import android.widget.Toast;

public class MainActivity extends FragmentActivity 
        implements MainListFragment.OnListSelectedListener {

    MainListFragment tempmainfrag;
    InfoFragment infofrag;
    int mainPosition = -1;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mainlayout);

        // Check whether the activity is using the layout version with
        // the fragment_container FrameLayout. If so, we must add the first fragment
        if (findViewById(R.id.fragment_container) != null) { //meaning, if using phone version

            // However, if we're being restored from a previous state,
            // then we don't need to do anything and should return or else
            // we could end up with overlapping fragments.
            if (savedInstanceState != null) {
                return;
            }



            // Create an instance of MainListFragment
            tempmainfrag = new MainListFragment();  //made a context parameter to pass the context

            // In case this activity was started with special instructions from an Intent,
            // pass the Intent's extras to the fragment as arguments
            tempmainfrag.setArguments(getIntent().getExtras());



            // Add the fragment to the 'fragment_container' FrameLayout
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, tempmainfrag).commit();

            Log.i("mydebug","TEMPMAINFRAG: " + tempmainfrag);
        }
    }

    public void onResume()
    {
        super.onResume();


    }


    public void onItemSelected(int position, String schedulename, String[] ampm, boolean[] days, int[] times, boolean vibrate) {
        // The user selected a list item

        //////////////////////////////TWO PANE LAYOUT STUFF///////////////////////////////////
        // Capture the article fragment from the activity layout
//        InfoFragment articleFrag = (InfoFragment)
//                getSupportFragmentManager().findFragmentById(R.id.article_fragment);  //article_fragment exists in layout-large
//
//        if (articleFrag != null) {
//            // If article frag is available, we're in two-pane layout...
//
//            // Call a method in the ArticleFragment to update its content
//            articleFrag.updateArticleView(position);
//
//        } else {
            // phone layout - swap frags

            mainPosition = position;

            // Create fragment and give it an argument for the selected article
            infofrag = new InfoFragment();
            Bundle args = new Bundle();
            args.putInt(infofrag.ARG_POSITION, position);

            //new stuff to add info
            args.putString(infofrag.ARG_NAME, schedulename);    
            args.putBooleanArray(infofrag.ARG_DAYS, days);
            args.putIntArray(infofrag.ARG_TIMES, times);
            args.putBoolean(infofrag.ARG_VIBRATE, vibrate); 
            args.putStringArray(infofrag.ARG_AMPM, ampm);

            infofrag.setArguments(args);
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, infofrag);
            transaction.addToBackStack(null);

            // Commit the transaction
            transaction.commit();

    }

    public void saveButtonClicked(View view) {  //pass the click to the mainlistfragment
        Log.i("mydebug","TEMPMAINFRAG: " + tempmainfrag);
        Log.i("mydebug","enter2222!!!!!!");
        boolean redo = false;
        //create toast
        Toast toast;

        //get title
        EditText titletext = (EditText)this.findViewById(R.id.titletext);

        //get checkboxes
        CheckBox check1 = (CheckBox)this.findViewById(R.id.monbox); //recreate checkboxes from view in activity (doesnt extend Activity 
        CheckBox check2 = (CheckBox)this.findViewById(R.id.tuebox); //so use getActivity())
        CheckBox check3 = (CheckBox)this.findViewById(R.id.wedbox);
        CheckBox check4 = (CheckBox)this.findViewById(R.id.thubox);
        CheckBox check5 = (CheckBox)this.findViewById(R.id.fribox);
        CheckBox check6 = (CheckBox)this.findViewById(R.id.satbox);
        CheckBox check7 = (CheckBox)this.findViewById(R.id.sunbox);
        CheckBox vibratebox = (CheckBox)this.findViewById(R.id.vibratecheckbox);

        //get times
        TimePicker startpicker = (TimePicker)this.findViewById(R.id.starttimepicker);
        TimePicker stoppicker = (TimePicker)this.findViewById(R.id.stoptimepicker);

        EditText temppp = titletext;
        //check for input errors
        if(titletext.getText().toString().length() == 0) //if title is empty
        {
            redo = true;
            toast = Toast.makeText(view.getContext(), "Enter an event name", 4);
            toast.show();

            //some sick-ass shake animations!!!
            Animation shake = AnimationUtils.loadAnimation(titletext.getContext(), R.anim.shake_big);
            this.findViewById(R.id.titletext).startAnimation(shake);
        }
        else if((!check1.isChecked()) && (!check2.isChecked()) && (!check3.isChecked()) && 
                (!check4.isChecked()) && (!check5.isChecked()) && (!check6.isChecked()) && 
                (!check7.isChecked()))  //if all checkboxes arent checked
        {
            redo = true;
            toast = Toast.makeText(view.getContext(), "At least one day of week must be checked", 4);
            toast.show();

            //more sick-ass shake animations!!!
            Animation shake = AnimationUtils.loadAnimation(titletext.getContext(), R.anim.shake_small);
            this.findViewById(R.id.checkboxes).startAnimation(shake);
            this.findViewById(R.id.daysofweek).startAnimation(shake);
            this.findViewById(R.id.frequencytext).startAnimation(shake);
        }

        if(!redo)   //if all info is fine
        {
            //check to see if time goes into next day
            if((startpicker.getCurrentHour() > stoppicker.getCurrentHour())||
                    ((startpicker.getCurrentHour() == stoppicker.getCurrentHour())
                            && (startpicker.getCurrentMinute() >= stoppicker.getCurrentMinute())))
            {
                toast = Toast.makeText(view.getContext(), "Note: Stop time is earlier than start time, so this schedule stops at next day", Toast.LENGTH_LONG);
                toast.show();
            }

            toast = Toast.makeText(view.getContext(), "Schedule saved", Toast.LENGTH_LONG);
            toast.show();

            //changing old schedule to new one
            boolean[] tempdays = {check1.isChecked(), check2.isChecked(), check3.isChecked(), check4.isChecked(), 
                    check5.isChecked(), check6.isChecked(), check7.isChecked()};

            tempmainfrag.mainObjectList.changeSchedule(mainPosition, titletext.getText().toString(), tempdays, vibratebox.isChecked(), 
                    startpicker.getCurrentHour()-1, startpicker.getCurrentMinute(), stoppicker.getCurrentHour()-1, stoppicker.getCurrentMinute());

            //used to hide keyboard in case its still open when displaying list
            InputMethodManager imm = (InputMethodManager)this.getSystemService(
                      Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(titletext.getWindowToken(), 0);

            this.onBackPressed();   //replicates backpress to go back to list
        }
    }

    public void deleteButtonClicked(View view)
    {
        //make a notification

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Delete?");
        builder.setIcon(R.drawable.trash_icon);
        builder.setMessage("Are you sure you wish to delete this schedule?")
           .setCancelable(false)
           .setPositiveButton("Delete", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   tempmainfrag.mainObjectList.removeSchedule(mainPosition);

                   tempmainfrag.exit();
               }
           })
           .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    dialog.dismiss();
               }
           });
        AlertDialog alert = builder.create();
        alert.show();
    }

    public void hideKeyboard()  //hides keyboard, called whenever reverting back to list
    {
        InputMethodManager imm = (InputMethodManager)getSystemService(
                  Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
    }


}

onResume でいくつかの解決策を試しましたが、何も思いつきません。アイデアはありますか? どうもありがとうございました。

4

1 に答える 1

0

いくつかの静的変数があり、タスクの終了後に変数が空または null になる可能性があるという @andr に同意しました。そのため、変数を呼び出そうとするとエラーが発生します。LogCat に何があるかによって異なりますが、間違っている可能性があります。

高度なタスク キラーでアプリケーションを終了しようとすると、アプリケーションもクラッシュします。その理由は、タスクの kill 後に空になることが判明した静的変数を使用したためです。アプリケーションのクラッシュを避けるために、私がこのようなものを実装したすべてのアクティビティで。

これがお役に立てば幸いです。または、他の人があなたを助けることができるように、LogCat またはより多くの情報を提供することができます。

public void onCreate(Bundle savedInstance){
       super.onCreate(savedInstance);

       //check whether global / static variables are empty or not
       //retrieve back the variables or intent it back to other activity
       if(globalvariables.UserName.equals(""){
               //execute something to deal with it
       }
}
于 2013-02-22T01:48:16.357 に答える