简体   繁体   中英

Android - send sms/email - Intent

I'm trying to send sms/email by calling an Intent, but I'm getting a NPE and I can't figure out what's the reason.

I've tried several different approaches but apparently I'm looking for the problem in the wrong part of the code.

As I'm still testing, I'm using sendSms/sendEmail straight from my other class, which also extends IntentService, but that's not how it's gonna be. Although that's not really important. Anyhoo, here's my code:

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;
        }
    }
}

This is my 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>

And here's the 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'
}

Stacktrace:

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)

Also, if uncomment the line where with the Toast.makeText, I get a NPE as well. So I'm guessing the problem is something to do with what I'm passing as context, but I can't figure out what it is.

As we can see in your stack trace, the crash is coming from function sendEmail() and generating as in your phone there is no application having any activity which can handle the intent's constraints, you have provided in your Intent, so

    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;
    }

We can see here, you have provided condition here in setData(Uri.parse("mailto:" + contact)) so If the android phone does not have any application to send email, It will crash, But as you are catching it in try-catch so It is throwing null pointer exception, If you will test your code in a device having an email app, It will work. So It is always a best practice to check whether the conditions of intent are satisfied or not using function resolveActivity() like below.

    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..
     }

It happens that as Mike M. said, I was instantiating the service with new. So I added it to my AndroidManifest.xml and called startActivity instead where I was calling new FallNotificationService().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM