Calling "this" function from another class. What is the best way? - c#

I am working on an app that plays music. Now, I have a function in my main class that chooses a random new song and plays said song:
private void ChooseRandomNewSongAndPlay(bool songHasCompleted)
{
Random rnd = new Random();
int rndValue = rnd.Next(0, Mp3ObjectSmall.Count());
int currentPos = 0;
if (!songHasCompleted)
{
currentPos = mediaPlayer.CurrentPosition; // if song infact has completed, reset position to else save current position (when next has been pressed)
}
WriteSeekingToDataBase(currentPos, CurrentSongObject);
mediaPlayer.Stop();
if (Android.Net.Uri.Parse(CurrentSongObject.Mp3Uri) != null)
{
PhotoAlbumAdapter.OldSongUri = Android.Net.Uri.Parse(CurrentSongObject.Mp3Uri);
}
PhotoAlbumAdapter.NewSongUri = (Android.Net.Uri.Parse(Mp3ObjectSmall[rndValue].Mp3Uri));
PlayMusic((Android.Net.Uri.Parse(Mp3ObjectSmall[rndValue].Mp3Uri)));
}
But I also set up a broadcast receiver, so when the user is in his car and clicks on next song from the car stereo, I also want the above function to be played.
But here is the problem:
I cannot make this above function public static since it calls other non static functions. I would have to make those static too, but that would cause many, many other errors and is not a good solution at all I believe.
Also, I cannot create a new object of my main class in within the broadcast receiver as such: class xy = new class(). I cannot do that, because that would also create another object of my mediaplayer object, but this object needs to be the same to skip to a next some. If it isnt, just anoither song is played on top of the first song which of course is also not good.
Lastly, I cannot just hand over the class as a parameter to the constructor of the broadcast receiver. I am getting told then that the braodcast receiver needs to have a "standart constructor" so I cannot alter the parameters.
Unfortunately, these 3 optiones are all I believe I have and neither seems to work. What I really, really do not want to do is to copy paste all functions from my main class into the broadcast receiver for obvious reasons.
Can you guys help me out here?
Thank you!

You didn't specified if you broadcast receiver is an activity-local broadcast receiver or application-wide broadcast receiver.
LocalBroadcastReceivers can be created as activity's property and let you broadcast messages within the app, while classic BroadcastReceivers can let you respond to an action coming from outside your app even if your app is closed.
If you have a BroadcastReceiver you can, when it receives a message from, make it republish the message through LocalBroacastManager.
Also your activity must setup a LocalBroadcastReceiver that handles that particular internal broadcast message.
Doing so, you don't worry about Activity state. When the global BroadcastReceiver is invoked, it broadcast the message inside the application, and if there's some receiver listening to they will be invoked all, otherwise the message is simply ignored with no bugs, retain cycles or crashes.
I suppose you are using Xamarin Android.
You can get the full documentation about receivers here
https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/broadcast-receivers

The easiest way is to just create a single static instance from your class and fire the functions:
public static Activity_Player Instance;
then in the broadcast recevier:
Instance.MYFUNCTION

How about creating a property on the broadcast receiver and using that to pass a reference to the main class?
public class MyBroadcastReceiver
{
// Constructor
public MyBroadcastReceiver() {}
// property
public MyMainClass {get;set;}
}
public MyMainClass
{
private void CreateBroadcastReceiver()
{
var br = new MyBroadcastReceiver();
br.MyMainClass = this;
}
}

Related

C#: Access function of another class when having to use a default constructor and making it static is not an option

I am working on a little app that includes a broadcast receiver.
Broadcast receivers HAVE to HAVE a default constructor. Don't ask me why...
Anyway, This is it:
[BroadcastReceiver]
public class IntentReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (AudioManager.ActionAudioBecomingNoisy.Equals(intent.Action))
{
Activity_Player.Instance.PlayOrPauseLogic();
}
}
}
The problem is, that when this function fires (becoming noisy means someone unplugged the headset) I need to be able to stop the current music playing.
In my main class, I have a MediaPlayer object called mediaplayer. I now need to call this mediaplayer object with the ".Stop()" prompt.
This means however, that I cannot just create a new object from my class and then call Stop() on this media player, since this would not affect the currently playing media player.
I can also not hand the media player over into broadcast recevier, since the constructor needs to be the default one.
Lastley, making the mediaplayer object static is also NOT an option for many reasons now.
So what can I do?
What I did now is make a single instance of my activity and THEN call stop on this instance. This is a very bad solution since it causes memory leaks and I need to get rid of it.
Please help me.
Thank you! :)

