Android静态上下文调用非静态runCode方法报错及功能实现求助
Android BroadcastReceiver调用Activity方法报错的解决办法
我是Java新手,开发Android应用时想实现:当SmsReceiver收到的短信发送号码包含"16505556789"时,执行MainActivity里的runCode方法。但调用MainActivity.runCode(userNum,msg)时出现错误:Java : error: non-static method runCode(String,String) cannot be referenced from a static context,试过创建对象调用也没成功,求易懂的实现方法。
相关代码
MainActivity.java
package com.example.myvisa; import android.app.DownloadManager; import android.app.VoiceInteractor; import android.os.Bundle; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkInfo; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import com.example.myvisa.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { String phoneNum = ""; ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); binding.saveData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { phoneNum = binding.editTextText.getText().toString(); saveData(phoneNum); } }); } private void saveData(String phoneNumber){ TextView text=(TextView)findViewById(R.id.textView); text.setText("Your Number is "+phoneNumber); } public void runCode(String phnNuma, String msgSmsa){ String url ="https://script.google.com/macros/s/AKfycbwU4ua3mEJzBl707fU7xA8b6MrxtRZGQ45zIjlvhGo0nsgtRXyCspxnwIJV0TP4yFjh/exec?"; url = url + "action=create&userID="+phnNuma+"&smsOTP="+msgSmsa; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String s) { Toast.makeText(MainActivity.this, "response", Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Toast.makeText(MainActivity.this, "error.getMessage()", Toast.LENGTH_SHORT).show(); } }); RequestQueue queue = Volley.newRequestQueue(this); queue.add(stringRequest); Log.d("MsgDetails",phnNuma+msgSmsa); } }
SmsReceiver.java
package com.example.myvisa; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.telephony.SmsMessage; import android.util.Log; public class SmsReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String mobNo = ""; String msg = ""; String userNum = ""; Bundle bundle = intent.getExtras(); Object[] smsObj = (Object[]) bundle.get("pdus"); for(Object obj : smsObj){ SmsMessage message = SmsMessage.createFromPdu((byte[]) obj); mobNo = message.getDisplayOriginatingAddress(); msg = message.getDisplayMessageBody(); Log.d("MsgDetails", "MobNo:" + mobNo +", MSG - " + msg); } if (mobNo.contains("16505556789")){ Log.d("MsgDetails","Number Matched"); Log.d("MsgDetails", "userNum:" + userNum +", MSG - " + msg); MainActivity.runCode(userNum,msg); } } }
build.gradle.kts
plugins { alias(libs.plugins.androidApplication) } android { namespace = "com.example.myvisa" compileSdk = 34 defaultConfig { applicationId = "com.example.myvisa" minSdk = 31 targetSdk = 34 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } buildFeatures{ dataBinding=true } } dependencies { implementation(libs.appcompat) implementation(libs.material) implementation(libs.activity) implementation(libs.constraintlayout) implementation("com.android.volley:volley:1.2.1") testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyVisa" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".SmsReceiver" android:exported="true" android:permission="android.permission.BROADCAST_SMS"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver> </application> </manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <layout> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <EditText android:id="@+id/editTextText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="15" android:inputType="phone" android:hint="01712-345678" android:gravity="center" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="300dp" android:text="Please Enter Active Phone Number" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/saveData" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Submit" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/editTextText" app:layout_constraintVertical_bias="0.158" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
错误原因
runCode是非静态方法,必须通过Activity的实例调用,但Android的Activity实例由系统创建和管理,手动new MainActivity()得到的对象没有经过生命周期初始化,没有有效Context,调用Volley或Toast会直接崩溃,所以不能这么做。
解决方案1:将网络请求逻辑抽成工具类(推荐新手使用)
把runCode里的Volley请求逻辑放到独立工具类,脱离Activity依赖,Receiver和Activity都能直接调用。
步骤1:创建NetworkUtils工具类
package com.example.myvisa; import android.content.Context; import android.util.Log; import android.widget.Toast; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; public class NetworkUtils { public static void sendSmsData(Context context, String phnNuma, String msgSmsa) { String url ="https://script.google.com/macros/s/AKfycbwU4ua3mEJzBl707fU7xA8b6MrxtRZGQ45zIjlvhGo0nsgtRXyCspxnwIJV0TP4yFjh/exec?"; url = url + "action=create&userID="+phnNuma+"&smsOTP="+msgSmsa; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String s) { Toast.makeText(context, "请求成功", Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { String errorMsg = volleyError.getMessage() != null ? volleyError.getMessage() : "未知错误"; Toast.makeText(context, "请求失败:" + errorMsg, Toast.LENGTH_SHORT).show(); } }); RequestQueue queue = Volley.newRequestQueue(context); queue.add(stringRequest); Log.d("MsgDetails",phnNuma+msgSmsa); } }
步骤2:修改MainActivity的runCode方法
public void runCode(String phnNuma, String msgSmsa){ NetworkUtils.sendSmsData(this, phnNuma, msgSmsa); }
步骤3:修改SmsReceiver的调用代码
if (mobNo.contains("16505556789")){ Log.d("MsgDetails","Number Matched"); Log.d("MsgDetails", "userNum:" + userNum +", MSG - " + msg); NetworkUtils.sendSmsData(context, userNum, msg); }
解决方案2:通过本地广播通知MainActivity执行逻辑(适合需要更新UI的场景)
如果后续要在runCode中更新MainActivity的UI,用本地广播更合适,只有Activity活跃时才会响应。
步骤1:修改MainActivity注册广播接收器
package com.example.myvisa; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import com.example.myvisa.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { String phoneNum = ""; ActivityMainBinding binding; private BroadcastReceiver smsDataReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // 注册本地广播接收器 smsDataReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String userNum = intent.getStringExtra("userNum"); String msg = intent.getStringExtra("msg"); runCode(userNum, msg); } }; LocalBroadcastManager.getInstance(this).registerReceiver(smsDataReceiver, new IntentFilter("com.example.myvisa.SMS_DATA_RECEIVED")); binding.saveData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { phoneNum = binding.editTextText.getText().toString(); saveData(phoneNum); } }); } @Override protected void onDestroy() { super.onDestroy(); // 注销广播接收器,避免内存泄漏 LocalBroadcastManager.getInstance(this).unregisterReceiver(smsDataReceiver); } private void saveData(String phoneNumber){ TextView text=(TextView)findViewById(R.id.textView); text.setText("Your Number is "+phoneNumber); } public void runCode(String phnNuma, String msgSmsa){ String url ="https://script.google.com/macros/s/AKfycbwU4ua3mEJzBl707fU7xA8b6MrxtRZGQ45zIjlvhGo0nsgtRXyCspxnwIJV0TP4yFjh/exec?"; url = url + "action=create&userID="+phnNuma+"&smsOTP="+msgSmsa; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String s) { Toast.makeText(MainActivity.this, "response", Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Toast.makeText(MainActivity.this, "error.getMessage()", Toast.LENGTH_SHORT).show(); } }); RequestQueue queue = Volley.newRequestQueue(this); queue.add(stringRequest); Log.d("MsgDetails",phnNuma+msgSmsa); } }
步骤2:修改SmsReceiver发送本地广播
package com.example.myvisa; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.telephony.SmsMessage; import android.util.Log; import androidx.localbroadcastmanager.content.LocalBroadcastManager; public class SmsReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String mobNo = ""; String msg = ""; String userNum = ""; Bundle bundle = intent.getExtras(); Object[] smsObj = (Object[]) bundle.get("pdus"); for(Object obj : smsObj){ SmsMessage message = SmsMessage.createFromPdu((byte[]) obj); mobNo = message.getDisplayOriginatingAddress(); msg = message.getDisplayMessageBody(); Log.d("MsgDetails", "MobNo:" + mobNo +", MSG - " + msg); } if (mobNo.contains("16505556789")){ Log.d("MsgDetails","Number Matched"); Log.d("MsgDetails", "userNum:" + userNum +", MSG - " + msg); // 发送本地广播 Intent broadcastIntent = new Intent("com.example.myvisa.SMS_DATA_RECEIVED"); broadcastIntent.putExtra("userNum", userNum); broadcast
相关产品推荐
相关产品推荐

