Android Code Snippet Pass a reference of a View to a service

lemonisdead

Well-Known Member
Licensed User
Hello,

Following @Informatix's advice, here is a simple way I was not aware of to pass a reference of a view to a service.

As you already know, Views can only be declared in Globals. So I use a Globals list as a gateway to a wider Process_Globals list that can be retrieved from the service. Like this :

In the Activity
B4X:
Sub Process_Globals
    'this list is used as a way to pass the View as a Process_Global
    Dim L1 As List
End Sub

Sub Globals
    'this list is used as a gateway between Globals and Process_Globals
    Dim L As List

    Dim mView As Label 'or any other view I think
End Sub

Sub Activity_Create(FirstTime As Boolean)

    If Not(L.IsInitialized) Then L.Initialize
    If Not(L1.IsInitialized) Then L1.Initialize

    If FirstTime Then
        mView.Initialize("")
        mView.Text= "Some text"
        L.Add(mView) 'stores the view in the gateway
        L1.Add(L.Get(0)) 'stores the view from the gateway to the system wide
    End If

End Sub
And in the service where I need the reference to the view :

B4X:
Sub RemoveOverlay
    Dim mView As Label 'same type as the view to retrieve
    mView.Initialize("")
    mView=Main.L1.Get(0) 'gets the reference to the view

End Sub
I hope this could help someone who didn't got it (like me) previously
 

NJDude

Expert
Licensed User
Note that your code doesn't work on Lollipop, it crashes if you open an app that alters the status bar, for example:

1- Open your app and lock the status bar
2- Open the Google Play app
3- Exit Google Play
4- Go back to your app, unlock the status bar
5- BOOM!

On my HTC One (KitKat) it crashes all the time I return to your sample and turn the lock off.

The logs are below.
B4X:
** Service (s1) Create **


** Service (s1) Start **


** Activity (main) Create, isFirst = true **


** Activity (main) Resume **


** Activity (main) Pause, UserClosed = false **


** Activity (main) Create, isFirst = true **


** Activity (main) Resume **


** Activity (main) Resume **


** Activity (main) Pause, UserClosed = true **


** Activity (main) Create, isFirst = true **


** Activity (main) Resume **


** Activity (main) Pause, UserClosed = false **


** Activity (listmemes) Create, isFirst = true **


** Activity (listmemes) Resume **


** Activity (listmemes) Pause, UserClosed = true **


** Activity (main) Resume **


** Activity (main) Pause, UserClosed = true **


** Activity (main) Create, isFirst = false **


** Activity (main) Resume **


java.lang.reflect.InvocationTargetException


	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:109)
	at b4a.example.s1._addoverlay(s1.java:116)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
	at anywheresoftware.b4a.keywords.Common$5.run(Common.java:962)
	at android.os.Handler.handleCallback(Handler.java:739)
	at android.os.Handler.dispatchMessage(Handler.java:95)
	at android.os.Looper.loop(Looper.java:135)
	at android.app.ActivityThread.main(ActivityThread.java:5221)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)


Caused by: java.lang.IllegalStateException: View android.widget.TextView{122390d5 V.ED.... ......I. 0,0-800,100 #3} has already been added to the window manager.
	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:243)
	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
	... 16 more
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
	at anywheresoftware.b4a.keywords.Common$5.run(Common.java:965)
	at android.os.Handler.handleCallback(Handler.java:739)
	at android.os.Handler.dispatchMessage(Handler.java:95)
	at android.os.Looper.loop(Looper.java:135)
	at android.app.ActivityThread.main(ActivityThread.java:5221)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
	at anywheresoftware.b4a.BA.raiseEvent2(BA.java:201)
	at anywheresoftware.b4a.keywords.Common$5.run(Common.java:962)
	... 8 more
Caused by: java.lang.reflect.InvocationTargetException
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:109)
	at b4a.example.s1._addoverlay(s1.java:116)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
	... 9 more
Caused by: java.lang.IllegalStateException: View android.widget.TextView{122390d5 V.ED.... ......I. 0,0-800,100 #3} has already been added to the window manager.
	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:243)
	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
	... 16 more
 

lemonisdead

Well-Known Member
Licensed User
Note that your code doesn't work on Lollipop, it crashes if you open an app that alters the status bar
You are right NJDude : I should have stored the overlay status in a Process_Globals variable instead of relaying on the status of the ToggleButton

The error you get is
... View .... has already been added to the window manager
Knowing your high level of development (not kidding), I am sure you understand the way of correcting my error. BTW, it was just an example and sorry for the behavior.
 

lemonisdead

Well-Known Member
Licensed User
I had a rude exchange with a quidam who was not able to make this work and didn't want to beleive that we could update any view from a service.
After having spent some times with that quidam, I publish the example attached.

What it does : update the time in a label view directly from a service. It is based on the code example of the post #1 and uses the same technic : use a process global list as a Gateway to your activity's view.

The example is very simple. There is no magic nor any other update process. Hope this can help
 

Attachments

Troberg

Well-Known Member
Licensed User
I did something similar, by simply declaring a public variable in Process_Globals as Object, and then assign the view to that object. It works, but it has some disadvantages (IntelliSense does not work, you have to use CallSub).
 
Top