Android Tutorial [TUTORIAL] Inter-app Communication with Intents

Discussion in 'Tutorials & Examples' started by thedesolatesoul, Jun 28, 2013.

  1. thedesolatesoul

    thedesolatesoul Expert Licensed User

    DISCLAIMER:
    This tutorial is written without testing code. There may be bugs, but try to understand the process, not copy the code.


    An intent is a way for different applications to communicate at run time. It can be used to pass messages between activities and make them do actions. Using it with startActivity targets the intent to an activity. Broadcast intents are broadcast to all activities, and any applications with an intent filter can listen for it and perform an action.

    Explicit Intents: The target component (service or activity) is known. (For e.g. an intent to the browser)

    Implicit Intents: The system will determine which activity is best to launch this intent. (For e.g. Share intents)

    More information on intents:
    Intents and Intent Filters | Android Developers


    In this example we have two apps.
    - The Provider, that contains the data we need
    - The Requester, that will request the data via Intent


    Step 1: Setup the Provider to be able to receive intents
    This can be done in two ways:
    1. Explicitly setting the component, and making it visible by setting exported=true
    2. Defining your own intent filter

    We will do the second way since it is more structured.

    We set up an intent filter to trigger our activity in the Provider.
    In the manifest editor add the following, for the Activity you want to trigger.
    You can also use a service (use AddServiceText instead)

    Code:
    AddActivityText(Main, <intent-filter>
       <action android:name=
    "com.maximussoft.myprovider.REQUEST" />
       <category android:name=
    "android.intent.category.DEFAULT" />
    </
    intent-filter>)
    Step 2: Code the Provider to return the data
    When using an Activity,

    Code:
    Sub Activity_Resume
     
    Dim in as Intent
     
    in = Activity.GetStartingIntent
     
    If in <> null Then
        
    If In.HasExtra("GetSettings"Then
           SendSettings(
    in)
           
    Activity.Finish
           
    Return
        
    End If
     
    End If
    End Sub
    ...so far so good...
    however do you see the problem here?
    no? come on think harder
    How does the Providor know which app to send the data back to? The Intent by default has no information about the Calling package.

    Again, there are two (simpler) ways to deal with this
    1. Add information about the Requestor in the intent extras so we can call it back
    2. Use StartActivityForResult. This allows you to get the calling package name, but infact you do not even need it. You can just return the result as an intent back to the Requestor Activity.

    However, this is the point where you pause and think about what your apps need to do. Are they working silently in the background? Or do they show a dialog at some point?

    For now, we go with the first option, and assume that the Requestor sends us an intent action in the extras.
    So in SendSettings we do,
    Code:
    Sub SendSettings(in as Intent)
       
    Dim returnIntent as Intent
       returnIntent.Initialize(
    in.GetExtra("Callback"),"")
       returnIntent.AddCategory(
    "android.intent.category.DEFAULT")
       returnIntent.PutExtra(
    "Settings",someGlobalSettings)
       returnIntent.PutExtra(
    "Successful","True")
       
    StartActivity(returnIntent) 'Or StartService(returnIntent)
    End Sub
    Make note of how the return intent is initialized with the Callback field from the original recevied intent.

    3. Set up the Requester
    As you may have noticed, the Requester needs to be set up in the same way except for some minor differences. First you set up the manifest, with a different intent filter:
    Code:
    AddActivityText(Main, <intent-filter>
       <action android:name=
    "com.maximussoft.myrequestor.CALLBACK" />
       <category android:name=
    "android.intent.category.DEFAULT" />
    </
    intent-filter>)
    4. Code the Requester to request the data/settings
    This can be anywhere in your code, but if its settings you want to request, it will probably be in activity create or resume. The thing to note here is how we initialiaze the intent with the ACTION of the PROVIDER. And we send the CallBack i.e. the intent of the REQUESTER as the CALLBACK so the provider can send us back the data.

    Code:
    Sub RequestSettings
       
    Dim in as Intent
       
    in.Initialize("com.maximussoft.myprovider.REQUEST","")
       
    in.AddCategory("android.intent.category.DEFAULT")
       
    in.PutExtra("Callback","com.maximussoft.myrequestor.CALLBACK")
       
    in.PutExtra("GetSettings","True")
       
    StartActivity(in'Or StartService(returnIntent)
    End Sub
    5. Code the Requester to accept the data
    Again this code is very similar to the Provider except that it gets the data
    Code:
    Sub Activity_Resume
     
    Dim in as Intent
     
    in = Activity.GetStartingIntent
     
    If in <> null Then
        
    If In.HasExtra("Settings"Then
             AcceptSettings 
    'Do something here with your settings
        End If
     
    End If
    End Sub
    Points to note:
    While I dont consider intents to be very advanced, it can be quite overwhelming for newbies, so do your research.

    There are many ways to do things and combinations of services/activities can make things complicated.

    You can add permissions on your intent filters, this way Plugin apps need to have your permission in their manifest. This helps in *some* access control, mainly you can list all apps that can access your app/settings/data.
    To see this in operation you can look at my apps that plugin to each other Cloudpipes and PhoneBackup.
    If I get time I may write a sample otherwise not.
     
  2. RiverRaid

    RiverRaid Active Member Licensed User

    Thank you very much...

    ... for this Tutorial!

    I'm experimenting right now with this and I love it!! :sign0162:
    I'm thinking of Add-Ons to my App (Daydream, Live Wallpaper,..) and all now possible :)
     
  3. thedesolatesoul

    thedesolatesoul Expert Licensed User

    Thats great :)
    Let me know if you find anything missing...it is a really broad subject.
     
  4. nosaj66au

    nosaj66au Member Licensed User

    Great explanation. I would like to understand if this method would suite my application it seems to have possibilities. I would like to setup a what would be best described an a local server and clients application running on a single device (at this stage).Each client would be a separate app but have access to the same data on the server service, but each client would uses the data in different way i.e. reporting, RT displaying, trending ,logging etc. Using this method would it be practical to send a data model of say 100 elements every 1 sec or should I just send 1 element when it changes. (a single larges exchange vs several small exchanges in the same time frame). I guess I'm looking to creating an Android based SOA bus.
    Maybe I'm just asking to much!!!!!?????
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    Consider using HttpServer is you want to build a small (local) server. It will give you more options.
     
  6. thedesolatesoul

    thedesolatesoul Expert Licensed User

    Its hard to say. Using Intents like this may have a fair bit of overhead and a little inflexible. It might still work for you.
    The usual Android method for this would be to use Content Providers, but I dont know how to work with those yet. You can use a shared storage location to share the data?
    Maybe you can go with Erel's suggestion.
     
  7. Rick Harris

    Rick Harris Well-Known Member Licensed User

    Nice idea Erol! It indeed sounds much more simple. Do you have any example code to make two apps exchange data?
     
  8. Erel

    Erel Administrator Staff Member Licensed User

    See HttpServer tutorial.
     
  9. Rick Harris

    Rick Harris Well-Known Member Licensed User

    I found another solution, i.e. by letting App1 store a parameter in a file in the dirrootexternal directory, then start App2 using an intent after which App2 reads the contents of this (shared) file. It works like a dream!
     
  10. cncncn

    cncncn Member Licensed User

    hi,

    I have got this error:
    "An error has occurred in sub:main_sendsettings(java line 341)
    android.content.ActivityNotFoundException:No Activity found to handle Intent { act=null cat =[android.intent.category.DEFAULT]flg=0x20000(has extras)}"

    I have two applications.
    The A application that opens a PDF with Adobe Reader and still running in the background.
    Applying B prevents A when B is create.
    Do I miss something?

    thank you for your future response
     
  11. thedesolatesoul

    thedesolatesoul Expert Licensed User

    Can you post the code for sending the intent?
    Also what you defined the action/activity in the manifest of B?
     
  12. cncncn

    cncncn Member Licensed User

    Code:
    Version=2.71
    IconFile=
    NumberOfModules=
    3
    Module1=widget
    ModuleVisible1=
    1
    Module2=bibli
    ModuleVisible2=
    1
    Module3=SMBService
    ModuleVisible3=
    1
    Package=b4a.example
    DoNotOverwriteManifest=
    True
    ManifestCode=
    'This code will be applied to the manifest file during compilation.~\n~'You do not need to modify it in most cases.~\n~'See this link for for more information: http://www.basic4ppc.com/forum/showthread.php?p=78136~\n~AddManifestText(~\n~<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14"/>~\n~<supports-screens android:largeScreens="true" ~\n~    android:normalScreens="true" ~\n~    android:smallScreens="true" ~\n~    android:anyDensity="true"/>)~\n~SetApplicationAttribute(android:icon, "@drawable/icon")~\n~SetApplicationAttribute(android:label, "$LABEL$")~\n~'End of default text.~\n~AddActivityText(Main,<intent-filter>~\n~<action android:name="com.maximussoft.myprovider.REQUEST"/>~\n~<category android:name="android.intent.category.DEFAULT"/>~\n~</intent.filter>)
    UserTypesHint=
    NumberOfFiles=
    1
    File1=main.bal
    NumberOfLibraries=
    2
    Library1=core
    Library2=
    smb
    @EndOfDesignText@
    #Region  Project Attributes
        
    #ApplicationLabel: Modification
        
    #VersionCode: 1
        
    #VersionName:
        
    'SupportedOrientations possible values: unspecified, landscape or portrait.
        #SupportedOrientations: unspecified
        
    #CanInstallToExternalStorage: False
    #End Region

    #Region  Activity Attributes
        
    #FullScreen: False
        
    #IncludeTitle: True
    #End Region
    'Version 1.0
    'dernière mise à jour faite le 28.04.2014
    Sub Process_Globals
        
    'These global variables will be declared once when the application starts.
        'These variables can be accessed from all modules.

    End Sub

    Sub Globals
        
    'These global variables will be redeclared each time the activity is created.
        'These variables can only be accessed from this module.
        Dim fichier As Int '0=Plan de Q.F. 1=DT 2=N
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
        
    'Do not forget to load the layout file created with the visual designer. For example:
       
       
        
    Activity.LoadLayout("main")
        
    Activity.SendToBack
    '    fichier=1
    '    If fichier =1 Then
    '   
    '        SMBService.Src        = "smb://192.168.1.60/GPAONGV/DOSSIERS/NGTS2222/CLANGDT012/"
    '        SMBService.Fil        = "jeton.txt"
    '        SMBService.Action    = 400
    '       
    '       
    '    End If
    '
    '    StartService(SMBService)
    '    If SMBService.DoneSuccessfully Then
    '        ToastMessageShow("modification impossible",True)
    '           
    '    Else
    '        ToastMessageShow("modification possible",True)
    '    End If
    '   
       
       

    End Sub

    Sub Activity_Resume
        
    Dim In As Intent
        
    In=Activity.GetStartingIntent
        
    If In <> Null Then
            
    Log("envoie 1")
            
    If In.HasExtra("GetSettings"Then
                SendSettings(
    In)
                
    Log("envoie 2")
                
    Return
            
    End If
        
    End If   
       
        
    Activity.Finish
       
    End Sub

    Sub Activity_Pause (UserClosed As Boolean)

    End Sub
    'fonction delay
    Sub Delay(nMilliSecond As Long)As Boolean
    Dim nBeginTime As Long
    Dim nEndTime As Long
    nEndTime = 
    DateTime.Now + nMilliSecond
    nBeginTime = 
    DateTime.Now
    Do While nBeginTime < nEndTime
    nBeginTime = 
    DateTime.Now
    'Log(nBeginTime)
    If nEndTime < nBeginTime Then
    Return True
    End If
    DoEvents
    Loop
    End Sub

    Sub SendSettings(In As Intent)
        
    Dim returnIntent As Intent
        returnIntent.Initialize(
    In.GetExtra("CallBack"),"")
        returnIntent.AddCategory(
    "android.intent.category.DEFAULT")
        returnIntent.PutExtra(
    "Settings","true")
        returnIntent.PutExtra(
    "Successful","true")
        
    StartService(returnIntent)

    End Sub



    And yes i add this code in my manifest of B :
    "
    AddActivityText(Main, <intent-filter>
    <action android:name="com.maximussoft.myprovider.REQUEST" />
    <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>)"
     
  13. thedesolatesoul

    thedesolatesoul Expert Licensed User

    Ok, and what about the intent code for the sending app?
     
  14. incendio

    incendio Well-Known Member Licensed User

    How to set Provider to point to a service?

    I made this code on manifest text
    Code:
    AddServiceText (myService, <intent-filter>
       <action android:name=
    "com.myAppthatHasService.REQUEST" />
       <category android:name=
    "android.intent.category.DEFAULT" />
    </
    intent-filter>)
    Is that the right manifest?

    In your example above, codes to respond from Requester, put below Sub Activity_Resume, where to put respond codes if it is point to Service?

    Thanks.
     
  15. Erel

    Erel Administrator Staff Member Licensed User

  16. thedesolatesoul

    thedesolatesoul Expert Licensed User

    Manifest looks ok to me. Put the respond code in Service_Start and use StartingIntent. Look at Erel's link above.
     
  17. tdocs2

    tdocs2 Well-Known Member Licensed User

    Hello, Rick.

    Sounds clever.

    Can you post your code? Requester: Manifest code and sub to issue intent. Provider: Manifest code and sub where you receive the intent and call sub that reads external file?

    Thank you in advance.

    Sandy
     
  18. tdocs2

    tdocs2 Well-Known Member Licensed User

    Greetings, all.
    Thank you in advance for your help.

    I have no experience doing this. Obviously, I am missing a few building blocks... I have created two apps: IntentRequester and IntentProvider. This is as far as I got… IntentRequester sends the intent to IntentProvider and it works. The IntentProvider app is “killed” and restarted. Why is
    StartActivity in IntentRequester killing the activity and not just bringing it to the front?

    Log
    Code:
    Killing previous instance (main).
    Code in IntentRequester
    Code:
    Sub Activity_Create(FirstTime As Boolean)
        
    'Do not forget to load the layout file created with the visual designer. For example:
        Activity.LoadLayout("1")
        
    Activity.Title="IntentRequester"


    End Sub

    Sub Activity_Resume

    End Sub

    Sub Activity_Pause (UserClosed As Boolean)

    End Sub
    Sub Button1_Click
        
    Dim Intent1 As Intent
        Intent1.Initialize(
    "swi.IntentProvider.REQUEST""")
        Intent1.PutExtra(
    "B4A","")
        
    'Intent1.SetComponent("swi.IntentProvider/.Main")
        StartActivity(Intent1)
     
    End Sub
    Code in IntentProvider
    Code:
    Sub Activity_Create(FirstTime As Boolean)
        
    'Do not forget to load the layout file created with the visual designer. For example:
        Activity.LoadLayout("1")
        
    Activity.Title="IntentProvider"
        Label1.Text=
    DateTime.Time(DateTime.now)

    End Sub

    Sub Activity_Resume
        
    Dim In As Intent
         
    In = Activity.GetStartingIntent
         
    If In <> Null Then
           
    If In.HasExtra("B4A"Then
            
    Log("GetStartingIntent")
            
    Dim Notification1 As Notification
            Notification1.Initialize
            Notification1.Icon=
    "icon"
            
    'Notification1.Insistent=True
            Notification1.SetInfo("IntentProvider""Intent received""")
            Notification1.Notify(
    1)
          
    End If
         
    End If

    End Sub
    Best regards.

    Sandy
     
    Last edited: Oct 22, 2014
  19. Rick Harris

    Rick Harris Well-Known Member Licensed User

    All you have to do is add the following code to App-1 to save a parameter:
    Code:
    'Add this to your App number-1
        Dim Text1 As String
        
    Dim TW As TextWriter
        Text1 = 
    "Hello"
        TW.Initialize(
    File.OpenOutput(File.DirRootExternal, "data1.ini"False))
        TW.Write(Text1)
        TW.Close
    and read it from within App-2 with:
    Code:
    'Add this to your App number-2
        Dim Text1 As String
        Text1 = 
    File.ReadString(File.DirRootExternal, "data1.ini")
        
    ToastMessageShow(Text1,True)
    I assume you are aware that both apps cannot be active at the same time because Android has no multi-tasking and one app will go into pause state as soon as the other app is activated. You could create a service that holds a timer which controls which app should be active (e.g. flip flop every minute). Or you could write code that automatically reactivates your other app as soon as the active app is paused (and vise versa).
     
    Last edited: Oct 29, 2014
    Mikonios likes this.
  20. tdocs2

    tdocs2 Well-Known Member Licensed User

    Thank you, Rick.

    Simple and effective solution. I did manage to pass data directly with Intents. Powerful Tool!

    Best regards.

    Sandy
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice