Android Question Event not being called in Main Activity from Class Module

Falcon

Member
Licensed User
Hi Gurus,

OK so I have a Helper Class Module I made called 'JRHelper' and in there I have a sub which will show the Device's Image Gallery and then wait for the user to pick an image.
I then want to call a Event sub in my Main Activity once the image has been picked, but the problem is that the Event is only called if I step through the code with a Breakpoint, if I just
run it (either in Debug or Release mode) it will not call the Event.

The code in my Main Activity:

B4X:
Sub Globals
     Private JRHelper_ As JRHelper            'My Helper Class Module.
End Sub


Sub Activity_Create(FirstTime As Boolean)
   JRHelper_.Initialize(Me,"JRHELPER")    'Initialise my Helper Class Module.
End Sub


Sub Button1_Click  
    JRHelper_.ShowImageGallery()  
End Sub


'This is the Event Sub I am trying to call from my Class Module.
Private Sub JRHELPER_ImageGalleryFileSelected(strRealFilePathName As String, strVirtualFilePathName As String)

    'Get the Image's File Name and it's Path separately.
    Dim strRealFileName As String = JRHelper_.GetFileName(strRealFilePathName)
    Dim strRealPath As String = JRHelper_.GetPath(strRealFilePathName)

    'Make the image's Max Height or Width 300 pixels to reduce size & loading times in the Database.
   Dim ReducedSizeBitmap As Bitmap = JRHelper_.ResizeImage(strRealPath,strRealFileName,300)

End Sub


In my Class Module I have the following code:

B4X:
'Declare my Event which is in the Main Activity.
#Event: ImageGalleryFileSelected(strRealFilePathName as string, strVirtualFilePathName as string)

Sub Class_Globals
    Private Caller_ As Object                  'The Main Activity.
    Private strEventName_ As String      'The event prefix.
End Sub


Public Sub Initialize(Caller As Object,strEventName As String)
    Caller_ = Caller                                 'Get my Main Activity 
    strEventName_ = strEventName     'Get my event prefix.
End Sub


Public Sub ShowImageGallery()
     
    'Prompt the user with a message box to grant permission for access to external storage.
    RequestPermissionToReadExtStorage
            
    'Show the Device's Image Gallery.
    Dim chooser As ContentChooser
    If chooser.IsInitialized = False Then
        chooser.Initialize("chooser")
    End If
   
    chooser.show("image/*", "Choose Image")
    
    Wait For(chooser) chooser_Result (Success As Boolean, Dir As String, FileName As String)
         
    If Success Then
         
        
        Dim strRealFilePathName As String = GetRealFilePathNameFromContentChooser(FileName)
        Dim strVirtualFilePathName As String = Dir & ";" & FileName

        'Call my Event in the Main Activity   <----- This only works when I step it with a Break Point.
        CallSubDelayed3(Caller_, strEventName_ & "_ImageGalleryFileSelected",strRealFilePathName,strVirtualFilePathName)
              
    Else
        'No image was selected.
    End If
     
End Sub