Sending messages to all clients in Unity PUN (C#)

this is a silly question but i can't figgure it out, I tried looking it out but nothing was what i was looking, so i thought that asking might be a good way.
In my game i would like a client to be able to send messages (messages not for the users, if not for the other clients to interpreted into code) to everyone in it's room:
"(User1): How many points does everyone have?"
"(User2): Hey, I got 5 points"
"(User3): Hey, I got 10 points"
"(User1): Time is over, tell me your points:"
"(User2): Hey, I got 20 points"
"(User3): Hey, I got 30 points"
"(User1): User 3 won"
Of course, this is more of a graphical example, what I want is to be able to send messages to all clients (in the room) so other clients can process tjem. I would like to know how to do it and if this is a possible trough PUN (Unity Photon Network). Or if there is other way to do this over UnityNetworking. Additionally, this would be over LAN not over the internet.
Thank you in advanced.
You are looking for RPC's:
https://doc.photonengine.com/en-us/pun/current/gameplay/rpcsandraiseevent
This allows you to call to only the master, to only clients, or to a specific player.
Before the function you put "[PunRPC]" (without the qoutes), this makes the method callable by RPC:
[PunRPC]
public void GetScore(int score)
{
//Do something
}
The class that calls the RPC requires have a photonview attached or extend from Pohotn.PunBehaviour, and calls the function as following:
photonView.RPC("function", targets, arguments);
The "function" is the rpc as a string, in the example case it would be GetScore, the target could be either a PhotonPlayer instance, or you could use the PhotonTargets enum.
I like to create a singleton class that handles the RPC's (Remember, this only works if the class has only 1 instance):
using UnityEngine;
public class RPC : Photon.PunBehaviour
{
public static RPC singleton;
private void Awake()
{
if(singleton != null && singleton != this)
Destroy(this);
singleton = this;
}
//Called by someone who wants to set the score
public void CallSetScore(sbyte score)
{
this.photonView.RPC("SetScore", PhotonTargets.All, score);
}
[PunRPC]
public void SetScore(sbyte score)
{
//Do something with the score
}
}

How to establish connect/disconnect event handlers in class that utilizes the blink1 HidLibrary?

I'm attempting to detect two events for this particular USB device (blink1): insert and remove
I've successfully enumerated the device(s) and can send commands, though I'm having a difficult time establishing the delegates and getting either event to trigger.
The HidLibrary.cs library contains two event handlers titled "InsertedEventHandler", "RemovedEventHandler" and the functions "DeviceEventMonitorInserted", "DeviceEventMonitorRemoved" which seem to be attached to an instance of the HidDeviceEventMonitor.cs class. I'm attempting to establish connect/disconnect/re-connect methods within the calling class where I utilize the HidLibrary class as:
using HidLibrary
...
private HidDevice hidDevice;
...
hidDevice.command(var1, var2, ..);
I feel this is a simple task, and I've established and worked with event handlers, routed events and delegates in the past to a limited degree in C# but I seem to be missing a crucial concept when dealing with this particular situation.
Update: In case anyone else comes across this when working with the blink1 HidLibrary, to enable the EventMonitor you must set hidDevice.MonitorDeviceEvents = true after calling OpenDevice() on the HidDevice instance. This isn't in any of the documentation and only became apparent after getting the event routing down.
I don't have any Blink1 devices, but after spending a few minutes with the code, I think this might work:
public static void Main()
{
HidDevice device;
// device declaration
device.Inserted += Device_Inserted;
device.Removed += Device_Removed;
}
private static void Device_Removed()
{
// Some stuff to do when device is removed
throw new NotImplementedException();
}
private static void Device_Inserted()
{
// Some stuff to do when device is inserted
throw new NotImplementedException();
}

C# - Design Thoughts on Passing by Reference

I have a C# Windows Service that routes incoming emails and twitter comments to available Agents (I don't really - but the app does something very similar). So, I have a list of Agents, and logic to route these emails and tweets to available agents.
How does my code look?
I have an AgentManager class that keeps track of which agents are available, their skill levels, etc.
I have an EmailManager class that routes Emails to Agents.
I have a TwitterManager class that routes Tweets to Agents.
So - logic pertaining to Agents, such as the list of Agents, who is available, who has capacity for a Tweet, who has capacity for an Email, etc is all in the AgentManager.
Now, when EmailManager detects that there is a new email and needs to assign it to an Agent, I want
to get my list of agents from AgentManager(rather than going back to the database or keeping a separate list of Agents in EmailManager).
My initial thought is to pass AgentManager to EmailManager by reference. The reason I want to do this is so as Agents change state, are added/removed, etc - EmailManager will always be working wit
h the latest AgentManager (and therefore the latest Agent list). Somehow - this feels dirty. I know it is out of fashion to pass by ref, but it seems to be a good way to handle this. Am I doing it wrong?
EDIT:
I am passing the AgentManager by reference for storage, not to change it in the EmailManager class.
From your descriptions seems more soud to go the other way.
An AgentManager process EMails and Tweets and knows everything of its Agents -
So it should have a method that receive a list of EMails/Tweets and process them.
Because we are speaking of reference-types the question about passing by ref is a bit unclear.
For example:
AgentManager ag = new AgentManager();
EMailManager eg = new EMailManager();
TweetManaget tg = new TweetManager();
eg.LoadEMail();
List<EMails> mails = eg.GetMailsList();
tg.LoadTweet();
List<Tweets> tws = tg.GetTweetsList();
ag.ProcessData(mails, tws);
EDIT: Looking at the comment from OP I have thought of another strategy
Let the EMailManager and TweetManager declare an Event to which the AgentManager subscribe-
eg.EmailReceived += ag.NotifyEmail;
tg.TweetPolled += ag.NotifyTweet;
public class EventManager
{
public delegate void OnMailReceived(EMails m);
public event MailReceived;
........
private void GetMail()
{
EMails m;
.....
if(MailReceived != null)
MailReceived(m);
}
}
public class AgentManager()
{
public void NotifyEMail(EMails m)
{
.....
}
}

Writing to a label from a static function

I'm trying to do something that I thought would be easy but can't figure out how to write to a label inside my stating function.
public static void StartProcessing(object data)
{
lblError.Text = "Blah Blah"
}
I get the error "An object reference is required for the non-static field, method, or property..."
So I tried creating a new instance of the label and adding it to a new instance of a control (Panel) but the lblError isn't getting displayed
public static void StartProcessing(object data)
{
Panel Panel1 = new Panel();
Label lblError= new Label();
Panel1.Controls.Add(lblError);
lblError.Visible = true;
lblError.Text = "Blah Blah";
}
there must be an easy way to do this? Which i've overlooked..
The function is getting called as follows: If I change the above to not be static I get an error message on the second line below saying the same "An object reference is required for the non-static field, method, or property..." When this function isn't static?
public object LaunchNewProcess(object data)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(ProcessStatuses.StartProcessing),
new object[] {newProcess, allProcesses}
);
Pass the label to your static function when you call it:
public static void StartProcessing(object data, Label lblError)
{
lblError.Text = "Blah Blah"
}
Static functions don't have access to controls because the controls belong to the instance of the page (class).
Static means that all instances of a class share the same function or variable. So, an instance of a class has access to a static variable or function. However, since a static is not "aware" of any instances of the class, it cannot access the members of an instance. In fact, a static method or variable does not even require any instance of the class to exist, so how could it?
Removing the static key word from your function will also work, as others have mentioned, but I'm assuming you made it static for a reason.
EDIT
Alright, this is more complex.
So, you have some class that launches a bunch of threads, and you want it to display to the user if something went wrong? Well, your current approach is flawed because you cannot access controls of a page without the instance of the page. Also, I am not sure how this approach would fit within the page lifecycle.
Your best approach (sorry for lack of code, it's going to depend a lot on your implementation) could be something like this:
//do this before you start spawning threads
List<bool> successes = new List<bool>();
ThreadPool.QueueUserWorkItem(
new WaitCallback(ProcessStatuses.StartProcessing),
new object[] {newProcess, allProcesses, successes}
);
//you MUST wait for all your threads to complete before proceeding!
if(successes.Any(s => !s))
{
//update your error label
}
public static void StartProcessing(object data, Label lblError)
{
var dataArray = (object[3]) data;
//if there is an error
dataArray[2] = false;
}
What you want to do is actually quite difficult.
You want to create a page, start an asynchronous task, send the page to the user, and then update content on the page after the asynchronous job finishes.
The problem is that by the time the asynchronous task finishes the page has already been sent, and based on the way HTTP works once you've sent your response you're done; there's not more communicating with the client for you. You need to wait for the client to send another request if you want to update them.
This means that you need to have JavaScript code that is constantly polling the server basically asking, "Are you done yet, are you done yet, are you done yet?" until eventually the server says, "Yes, here's something to display on the page".
Fortunately, you don't need to start from scratch. Here you'll find an example by Microsoft that does all of this; you can modify it to suit your needs. It's also worth mentioning that in addition to being non-trivial to program, it also consumes a lot of resources to constantly poll the server, so be sure you really need to do this.
Option 2 is to just not start the other tasks in new threads, and execute the code serially before the page is ever returned to the user. They'll be staring at a blank screen for a while, but it'll be MUCH easier to program. The one downsize to keep an eye on here is on timeouts if the task is REALLY long running.

Categories

Resources