调用另一个类的非静态方法

时间:2015-12-23 20:22:37

标签: java android android-spinner

我有两个与此问题相关的类:AddA和TopicSpinner。

在AddA类中,我正在为微调器设置一个触摸侦听器。选择微调器时,我想调用TopicSpinner类的方法loadSpinnerData()。所以我想在AddA类中调用TopicSpinner类的非静态方法。

我知道从AddA类启动TopicSpinner类可以使用Intent调用,因此loadSpinnerData()方法可以正常工作。我在听众中尝试了几种方法,如下所示。但是,我无法在没有空指针的情况下调用方法,或者“无法从静态方法引用非静态方法”。

有关如何在AddA类的侦听器方法中调用TopicSpinner类的方法loadSpinnerData()的任何建议吗?

这是当前的例外:

java.lang.NullPointerException
at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:109)
at TopicSpinner.loadSpinnerData(TopicSpinner.java:56)
at AddA$2.onTouch(AddAlerts.java:117)
at android.view.View.dispatchTouchEvent(View.java:7241)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2168)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1903)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1953)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1405)
at android.app.Activity.dispatchTouchEvent(Activity.java:2410)
at android.support.v7.internal.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:59)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1901)
at android.view.View.dispatchPointerEvent(View.java:7426)
at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3220)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3165)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4292)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4271)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4363)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:179)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:125)
at android.os.Looper.loop(Looper.java:124)
at android.app.ActivityThread.main(ActivityThread.java:5041)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)

7 个答案:

答案 0 :(得分:0)

不要在AddA类中添加侦听器,只需将其添加到TopicSpinner类中即可。您可以在onCreate方法中执行此操作。然后你可以直接引用你的loadSpinnerData方法。

public class TopicSpinner extends AddAlerts implements OnItemSelectedListener {

    // Spinner element
    Spinner spinner;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_alerts);

        //Spinner element
        spinner = (Spinner) findViewById(R.id.spinner);

        //Spinner click listener
        spinner.setOnItemSelectedListener(this);

        //ADD LISTENER HERE
        spinner.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    loadSpinnerData();
                }
                return false;
            }
        });


        //Loading spinner data from database
        loadSpinnerData();
    }

    /**
     * Function to load the spinner data from SQLite database
     **/
    public void loadSpinnerData() {
        // database handler
        DatabaseHelper db = DatabaseHelper.getInstance(getApplicationContext());

        Cursor topicCursor = db.getAllTopics();
        Log.v("topicCursor", topicCursor.toString());
        db.close();

        String str;

        ArrayList<String> labels = new ArrayList<String>();
        if (topicCursor.moveToFirst()) {
            do {
                str = topicCursor.getString(topicCursor.getColumnIndex("topic_name"));
                Log.v("str", str);

                labels.add(str);
                Log.v("labels", labels.toString());

            } while (topicCursor.moveToNext());

        }
        ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, labels);

        //Drop down layout style - list view with radio button
        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        Log.v("dataAdapter", dataAdapter.toString());

        //Attaching data adapter to spinner
        spinner.setAdapter(dataAdapter);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

        // On selecting a spinner item
        String label = parent.getItemAtPosition(position).toString();

    }

    @Override
    public void onNothingSelected(AdapterView<?> arg0) {
        // TODO Auto-generated method stub

    }

}

答案 1 :(得分:0)

根据你的问题,我打电话告诉“班级”和“对象”之间的混淆。通过调用静态方法,您在没有TopicSpinner的特定实例上调用操作。通过调用loadSpinnerData()原样(非静态),您要对精确的TopicSpinner说“执行loadSpinnerData()的工作”。请参阅here了解详情。

我可以在TopicSpinner中看到你有一个字段“spinner”,它被TopicSpinner的“实例”所占据。例如,您可以让2个TopicSpinner各自具有不同的Spinner。方法loadSpinnerData()将实际修改该Spinner。换句话说,loadSpinnerData()需要通过实例(对象)而不是通过静态调用来调用,因为它需要知道它实际上要使用的Spinner。

如果你正确地调用它,为什么你会得到一个Nullpointerexception?如果手动调用新的TopicSpinner(),则表示在我刚刚创建的TopicSpinner的新实例上运行loadSpinnerData()。我有一种感觉,你的主题微调器已经存在。您可以通过在对象View和MotionEvent中向下钻取来访问它。尝试调试并查找TopicSpinner实例。然后,您可以在该实例上调用loadSpinnerData()。

