im trying to create an android plugin and import it in unity but i always get 0 as return value from the plugin method and i cant fix this issue.
Here is what i did:
AndroidStudio:
-Created a new project
-Created a library module (package: com.e.timerlibrary)
-Created Public Class "MyPlugin"
-Build -> "Make Module 'timerlibrary'"
-copied "classes.jar" file into "Assets/Plugins/Android" in Unity
MyPlugin only has one method:
public int testmethode(){
return 100;
}
Unity:
AndroidJavaObject JavaTimerClass = new AndroidJavaObject("com.e.timerlibrary.MyPlugin");
TextPlugin.text = JavaTimerClass.Call<int>("testmethode").ToString();
TextPlugin.text should display "100" but its always 0.
It seems like the name of the package cant be found
Hopefully someone can help me. Im new to unity&Androidstudio and followed many tutorials on youtube but i cant fix this issue.
Here is my full c# code. it's basically a timer.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CountDownTimer : MonoBehaviour
{
public float timeValue = 0;
public float timeValuePause = 0;
public float sliderValue;
public Slider slider;
public Text textTimer;
public Text textTimerBtn;
public Text TextPlugin;
bool timerActive = false;
bool backTimerActive = false;
AndroidJavaObject JavaTimerClass = new AndroidJavaObject("com.e.timerlibrary.MyPlugin");
int testvar1;
// Start is called before the first frame update
void Start()
{
textTimer.text = timeValue.ToString();
//startService();
}
// Update is called once per frame
void Update()
{
if (timerActive)
{
timeValue -= Time.deltaTime;
textTimer.text = timeValue.ToString("f0");
slider.value = timeValue;
if (timeValue <= 0)
{
timerActive = false;
textTimerBtn.text = "Start";
timeValue = 0;
slider.interactable = true;
}
}
}
public void OnTimerBtnClick()
{
textTimerBtn.text = timerActive ? "Start" : "Stop";
timerActive = !timerActive;
slider.interactable = false;
if (timerActive==false)
{
timeValue = 0;
textTimer.text = timeValue.ToString("f0");
slider.interactable = true;
slider.value = 0;
}
}
public void GetValueOfSlider(float value)
{
if (timerActive == false)
{
textTimer.text = value.ToString("f0");
timeValue = value;
}
}
void OnApplicationPause(bool pause) //Wird nur jeweils 1 mal ausgeführt!!
{
if (pause)
{
//startService1();
//TextPlugin.text = "pause";
TextPlugin.text = JavaTimerClass.Call<int>("testmethode").ToString();
}
else
{
//TextPlugin.text = "unpause";
stopService1();
}
}
void startService1()
{
/* if (!backTimerActive)
{
JavaTimerClass.Call("StartTimerService");
backTimerActive = true;
} */
TextPlugin.text = JavaTimerClass.Call<int>("testmethode").ToString();
//TextPlugin.text = JavaTimerClass.Call<int>("GetTime").ToString();
}
void stopService1()
{
//TextPlugin.text = JavaTimerClass.Call<int>("StopTimerService").ToString();
backTimerActive = false;
}
}
here is java code:
package com.e.timerlibrary;
public class MyPlugin {
public int testmethode(){
return 100;
}
}
i know it looks pretty bad but im only trying to get the plugin to work
Related
I am using photon to make a FPS game for android.
Here is the code:
using UnityEngine;
using UnityEngine.UI;
public class SceneLoaderButton : Photon.PunBehaviour {
public string roomName, mapNameGL, password;
public GameObject loadingPan;
public MenuRooms menuManager;
// Use this for initialization
void Start () {
Button btn = GetComponent<Button> ();
btn.onClick.AddListener (ConnectCustomRoom);
}
// Update is called once per frame
void Update () {
}
void ConnectCustomRoom(){
string room = roomName;
RoomInfo[] ri;
ri = PhotonNetwork.GetRoomList ();
bool correct = false;
string passwd, mapName = "";
passwd = password;
foreach (RoomInfo info in ri) {
if (info.name == room) {
if (info.customProperties ["Password"].ToString() == passwd) {
print(info.playerCount + "/" + info.maxPlayers);
if (info.playerCount < info.maxPlayers)
{
correct = true;
}
else
{
menuManager.error("No room for you");
}
mapName = info.customProperties ["MapName"].ToString ();
}
else
{
menuManager.error("Incorrect password");
}
}
}
mapNameGL = mapName;
print(mapNameGL);
if (correct) {
print("Correct");
loadingPan.active = !loadingPan.active;
PhotonNetwork.playerName = "Player" + UnityEngine.Random.Range (1000,9999).ToString();
PhotonNetwork.JoinRoom(room);
}
}
void OnJoinedRoom()
{
print("Joined room: " + roomName);
//We joined room, load respective map
Application.LoadLevel(mapNameGL);
}
}
This is the code from button. It is instantiated and it should join the room, then load the scene. In other scripts, "onjoinedroom" callback works, even if I inherite from Photon.MonoBehaveiour, not from PUNBehaveiour. What is wrong?
based on PUN documentation, it is a virtual member, so you can override that method.
try to change the method to :
override void OnJoinedRoom ()
{
//your codes
}
//or
public override void OnJoinedRoom ()
{
//your codes
}
This class provides a .photonView and all callbacks/events that PUN
can call. Override the events/methods you want to use. By extending
this class, you can implement individual methods as override.
Hope that's help you.
Reference :
PUN Documentation
The script I have is for to pause and unpause the gameobject . I have two of the same errors (31,16): error CS1525: Unexpected symbol (', expecting)', ,',;', [', or='
I am just trying to pause and unpause the gameobject . Maybe pause and unpause more in my scene . I need the gameobject pause for a couple of seconds and unpause . Dont what to pause the gameobject by a key. Here is my script :
using UnityEngine;
using System.Collections;
public class star : MonoBehaviour {
GameObject[] pauseObjects;
void Start () {
pauseObjects = GameObject.FindGameObjectsWithTag("Player");
}
void Pause(){
StartCoroutine(waitToUnpause);
}
IENumerator waitToUnpause(){
//do the thing to pause game
Time.timeScale = 7f;//or some other method
yield return new WaitForSeconds(7);///or any duration you want
Time.timeScale = 1f;//or some other method
}
void pauseGameobject()
{
timeLeft -= Time.deltaTime;
if(timeLeft < 0)
gameObject.SetActive(false);
{
start coroutine("wait");
}
}
public ienumenator wait()
{
time.timescale = 0;
yield return new waitforsceonds(7);
time.timesale = 1;
}
void pauseGameobject()
{
if(timerleft < 0)
{
start coroutine("wait");
}
}
public ienumenator wait()
{
time.timescale = 0;
yield return new waitforsceonds(7);
time.timesale = 1;
}
}
This code is compiling without errors (yours is pretty ... unclean). It will definitely not work though. Also I changed some naming to match naming conventions (lower/upper case).
using UnityEngine;
using System.Collections;
public class Star : MonoBehaviour {
GameObject[] pauseObjects;
// I guess this variable is meant to be a field
// it is never set to any initial value!
float timeLeft;
void Start () {
pauseObjects = GameObject.FindGameObjectsWithTag("Player");
}
void Pause(){
StartCoroutine(WaitToUnpause());
}
IEnumerator WaitToUnpause(){
//do the thing to pause game
Time.timeScale = 7f;//or some other method
yield return new WaitForSeconds(7);///or any duration you want
Time.timeScale = 1f;//or some other method
}
void PauseGameobject()
{
timeLeft -= Time.deltaTime;
if(timeLeft < 0)
{
gameObject.SetActive(false);
StartCoroutine(Wait());
}
}
public IEnumerator Wait()
{
Time.timeScale = 0;
yield return new WaitForSeconds(7);
Time.timeScale = 1;
}
// The following code is nearly a duplicate of the above two functions
// void PauseGameobject()
//
// {
//
// if(timeleft < 0)
//
// {
//
// StartCoroutine(Wait());
//
// }
//
// }
//
// public IEnumerator Wait()
//
// {
//
// Time.timeScale = 0;
//
// yield return new WaitForSeconds(7);
//
// Time.timeScale = 1;
//
// }
}
I am building a simple game in flash for android. I am using AS3. After publishing the APK and trying it on the device, the game crashes automatically. and it doesn't even use a lot of resources. I tried everything but still the same problem.
I also tried publishing the apk with and without the Adobe Air Embedded.
Can Anyone tell me why is this happening?
And I am using an accelerometer. And the Frame rate is 24.The Device is Redmi note 4g.
below is the code for two classes.
package
{
import flash.display.MovieClip;
import flash.events.AccelerometerEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.events.TouchEvent;
import flash.sensors.Accelerometer;
import flash.utils.Timer;
public class laduCatch extends MovieClip
{
public var rat:MovieClip;
//declaring the array for ladus
private var laduarr:Array;
public var score:Number = 0;
public var missed:Number = 0;
public function laduCatch()
{
laduarr = new Array();
//TIMER DECLARATION AND INITIALISATION
var ladutimer:Timer = new Timer(500);
ladutimer.addEventListener(TimerEvent.TIMER,addladu);
ladutimer.start();
//ADDING LADU;
function addladu(e:TimerEvent):void
{
var ladu1 : ladu = new ladu();
stage.addChild(ladu1);
laduarr.push(ladu1);
trace(laduarr.length);
}
function gameloop(event:Event):void
{
laduoutofstage();
}
function laduoutofstage():void
{
for (var i:int = 0; i < laduarr.length; i++)
{
var currladu:ladu = laduarr[i];
if (currladu.y > stage.stageHeight)
{
//trace("ladu out of the screen");
laduarr.splice(i, 1);
//trace("ladu out and removed from array");
//trace(laduarr.length);
currladu.destroyladu();
missed++;
//trace("Ladu missed");
//trace(missed);
missedScore.text = String(missed);
//trace("ladu destroyed sucsessfully");
}
else if (rat.hitTestObject(currladu))
{
laduarr.splice(i, 1);
//trace(laduarr.length);
currladu.destroyladu();
//trace("ladu collected");
score++;
//trace(score);
collectedScore.text = String(score);
}
}
}
stage.addEventListener(Event.ENTER_FRAME, gameloop);
//ACCELEROMETER LOGIC
function ratmove(event:Event):void
{
var sen : Accelerometer = new Accelerometer();
sen.addEventListener(AccelerometerEvent.UPDATE, update);
sen.setRequestedUpdateInterval(4);
function update(event:AccelerometerEvent):void
{
//trace(rat.x);
//trace(rat.y);
rat.x -=(event.accelerationX*2);
//rat.y +=(event.accelerationY*2);
if (rat.x < 20)
{
rat.x = 20;
}
else if (rat.x>stage.stageWidth-20)
{
rat.x = stage.stageWidth - 20;
}
}
}
stage.addEventListener(Event.ENTER_FRAME, ratmove);
}
}
}
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class ladu extends MovieClip
{
public function ladu()
{
addEventListener(Event.ADDED_TO_STAGE,init);
this.stop();
}
public function init(e:Event):void
{
this.y = -20;
this.x = randomRange(0, stage.stageWidth);
moveladu();
}
public function moveladu():void
{
addEventListener(Event.ENTER_FRAME, laduloop);
}
public function laduloop(e:Event):void
{
this.y += 32;
}
public function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
public function destroyladu():void
{
parent.removeChild(this);
removeEventListener(Event.ENTER_FRAME, laduloop);
}
}
}
I think you should separate your functions instead of nesting them inside each others. Why:
You set Event Listener to run ratmove() on every frame, but inside ratmove function you also create new accelerometer each time and assign event listener for it, and this happens again and again on every frame, so I guess eventually it will just crash.
I would take all functions from the constructor and keep them separated to avoid this. Structure would look somehow like this:
package
{
import flash.display.MovieClip;
import flash.events.AccelerometerEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.events.TouchEvent;
import flash.sensors.Accelerometer;
import flash.utils.Timer;
public class laduCatch extends MovieClip
{
public var rat:MovieClip;
//declaring the array for ladus
private var laduarr:Array;
public var score:Number = 0;
public var missed:Number = 0;
public function laduCatch()
{
laduarr = new Array();
//TIMER DECLARATION AND INITIALISATION
var ladutimer:Timer = new Timer(500);
ladutimer.addEventListener(TimerEvent.TIMER,addladu);
ladutimer.start();
stage.addEventListener(Event.ENTER_FRAME, gameloop);
ratmove(); //CALL THIS ONLY ONCE HERE since it will add eventlistener for accelerometer
}
public function addladu(e:TimerEvent):void
{
var ladu1 : ladu = new ladu();
stage.addChild(ladu1);
laduarr.push(ladu1);
trace(laduarr.length);
}
public function gameloop(event:Event):void
{
laduoutofstage();
}
public function laduoutofstage():void
{
for (var i:int = 0; i < laduarr.length; i++)
{
var currladu:ladu = laduarr[i];
if (currladu.y > stage.stageHeight)
{
//trace("ladu out of the screen");
laduarr.splice(i, 1);
//trace("ladu out and removed from array");
//trace(laduarr.length);
currladu.destroyladu();
missed++;
//trace("Ladu missed");
//trace(missed);
missedScore.text = String(missed);
//trace("ladu destroyed sucsessfully");
}
else if (rat.hitTestObject(currladu))
{
laduarr.splice(i, 1);
//trace(laduarr.length);
currladu.destroyladu();
//trace("ladu collected");
score++;
//trace(score);
collectedScore.text = String(score);
}
}
}
//ACCELEROMETER LOGIC
public function ratmove():void
{
var sen : Accelerometer = new Accelerometer();
sen.addEventListener(AccelerometerEvent.UPDATE, update);
sen.setRequestedUpdateInterval(4);
}
public function update(event:AccelerometerEvent):void
{
//trace(rat.x);
//trace(rat.y);
rat.x -=(event.accelerationX*2);
//rat.y +=(event.accelerationY*2);
if (rat.x < 20)
{
rat.x = 20;
}
else if (rat.x>stage.stageWidth-20)
{
rat.x = stage.stageWidth - 20;
}
}
}
}
We have a xamarin android app that contains a httplistener that serves up html, js, css and json calls, to a single page app running in a full screen webview. As of Xamarin 3.5 onwards the webview fails to retrieve this localhost address which we run on port 31316. Prior to this release this was functioning correctly.
From what i can see, the httplistener seems healthy, as we can call it with the WebRequest library correctly, which leads me tb believe that something has changed to the webview.
Any assistance would be greatly appreciated.
Below is a sample app demonstrating the behaviour:
using System;
using System.Net;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Webkit;
using Android.Widget;
using System.IO;
using System.Text;
namespace HttpListenerTest
{
[Activity (Label = "HttpListenerTest", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
StartService(new Intent(this, typeof(HttpListenerTestService)));
var webView = (WebView)this.FindViewById<WebView>(Resource.Id.webview);
webView.Settings.AllowFileAccess = true;
webView.Settings.BlockNetworkLoads = false;
webView.LoadUrl("http://localhost:31316/");
//webView.LoadData (Activities.html, "text/html", "UTF-8");
var button = FindViewById<Button>(Resource.Id.button1);
button.Click += delegate
{
AlertDialog.Builder alert1;
alert1 = new AlertDialog.Builder(this);
try
{
if(!Activities.httpListener.IsListening)
{
alert1.SetMessage("Listener has stopped listening");
alert1.Show();
return;
}
string url = "http://localhost:31316/" + DateTime.Now.ToString("O");
var request = (HttpWebRequest)WebRequest.Create(new Uri(url));
request.Method = "GET";
string responseString = "";
using (WebResponse response = request.GetResponse())
{
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
responseString = reader.ReadToEnd();
response.Close();
reader.Close();
}
alert1.SetMessage(responseString);
}
catch (Exception e)
{
alert1.SetMessage(e.Message + " " + e.StackTrace);
}
alert1.Show();
};
}
}
[Service(Label = "HttpListenerTest Service")]
public class HttpListenerTestService : Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnCreate()
{
base.OnCreate();
Activities.InitRest();
}
public override void OnDestroy()
{
}
public override void OnStart(Intent intent, int startId)
{
base.OnStart(intent, startId);
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
}
}
public static class Activities
{
public static HttpListener httpListener { get; set; }
public static Thread RestThread { get; set; }
public const string html = "<html>hello world</html>";
public static void InitRest()
{
RestThread = new Thread(StartRest) { Name = "Rest Service" };
RestThread.Start();
}
private static void StartRest()
{
httpListener = new HttpListener { IgnoreWriteExceptions = true };
httpListener.Prefixes.Add(#"http://localhost:31316/");
httpListener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
httpListener.Start();
httpListener.BeginGetContext(HandleRequest, httpListener);
}
public static void HandleRequest(IAsyncResult result)
{
Console.WriteLine ("==========================HandleRequest==========================");
var context = httpListener.EndGetContext(result);
var unescapedUrl = Uri.UnescapeDataString(context.Request.RawUrl);
var bytes = new byte[html.Length * sizeof(char)];
Buffer.BlockCopy(html.ToCharArray(), 0, bytes, 0, bytes.Length);
context.Response.ContentLength64 = bytes.Length;
context.Response.OutputStream.Write(bytes, 0, bytes.Length);
context.Response.ContentType = "text/html";
//context.Response.ContentEncoding = "UTF-8";
context.Response.OutputStream.Close();
context.Response.OutputStream.Dispose();
context.Response.StatusCode = 200;
httpListener.BeginGetContext(HandleRequest, httpListener);
}
}
}
My goal is to have an AsyncTask that
can execute multiple times (one task at a time of course)
its current task can be cancelled
can be used by any activity
can execute many different tasks
does not have any problem with screen rotation (or phonecalls etc)
To achieve that i have created the classes shown below. But my experience with (and understanding of) threads is very limited. And since i don't know of any way to debug multiple threads, there is no way (for me) of knowing if this is going to work or not. So what i'm really asking is: Is this code ok?
And since there is no code that it is currently using this, here's an example use for it:
Data2Get d2g = new Data2Get(this, Data2Get.OpCountNumbers);
d2g.setParam("up2Num", String.valueOf(800));
LongOpsRunner.getLongOpsRunner().runOp(d2g);
So, here we go. This is the interface that every activity that wants to execute a long task (operation - op) should implement:
public interface LongOpsActivity {
public void onTaskCompleted(OpResult result);
}
This is a class to enclose any result of any task:
public class OpResult {
public LongOpsActivity forActivity;
public int opType;
public Object result;
public OpResult(LongOpsActivity forActivity, int opType, Object result){
this.forActivity = forActivity;
this.opType = opType;
this.result = result;
}
}
And finally the big part, the singleton async task class:
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import android.os.AsyncTask;
public class LongOpsRunner extends AsyncTask<Void, OpResult, Void> {
public class Data2Get implements Cloneable {
// one id for each operation
public static final int OpCountNumbers = 1;
public static final int OpCountLetters = 2;
public LongOpsActivity forActivity;
public int opType;
private HashMap<String, String> params = new HashMap<String, String>();
public Data2Get(LongOpsActivity forActivity, int opType) {
this.forActivity = forActivity;
this.opType = opType;
}
public void setParam(String key, String value) {
params.put(key, value);
}
public String getParam(String key) {
return params.get(key);
}
public void clearParams() {
params.clear();
}
#Override
protected Object clone() throws CloneNotSupportedException {
// deep clone
Data2Get myClone = (Data2Get) super.clone();
myClone.clearParams();
for (Entry<String, String> entry : params.entrySet()) {
myClone.setParam(new String(entry.getKey()), new String(entry.getValue()));
}
return myClone;
}
}
private class IntermediateResult extends OpResult {
public IntermediateResult(LongOpsActivity forActivity, int opType, Object result) {
super(forActivity, opType, result);
}
}
// not really needed
private class FinalResult extends OpResult {
public FinalResult(LongOpsActivity forActivity, int opType, Object result) {
super(forActivity, opType, result);
}
}
private final ReentrantLock lock = new ReentrantLock();
private final Condition executeOp = lock.newCondition();
private volatile boolean finished = false;
private volatile boolean waiting = true;
private volatile boolean shouldCancel = false;
private volatile boolean activityHasBeenNotified = true;
private Data2Get startingOpParams = null;
private Data2Get currentOpParams = null;
private FinalResult currentOpResult;
protected Void doInBackground(Void... nothing) {
try {
lock.lockInterruptibly();
do {
waiting = true;
while (waiting) {
executeOp.await();
}
shouldCancel = false;
activityHasBeenNotified = false;
boolean opCancelled = false;
try {
currentOpParams = (Data2Get) startingOpParams.clone();
} catch (CloneNotSupportedException cns) {
// do nothing
}
switch (currentOpParams.opType) {
case Data2Get.OpCountNumbers:
int numberCounter = 0;
int numLoopCount = 0;
while ((!opCancelled) & (numLoopCount <= 5000000)) {
if (!shouldCancel) {
numberCounter = (numberCounter + 1)
% Integer.parseInt(currentOpParams.getParam("up2Num"));
if (numberCounter == 0) {
numLoopCount++;
publishProgress(new IntermediateResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Numbers loop count:" + numLoopCount));
}
} else {
opCancelled = true;
activityHasBeenNotified = true;
}
if (!opCancelled) {
currentOpResult = new FinalResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Numbers loop completed.");
publishProgress(currentOpResult);
}
}
break;
case Data2Get.OpCountLetters:
int letterLoopCount = 0;
char ch = 'a';
while (!opCancelled & (letterLoopCount <= 5000000)) {
if (!shouldCancel) {
ch++;
if (Character.toString(ch).equals(currentOpParams.getParam("up2Letter"))) {
ch = 'a';
letterLoopCount++;
publishProgress(new IntermediateResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Letters loop count:" + letterLoopCount));
}
} else {
opCancelled = true;
activityHasBeenNotified = true;
}
if (!opCancelled) {
currentOpResult = new FinalResult(
currentOpParams.forActivity,
currentOpParams.opType,
"Letters loop completed.");
publishProgress(currentOpResult);
}
}
break;
default:
}
} while (!finished);
lock.unlock();
} catch (InterruptedException e) {
// do nothing
}
return null;
}
public void cancelCurrentOp() {
shouldCancel = true;
}
#Override
protected void onProgressUpdate(OpResult... res) {
OpResult result = res[0];
if (result instanceof IntermediateResult) {
// normal progress update
// use result.forActivity to show something in the activity
} else {
notifyActivityOpCompleted(result);
}
}
public boolean currentOpIsFinished() {
return waiting;
}
public void runOp(Data2Get d2g) {
// Call this to run an operation
// Should check first currentOpIsFinished() most of the times
startingOpParams = d2g;
waiting = false;
executeOp.signal();
}
public void terminateAsyncTask() {
// The task will only finish when we call this method
finished = true;
lock.unlock(); // won't this throw an exception?
}
protected void onCancelled() {
// Make sure we clean up if the task is killed
terminateAsyncTask();
}
// if phone is rotated, use setActivity(null) inside
// onRetainNonConfigurationInstance()
// and setActivity(this) inside the constructor
// and all that only if there is an operation still running
public void setActivity(LongOpsActivity activity) {
currentOpParams.forActivity = activity;
if (currentOpIsFinished() & (!activityHasBeenNotified)) {
notifyActivityOpCompleted(currentOpResult);
}
}
private void notifyActivityOpCompleted(OpResult result) {
if (currentOpParams.forActivity != null) {
currentOpParams.forActivity.onTaskCompleted(result);
activityHasBeenNotified = true;
}
}
private static LongOpsRunner ref;
private LongOpsRunner() {
this.execute();
}
public static synchronized LongOpsRunner getLongOpsRunner() {
if (ref == null)
ref = new LongOpsRunner();
return ref;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
I hope someone helps with making this work, as it would be very useful not only for me, but many other people out there. Thank you.
Try Loaders. I switched from simple AsyncTasks to AsyncTaskLoaders and they solve lots of problems. If you implement a Loader as a standalone class, it would meet all of your requirements, especially when it comes to rotation which is the biggest issue with old AsyncTask.