Android - 发送 sms/email - 意图

Android - send sms/email - Intent

我正在尝试通过调用 Intent 来发送 sms/email,但是我得到了一个 NPE,我不知道是什么原因。

我尝试了几种不同的方法,但显然我在代码的错误部分寻找问题。

因为我还在测试,所以我直接使用来自我的另一个 class 的 sendSms/sendEmail,它也扩展了 IntentService,但事实并非如此。虽然这并不是很重要。 Anyhoo,这是我的代码:

import android.app.IntentService;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.widget.Toast;

import java.util.Map;

public class FallNotificationService extends IntentService { // FIXME necessário extender IntentService?

    public FallNotificationService() {
        super(".FallNotificationService");
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public FallNotificationService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

    }

    public boolean sendNotification(Elderly elderly) {
        boolean success = false;
        String name = elderly.getName();
        for (Caregiver caregiver : elderly.getCaregivers()) {
            for (Map.Entry<ContactType, String> entry : caregiver.getContacts().entrySet()) {
                ContactType contactType = entry.getKey();
                String contact = entry.getValue();
                switch (contactType) {
                    case SMS:
                        success = this.sendSms(name, contact);
                        break;
                    case EMAIL:
                        success = this.sendEmail(name, contact);
                        break;
                    case WHATSAPP:
                        success = this.sendWhatsapp(name, contact);
                        break;
                }
            }

        }

        return success;
    }

    public boolean sendWhatsapp(String name,
                                 String contact) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_SEND);
        intent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
        intent.setType("text/plain");
        intent.setPackage("com.whatsapp");

        try {
            super.startActivity(intent);
            //finish();
            return true;
        } catch (Exception e) {
            //Toast.makeText(this, "Sms not send", Toast.LENGTH_LONG).show();
            e.printStackTrace();
            return false;
        }
    }

    public boolean sendSms(String name,
                           String contact) {
        String uriText = "smsto:" + contact +
                "?sms_body=" + Uri.encode("caiu");

        Intent intent = new Intent(Intent.ACTION_SENDTO);

        //intent.setData(Uri.parse("smsto:"));
        //intent.setData(Uri.parse("smsto:" + contact));
        intent.setData(Uri.parse(uriText));
        intent.setType("vnd.android-dir/mms-sendSms");
        //intent.putExtra("address", contact);

        try {
            super.startActivity(intent);
            //finish();
            return true;
        } catch (Exception e) {
            //Toast.makeText(this, "Sms not send", Toast.LENGTH_LONG).show();
            e.printStackTrace();
            return false;
        }
    }

    public boolean sendEmail(String name,
                             String contact) {
        Intent intent = new Intent(Intent.ACTION_SENDTO);

        intent.setData(Uri.parse("mailto:" + contact));
        //intent.putExtra("address", contact);
        intent.putExtra("message_body", "caiu");

        try {
            startActivity(intent);
            //finish();
            return true;
        } catch (Exception e) {
//            Toast.makeText(this, "Email not send", Toast.LENGTH_LONG).show();
            e.printStackTrace();
            return false;
        }
    }
}

这是我的AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cam.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".FallDetectionService" android:exported="false"/>
    </application>
    <uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
    <uses-feature android:name="android.hardware.sensor.gyroscope" android:required="false"/>

    <uses-permission android:name="android.permission.SEND_SMS"/>
</manifest>

这里是 app/build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.example.cam.myapplication"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/ASL2.0'
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    compileOnly "org.projectlombok:lombok:1.18.2"
    annotationProcessor 'org.projectlombok:lombok:1.18.2'

    implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
}

堆栈跟踪:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.content.Context.startActivity(android.content.Intent)' on a null object reference
     at android.content.ContextWrapper.startActivity(ContextWrapper.java:356)
     at com.example.cam.myapplication.FallNotificationService.sendEmail(FallNotificationService.java:108)
     at com.example.cam.myapplication.FallDetectionService.isFallDetected(FallDetectionService.java:88)
     at com.example.cam.myapplication.FallDetectionService.onSensorChanged(FallDetectionService.java:74)
     at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:699)
     at android.os.MessageQueue.nativePollOnce(Native Method)
     at android.os.MessageQueue.next(MessageQueue.java:323)
     at android.os.Looper.loop(Looper.java:136)
     at android.app.ActivityThread.main(ActivityThread.java:6123)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

此外,如果取消注释带有 Toast.makeText 的行,我也会得到 NPE。 所以我猜这个问题与我作为上下文传递的内容有关,但我无法弄清楚它是什么。

正如我们在您的堆栈跟踪中看到的那样,崩溃来自函数 sendEmail() 并在您的 phone 中生成,没有任何应用程序具有任何 activity 可以处理意图的约束,你已经在你的意图中提供了,所以

    Intent intent = new Intent(Intent.ACTION_SENDTO);
    intent.setData(Uri.parse("mailto:" + contact));
    //intent.putExtra("address", contact);
    intent.putExtra("message_body", "caiu");

    try {
        startActivity(intent);
        //finish();
        return true;
    } catch (Exception e) {
       // Toast.makeText(this, "Email not send", Toast.LENGTH_LONG).show();
        e.printStackTrace();
        return false;
    }

我们可以看到这里,你在setData(Uri.parse("mailto:" + contact))这里提供了条件所以如果androidphone没有任何发送邮件的应用程序,它会崩溃,但是作为你在 try-catch 中捕获它,所以它抛出空指针异常,如果您将在具有电子邮件应用程序的设备中测试您的代码,它会工作。 因此,使用函数 resolveActivity() 检查意图条件是否满足始终是最佳做法 如下所示。

    Intent intent = new Intent(Intent.ACTION_SENDTO);
    intent.setData(Uri.parse("mailto:" + contact));
    //intent.putExtra("address", contact);
    intent.putExtra("message_body", "caiu");
    if(intent.resolveActivity(getContext().getPackageManager())){
       // Phone has email app to handle this intent.. we can call the 
       intent
       startActivity(intent);
     }else{
        // Phone does not have email app to handle this intent, handle 
        accordingly, in this case we can show open default android 
        share intent..
     }

碰巧正如Mike M.所说,我是用new来实例化服务的。 所以我将它添加到我的 AndroidManifest.xml 并调用了 startActivity 而不是我调用 new FallNotificationService() 的地方。