希望我没有太混淆你,但你真的需要区分一个类和一个类(对象)的实例。

答案 2 :(得分:0)

您的问题是在loadSpinnerData()的以下行中未设置“spinner”(为空):

        spinner.setAdapter(dataAdapter);

当您使用Intent启动类时,它会执行onCreate,它会正确初始化“spinner”变量。您可以在AddA中将“spinner”声明为实例变量,然后将其作为参数发送到TopicSpinner的构造函数,您可以在其中捕获并保存引用。像这样:

 public AddA extends Activity {
     private Spinner spinner;
     private Context context;
     //In onCreate or wherever
     spinner = (Spinner) findViewById(R.id.spinner);
     context = this;
     spinner.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                     TopicSpinner ts = new TopicSpinner(spinner, context);
                     ts.loadSpinnerData();
                }
                //etc

现在在TopicSpinner中添加一个构造函数:

public class TopicSpinner extends AddA implements OnItemSelectedListener {

    // Spinner element
    private Spinner spinner;
    private Context context;
    public TopicSpinner(Spinner spinner, Context context){
         this.spinner = spinner;
         this.context = context;
    }
    //etc

TopicSpinner班级中,将getContext()替换为context。 其余代码保持不变。

答案 3 :(得分:0)

旧答案,(左,因为此时“确实',但上述代码/信息已更改)

从你的第一个错误开始不是存储'new'TopicSpinner。这就是为什么你不能调用类的'成员方法(可能是错误的名称,但是'非静态'方法)'。

 final Spinner spinner = (Spinner) findViewById(R.id.spinner);
        spinner.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP) {

                   // Intent i = new Intent(AddA.this, TopicSpinner.class);
                    //startActivity(i);

                    //TopicSpinner ts = new TopicSpinner();
                    //ts.loadSpinnerData();   //null

                    // the problem is that you aren't saving the reference to the 
                    // newly created TopicSpinner Object. 
                    // Storing that reference here allows you to call
                    // non-static methods.
                    TopicSpinner myTopicSpinner =  new TopicSpinner();
                    // Perhaps this can be above if it follows the builder pattern... 
                    // but if not, then you need to separate these calls.
                    myTopicSpinner.loadSpinnerData(); // loadSpinnerData you have listed returns 'void' so it doesn't follow builder pattern.
                    // if myTopicSpinner is null here then you have bigger issues in THAT class. 


                    // Now you can call non-static methods on the OBJECT.
                    // Since you 'have' an object now.
                    myTopicSpinner.loadSpinnerData(); //non-static method 
                }
                return false;
            }
        });

答案 4 :(得分:0)

  

DatabaseHelper db =   DatabaseHelper.getInstance(getApplicationContext()); return null。

如果是这种情况,那么您的DatabaseHelper类就是您的问题所在 实际上是。

这是一个带有(几乎)完整答案的问题,它将告诉你该怎么做(你需要impl。你自己的rawQuery(),他们不会在那个链接中做) Looking for Cause of Null Pointer Exception

您可以尝试一些事情。 (很难说没有看到DatabaseHelper的来源)

1)DatabaseHelper db = new DatabaseHelper(getApplicationContext());然后db.open()就在它之后。 (如果你按照我在下面显示的模式)。使用普通构造函数而不是'getInstance()'。我没有看到DBHelper类是单例或其他需要'getInstance()'之前的类。 SQLite DB应该能够轻松处理多个并发的可读DB访问(写入有时间问题,但这是'应用逻辑'而不是SQLite DB本身。)

2)在DatabaseHelper类中开始记录并查看它在内部失败的位置。

这是我很久以前写过的一个示例DBHelper类的(部分)。

当您尝试实例化您的时,您不应该获得'null'。您应该确保该类正常运行。如果你没有,你应该有一个内部的SQLiteOpenHelper类(非常有用)。

// Database open/upgrade helper
private myDbHelper dbHelper; // this is inside my DBAdapter class

// ... 

/**
 * constructor that accepts the context to be associated with
 * 
 * @param _context
 */
public DataDBAdaptor(Context _context) {
    Log.d(LOG_TAG, "MyDBAdapter constructor");

    context = _context;
    dbHelper = new myDbHelper(context, DATABASE_NAME, null,
            DATABASE_VERSION);
}