Public Sub RequestPermissionToReadExtStorage

    RuntimePermission.CheckAndRequest(RuntimePermission.PERMISSION_READ_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    Sleep(50)

End Sub
 

Falcon

Member
Licensed User
Hi LucaMs. I removed the _ as you suggested in all variable names, but it still only works if I set a break point and step through the code.
If I run it either in Debug without breakpoints it does not work. It also does not work in release mode. I can't understand what I'm doing wrong? Any ideas?
 
Upvote 0

Falcon

Member
Licensed User
Hmmm...update. Now suddenly it is working! All I did was put a message box here:

B4X:
Wait For(chooser) chooser_Result (Success As Boolean, Dir As String, FileName As String)
        
    If Success Then
       
        Msgbox("Hello","")    <---- I just added this.

   End if

Once I added that message box, it then worked.
I actually added the message box just so that I could see if the chooser 'Success' variable was getting set.

I have now subsequently removed the message box and it still works. Any idea what is going on here?
 
Upvote 0

Falcon

Member
Licensed User
Hi Agraham.

When you say Class Instance, I assume you mean the ContentChooser?
If so, it is declared in the Class Module, not the Main Activity.
 
Upvote 0

Falcon

Member
Licensed User
I have declared an instance of the Helper class in Sub Globals of the main Activity.
Like so:

B4X:
Sub Globals
   Private JRHelper1 As JRHelper 
End Sub
 
Upvote 0

Falcon

Member
Licensed User
Yeah I'm also baffled! I may be a noob in B4A, but my logic still tells me this should work! ?
Just out of frustration I have now moved everything to do with the Content Chooser to the Main Activity and it seems to be working fine now.
But thank you so much for the help, I really appreciate it.

By the way, while I am talking to you, I have another small issue which maybe you can help me with?
You see, when I select an Image in the Gallery (after opening it with the ContentChooser), a few seconds pass before it actually puts the Image in my image view control, so it kinda looks as though nothing is happening. Is there a way to put a message somewhere?
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
I could say nonsense (I'm still sleeping).
The RequestPermissionToReadExtStorage routine should be a Resumable (also, maybe you don't need it to be public, but that's okay).
ShowImageGallery too.

I mean they must be completed before returning the result.
 
Upvote 0

Falcon

Member
Licensed User
Hi LucasMs, thank you for the info, maybe you onto something there?

I don't suppose one of you boffins/gurus could give me an example project that actually works, woiuld probably take you 5 mins to create! :)
Basically a Class Module with the sub in it to open the Image Gallery, and then when the user clicks an Image it raises an event in the Main Activity.

Up for the challenge? ;)
 
Upvote 0

Falcon

Member
Licensed User
The reason why I wanted the Path and Filename is because I perform some operations such as compression, rotation etc on the image and I need the file/path name for that.
Once I have done that, I save the bitmap data to my remote SQL Server Database.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
For the moment I am attaching a test project where the class returns a B4XBitmap, not Path and FileName.

I believe (I could be wrong) that it is not possible to ask for permissions from within a class (I should do other tests but not now).

It has a very handy thing: the ChooseBitmap function has an example to copy and paste with a click that also contains the useful Erel's FitImageToView routine.
 

Attachments

  • ChooseImageTest.zip
    16.3 KB · Views: 134
Upvote 0

Falcon

Member
Licensed User
You sir are a legend! It is working great now! :D
One thing that I see is that you are not using 'CallSub' at all, so I guess that has solved the issue, for they seem to be a bit tempremental!

Anyway I have added some stuff onto your code to get the Bitmap, Real File Name & Path and Virtual File Name and Path returned, maybe it will be useful for others:

The complete code:

In the Main Activity:

B4X:
Sub Globals

   Private ImageChooser as ImageChooserClass
   Private RunTimePermission As RuntimePermissions

End Sub


Sub Activity_Create(FirstTime as Boolean)

   ImageChooser.Initialize(Me,"ImageChooser")

End Sub


Sub Button1_Click

    RunTimePermission.CheckAndRequest(RunTimePermission.PERMISSION_READ_EXTERNAL_STORAGE)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
   
    If Not(Result) Then
        Wait For MsgBox_Result (Unused As Int)
    End If

    Wait For (ImageChooser.ChooseImage()) Complete(Data As mContentChooserData)

    Dim strMyChosenFileName as string  = Data.RealFileName
    '.....etc........

End Sub


In the Class module:

B4X:
Sub Class_Globals

Dim mContentChooser As ContentChooser  
Dim mCaller as Object
Dim mstrEventName as String

Type mContentChooserData(Bitmap As B4XBitmap,RealDir As String, RealFileName As String, VirtualDir As String, VirtualFileName As String)

End Sub


Public Sub Initialize(Caller As Object,strEventName As String)
   
    mCaller = Caller
    mstrEventName = strEventName
    mContentChooser.Initialize("chooser")
   
End Sub


Public Sub ChooseImage() As ResumableSub   
   
    mContentChooser.show("image/*", "Choose Image")
    Wait For chooser_Result (Success As Boolean, Dir As String, FileName As String)
       
    If Success = True Then
               
        Dim strRealFilePathName As String = GetRealFilePathNameFromContentChooser(FileName)  'e.g. '/storage/emulated/0/DCIM/Camera/IMG_20201207_195412.jpg'
        Dim strRealFileName As String = GetFileName(strRealFilePathName)   'e.g. 'IMG_20201207_195412.jpg'
        Dim strRealPath As String = GetPath(strRealFilePathName)           'e.g. '/storage/emulated/0/DCIM/Camera'
           
        Dim Bitmap As B4XBitmap= LoadBitmap(Dir,FileName)
           
        Dim Data As mContentChooserData
        Data.Initialize
        Data.RealDir = strRealPath
        Data.RealFileName = strRealFileName
        Data.VirtualDir = Dir
        Data.VirtualFileName = FileName
        Data.Bitmap = Bitmap
       
        Return Data

    End If
   
    Return Null
       
End Sub


Public Sub GetRealFilePathNameFromContentChooser(UriString As String) As String
   
    If UriString.StartsWith("/") Then Return UriString 'If the user used a file manager to choose the image
    Dim Cursor1 As Cursor
    Dim Uri1 As Uri
    Dim Proj() As String = Array As String("_data")
    Dim cr As ContentResolver
    cr.Initialize("")
    If UriString.StartsWith("content://com.android.providers.media.documents") Then
        Dim i As Int = UriString.IndexOf("%3A")
        Dim id As String = UriString.SubString(i + 3)
        Uri1.Parse("content://media/external/images/media")
        Cursor1 = cr.Query(Uri1, Proj, "_id = ?", Array As String(id), "")
    Else
        Uri1.Parse(UriString)
        Cursor1 = cr.Query(Uri1, Proj, "", Null, "")
    End If
    Cursor1.Position = 0
    Dim res As String
    res = Cursor1.GetString("_data")
    Cursor1.Close
    Return res
   
End Sub


'Will return just the Path from the given path/file name.
'ie. '/storage/emulated/0/DCIM/Camera/mypic.jpg will return '/storage/emulated/0/DCIM/Camera'
Public Sub GetPath(Path As String) As String

    Dim Path1 As String
    Dim L As String
   
    If Path = "/" Then
        Return "/"
    End If
    L = Path.LastIndexOf("/")
    If L = Path.Length - 1 Then
        'Strip the last slash
        Path1 = Path.SubString2(0,L)
    Else
        Path1 = Path
    End If
    L = Path.LastIndexOf("/")
    If L = 0 Then
        L = 1
    End If
    Return Path1.SubString2(0,L)
   
End Sub


'Will return just the File Name from the given path.
'ie. '/storage/emulated/0/DCIM/Camera/mypic.jpg' will return 'mypic.jpg'
Public Sub GetFileName(FullPath As String) As String
    Return FullPath.SubString(FullPath.LastIndexOf("/")+1)
End Sub


[/code}
 
Upvote 0
Top