/**
 * open the DB, and write/read access or
 * just read access if that is all that is possible.
 * 
 * @return this DataDBAdaptor
 * @throws SQLException
 */
public MoocDataDBAdaptor open() throws SQLException {
    Log.d(LOG_TAG, "open()");
    try {
        db = dbHelper.getWritableDatabase();
    } catch (SQLException ex) {
        db = dbHelper.getReadableDatabase();
    }
    return this;
}

这是Helper类

/**
 * DB Helper Class.
 * 
 * @author mawalker
 * 
 */
private static class myDbHelper extends SQLiteOpenHelper {

    public myDbHelper(Context context, String name, CursorFactory factory,
            int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(LOG_TAG, "DATABASE_CREATE: version: " + DATABASE_VERSION);
        // ST:createTable:start
        db.execSQL(DATABASE_CREATE_STORY);
        db.execSQL(DATABASE_CREATE_TAGS);
        // ST:createTable:finish

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Log version upgrade.
        Log.w(LOG_TAG + "DBHelper", "Upgrading from version " + oldVersion
                + " to " + newVersion + ", which will destroy all old data");

        // **** Upgrade DB ****
        // TODO: migrate data?? from old DB to new DB
        // drop old DB

        // ST:dropTableIfExists:start
        db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_STORY);
        db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_TAGS);
        // ST:dropTableIfExists:finish

        // Create a new one.
        onCreate(db);

    }

}

答案 5 :(得分:0)

您可以尝试作为参数传入微调器或上下文吗?

所以使用参数化的微调器和上下文复制并粘贴你的加载微调器数据和sub:

 public Spinner loadSpinnerData(Context context, Spinner spinner) {
    // database handler
    DatabaseHelper db = DatabaseHelper.getInstance(context);

    Cursor topicCursor = db.getAllTopics();
    Log.v("topicCursor", topicCursor.toString());
    db.close();

    String str;

    ArrayList<String> labels = new ArrayList<String>();
    if (topicCursor.moveToFirst()) {
        do {
            str = topicCursor.getString(topicCursor.getColumnIndex("topic_name"));
            Log.v("str", str);

            labels.add(str);
            Log.v("labels", labels.toString());

        } while (topicCursor.moveToNext());

    }
    ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, labels);

    //Drop down layout style - list view with radio button
    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    Log.v("dataAdapter", dataAdapter.toString());

    //Attaching data adapter to spinner
    spinner.setAdapter(dataAdapter);
    return spinner;
}

然后重新分配您传入的微调器,使其成为此方法产生的新微调器。它也会保留以前的引用,因为我们没有在这个方法中分配它

答案 6 :(得分:0)

通过其他类的名称调用Activity类会让人非常困惑。

AddAActivity

TopicSpinner以来,

Activity也是extends AddA

调用new TopicSpinner()会创建一个Activity对象,但不会对其进行充气,因此在setContentView内调用findViewByIdTopicSpinner毫无意义。它甚至可能返回null,因为找不到视图。

原样,你有两种选择,都可以摆脱extends AddA

选项1:只需加载AddA中的数据 选项2:创建一个单独的类,用于加载而不是活动的数据。您对onCreatesetContentView以及findViewById感到困惑。 您需要的只是ContextSpinner

public class AddA extends Activity implements AdapterView.OnItemSelectedListener {

    private Spinner spinner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_a);

        spinner = (Spinner) findViewById(R.id.spinner);

        spinner.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    /** Option 1 **/
                    loadSpinnerData();

                    /** Option 2 **/
                    TopicLoader loader = new TopicLoader(getApplicationContext());
                    loader.loadSpinner(spinner);
                }
                return false;
            }
        });

    }

    private void loadSpinnerData() {
        Context ctx = getApplicationContext();

        // TODO: Implement Option 1 here
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // On selecting a spinner item
        String label = parent.getItemAtPosition(position).toString();
    }

    @Override
    public void onNothingSelected(AdapterView<?> adapterView) {

    }
}
public class TopicLoader {
    private Context mCtx;

    public TopicLoader(Context ctx) {
        this.mCtx = ctx;
    }

    public void loadSpinner(Spinner spinner) {
        // Context ctx = this.mCtx;

        // TODO: Implement Option 2 here
    }
}