I am making an app which consists of an activity and a service. By pressing a button the service is started, it collects data in the background from a sensor and classifies it and outputs a string. I want to display the string in a textView. Right now I can see in the log that the variable is updated 2 times every second, but when I try and update the textView from the service class nothing is happening unless I press the button, whenever I press the button, the string is displayed in the textView.
What is the easiest solution here? I tried to make the textView static and it still can't update it. Can you make it so that the view is updated automatically every second? Can I add a listener somehow? Since I am not very experienced I would like an easy solution that does not have to be a "good" one.
Here is my code
Activity:
public class CollectorActivity extends Activity {
private enum State {
IDLE, COLLECTING, TRAINING, CLASSIFYING
};
private final String[] mLabels = { Globals.CLASS_LABEL_STANDING,
Globals.CLASS_LABEL_WALKING, Globals.CLASS_LABEL_RUNNING,
Globals.CLASS_LABEL_OTHER };
private RadioGroup radioGroup;
private final RadioButton[] radioBtns = new RadioButton[4];
private Intent mServiceIntent;
private File mFeatureFile;
public static TextView mCurrentLabel;
private State mState;
private Button btnDelete;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
radioGroup = (RadioGroup) findViewById(R.id.radioGroupLabels);
radioBtns[0] = (RadioButton) findViewById(R.id.radioStanding);
radioBtns[1] = (RadioButton) findViewById(R.id.radioWalking);
radioBtns[2] = (RadioButton) findViewById(R.id.radioRunning);
radioBtns[3] = (RadioButton) findViewById(R.id.radioOther);
btnDelete = (Button) findViewById(R.id.btnDeleteData);
mCurrentLabel = (TextView) findViewById(R.id.textView);
mState = State.IDLE;
mFeatureFile = new File(getExternalFilesDir(null),
Globals.FEATURE_FILE_NAME);
mServiceIntent = new Intent(this, SensorsService.class);
}
public void onCollectClicked(View view) {
if (mState == State.IDLE) {
mState = State.COLLECTING;
((Button) view).setText(R.string.ui_collector_button_stop_title);
btnDelete.setEnabled(false);
radioBtns[0].setEnabled(false);
radioBtns[1].setEnabled(false);
radioBtns[2].setEnabled(false);
radioBtns[3].setEnabled(false);
int acvitivtyId = radioGroup.indexOfChild(findViewById(radioGroup
.getCheckedRadioButtonId()));
String label = mLabels[acvitivtyId];
Bundle extras = new Bundle();
extras.putString(Globals.CLASS_LABEL_KEY, label);
mServiceIntent.putExtras(extras);
startService(mServiceIntent);
} else if (mState == State.COLLECTING) {
mState = State.IDLE;
((Button) view).setText(R.string.ui_collector_button_start_title);
btnDelete.setEnabled(true);
radioBtns[0].setEnabled(true);
radioBtns[1].setEnabled(true);
radioBtns[2].setEnabled(true);
radioBtns[3].setEnabled(true);
stopService(mServiceIntent);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancelAll();
}
}
public void onDeleteDataClicked(View view) {
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
if (mFeatureFile.exists()) {
mFeatureFile.delete();
}
Toast.makeText(getApplicationContext(),
R.string.ui_collector_toast_file_deleted,
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onBackPressed() {
if (mState == State.TRAINING) {
return;
} else if (mState == State.COLLECTING || mState == State.CLASSIFYING) {
stopService(mServiceIntent);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancel(Globals.NOTIFICATION_ID);
}
super.onBackPressed();
}
#Override
public void onDestroy() {
// Stop the service and the notification.
// Need to check whether the mSensorService is null or not.
if (mState == State.TRAINING) {
return;
} else if (mState == State.COLLECTING || mState == State.CLASSIFYING) {
stopService(mServiceIntent);
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancelAll();
}
finish();
super.onDestroy();
}
And this is the "doInBackground" method in my service class. The line "CollectorActivity.mCurrentLabel.setText(classification);" is the problem. I want this to update the textView continously.
public class OnSensorChangedTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
Instance inst = new DenseInstance(mFeatLen);
inst.setDataset(mDataset);
Instance inst2 = new DenseInstance(65);
int blockSize = 0;
FFT fft = new FFT(Globals.ACCELEROMETER_BLOCK_CAPACITY);
double[] accBlock = new double[Globals.ACCELEROMETER_BLOCK_CAPACITY];
double[] re = accBlock;
double[] im = new double[Globals.ACCELEROMETER_BLOCK_CAPACITY];
double max = Double.MIN_VALUE;
while (true) {
try {
// need to check if the AsyncTask is cancelled or not in the while loop
if (isCancelled () == true)
{
return null;
}
// Dumping buffer
accBlock[blockSize++] = mAccBuffer.take().doubleValue();
if (blockSize == Globals.ACCELEROMETER_BLOCK_CAPACITY) {
blockSize = 0;
testList = new ArrayList<Double>();
// time = System.currentTimeMillis();
max = .0;
for (double val : accBlock) {
if (max < val) {
max = val;
}
}
fft.fft(re, im);
for (int i = 0; i < re.length; i++) {
double mag = Math.sqrt(re[i] * re[i] + im[i]
* im[i]);
inst.setValue(i, mag);
testList.add(i,mag);
im[i] = .0; // Clear the field
}
// Append max after frequency component
inst.setValue(Globals.ACCELEROMETER_BLOCK_CAPACITY, max);
inst2.setValue(Globals.ACCELEROMETER_BLOCK_CAPACITY, max);
testList.add(max);
classificationIndex = WekaClassifier.classify(testList.toArray());
classification = testLabel.get((int) classificationIndex);
CollectorActivity.mCurrentLabel.setText(classification);
inst.setValue(mClassAttribute, mLabel);
mDataset.add(inst);
Log.i("new instance", mDataset.size() + "");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
In doInBackground(Void... arg0) change CollectorActivity.mCurrentLabel.setText(classification); to publishProgress(classification); then change second argument from Void to String: public class OnSensorChangedTask extends AsyncTask<Void, Srting, Void> and add onProgressUpdate().
Finally your code should looks like:
public class OnSensorChangedTask extends AsyncTask<Void, Srting, Void> {
#Override
protected Void doInBackground(Void... arg0) {
//...
publishProgress(classification);
//...
}
#Override
protected Void onProgressUpdate(String... classification) {
CollectorActivity.mCurrentLabel.setText(classification[0]);
}
Related
Probably you want to jump to Update 2 and check the code if needed
I am building a barcode scanner and having difficulty in passing data that I have captured from an inner class that extends BroadcastReceiver to MainActivity class, I do understand the difference between static and non static objects, but I got stuck.
Cant invoke my logic method from the inner class.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
protected void onCreate(Bundle savedInstanceState){...}
public void Logic(String result){// Do something...}
//Inner Class
public static class ScanResultReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {...
// data here captured fine!
// Here I want to send my data to MainActivity Logic(result)
Logic(result);
}
}
If I make "Logic()" as Static method, I get a lot of errors regards to calling non static from static method from Toaster/variables..etc
Update
This method is inside MainActivity, I do want to call it from the inner class
public void Logic(String result) throws Exception {
//prepare the results
if (mDecodeResult.decodeValue.substring(0, 1).equals("{") && mDecodeResult.decodeValue.substring(mDecodeResult.decodeValue.length() - 1).equals("}")) {
if (!(mDecodeResult.decodeValue.equals("SCAN AGAIN"))) {
mDecodeResult.decodeValue = mDecodeResult.decodeValue.substring(1);
mDecodeResult.decodeValue = mDecodeResult.decodeValue.substring(0, mDecodeResult.decodeValue.length() - 1);
}
}
if (mDecodeResult.decodeValue.equals("SCAN AGAIN")) {
Toast toast = Toast.makeText(getApplicationContext(),
"No scan data received! Please Scan Again", Toast.LENGTH_SHORT);
toast.show();
} else if (mDecodeResult.decodeValue != null && tourFlag) {
String formattedDate = getTime();
String scanContent = mDecodeResult.decodeValue;
boolean found = false;
if (ForcedOrRandom.equals("Random")) {
String[] b;
for (String l : ToBeScanned) {
b = l.split(":");
if (scanContent.equals(b[0])) {
Log.d("remove", "scanned: " + scanContent);
Log.d("remove", "remove : " + b[0]);
found = true;
}
}
} else if (ForcedOrRandom.equals("Forced")) {
String[] b;
for (String I : FTobeScannedNext) {
b = I.split(":");
if (scanContent.equals(b[0])) {
Log.d("remove", "scanned: " + scanContent);
Log.d("remove", "remove : " + b[0]);
found = true;
}
}
}// end Skip/Forced
if (listLoaded && found) {
theResult[resultCount].setTourID(currentTourId);
theResult[resultCount].setBarcode(scanContent);
BarcodeObject a = getBarcodeInfo(scanContent);
if (ForcedOrRandom.equals("Random")) {
} else {
if (myTimer != null) {
myTimer.cancel();
Timer = (TextView) findViewById(R.id.timertext);
Timer.setText("");
PlayOrPause.setVisibility(View.INVISIBLE);
}
boolean isTimed = a.getForceNextBarCode().equals("");
if (!(isTimed)) {
PlayOrPause = (ImageButton) findViewById(R.id.PlayPause);
PlayOrPause.setVisibility(View.VISIBLE);
PlayOrPause.setImageResource(R.drawable.pause);
final AlertDialog.Builder timealert = new AlertDialog.Builder(this);
PlayOrPause.setEnabled(true);
long duration = Integer.parseInt(a.getForceNextBarCode());
duration = duration * 60000;
myTimer = new CountDownTimer(duration, 1000) {
#Override
public void onTick(long millisuntilFinished) {
int seconds = (int) (millisuntilFinished / 1000) % 60;
int minutes = (int) ((millisuntilFinished / (1000 * 60)) % 60);
Timer = (TextView) findViewById(R.id.timertext);
Timer.setText(minutes + ":" + seconds);
timeLeft = millisuntilFinished;
}
String value = "";
#Override
public void onFinish() {
Timer = (TextView) findViewById(R.id.timertext);
theResult[resultCount].setScanstatus(scanStatusTimeElapsed);
timealert.setTitle("Site Secure");
timealert.setMessage("Time Elapsed! Enter reason");
// Set an EditText view to get user input
final EditText input = new EditText(MainActivity.this);
timealert.setView(input);
timealert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
value = input.getText().toString();
// Do something with value!
while (value.equals("")) {
timealert.setView(input);
timealert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
value = input.getText().toString();
}
});
}
theResult[resultCount].setComments(value);
}
});
timealert.setIcon(android.R.drawable.ic_dialog_alert);
timealert.show();
Timer.setText(R.string.Time_Elapsed);
}
};
myTimer.start();
}
}
theResult[resultCount].setBarcodeID(a.getBarCodeId());
theResult[resultCount].setDateScanned(formattedDate);
theResult[resultCount].setSkipped(getResources().getString(R.string.Scanned));
}// end big if listLoaded && found
contentTxt.setText(scanContent);
Toaster(getResources().getString(R.string.TScan_Complete));
if (mainScanCounter == 0) {
if (tourDecider(scanContent)) {//tour decider is called to determine if this is boolJanamScanner random or forced tour
tourId = scanContent;
if (!(readFileOffline(siteSecurePath + "/doneTourNumber.txt").equals(""))) {
SYNC.setEnabled(true);
}
}
} else if (mainScanCounter > 0) {
if (ForcedOrRandom.equals("Random")) {
ListManager(scanContent);
} else {
ForcedListManager(scanContent);
}
}
} else if (mDecodeResult.decodeValue != null && officerScanFlag) {
TextView officertextview = (TextView) findViewById(R.id.officerid);
UserObject theofficer = getUserInfo(mDecodeResult.decodeValue);
if (theofficer == null) {
popUps("Error", "Invalid Officer ID, Please Rescan", "TITLE");
officerScan.setEnabled(true);
} else if (theofficer != null) {
// officer ID found need to store it for backup
officerId = theofficer.getOfficerid();
makeFileOffline(officerId, "officerID");
officertextview.setText(theofficer.getUsername());
officerScanFlag = false;
startTimersOfficerID = getTime();
tourBtn.setEnabled(true);
}
}
if (mDecodeResult.decodeValue != null && exceptionFlag) {
Log.d("check", "exception was clicked");
String ex_result = mDecodeResult.decodeValue;
for (int i = 0; i < theExceptions.length; i++) {
if (!(theExceptions[i].getBarcode().equals(ex_result))) {
String refnum = theExceptions[i].getRefNum();
i = theExceptions.length;
theResult[resultCount - 1].setException(refnum);
}
}
exceptionFlag = false;
Toaster(getResources().getString(R.string.TScan_Complete));
}
} // Logic Ends
Update 2
Not sure if I need to have another thread for this but I will put what I have found, my issue have narrowed to the following:
I am waiting on an intent called
<action android:name="device.scanner.USERMSG" />
with a permission
android:permission="com.permission.SCANNER_RESULT_RECEIVER"
now my issue
if a user tap button and released in less than .5 second onKeyup() event will be fired before my onReceive() that is inside the static class which is extends BroadcastReceiver, and that causes problem because Logic() will be invoked before updating the String inside onReceive()
if user hold the button long enough, onReceive will be invoked and everything is good and happy.
How can I make sure that onReceive() always invoked first?
public boolean onKeyUp(int keycode, KeyEvent event) {
if (keycode == 221 || keycode == 220 || keycode == 222) {
Logic(result);
}
return true;
}
Move this line of code:
public void Logic(String result){// Do something...}
inside your class ScanResultReceiver and it will work for sure. Your code should look like this:
public static class ScanResultReceiver extends BroadcastReceiver {
public ScanResultReceiver() {
//empty constructor
}
#Override
public void onReceive(Context context, Intent intent) {...
// data here captured fine!
// Here I want to send my data to MainActivity Logic(result)
Logic(result);
}
public void Logic(String result){/* ... */}
}
I implemented AsyncTask to execute results. Here is the error I get...
FATAL EXCEPTION: AsyncTask #1
Process: ai69.psoui, PID: 3287
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.app.Activity.<init>(Activity.java:754)
at android.support.v4.app.SupportActivity.<init>(SupportActivity.java:31)
at android.support.v4.app.BaseFragmentActivityGingerbread.<init>(BaseFragmentActivityGingerbread.java:37)
at android.support.v4.app.BaseFragmentActivityHoneycomb.<init>(BaseFragmentActivityHoneycomb.java:29)
at android.support.v4.app.BaseFragmentActivityJB.<init>(BaseFragmentActivityJB.java:30)
at android.support.v4.app.FragmentActivity.<init>(FragmentActivity.java:79)
at android.support.v7.app.AppCompatActivity.<init>(AppCompatActivity.java:61)
at ai69.psoui.MainActivity.<init>(MainActivity.java:0)
at android_tests.CustomUseCase.<init>(CustomUseCase.java:19)
at android_tests.TestFactory.getTest(TestFactory.java:15)
at ai69.psoui.ParticleActivity.runTest(ParticleActivity.java:91)
at ai69.psoui.ParticleActivity$runTests.doInBackground(ParticleActivity.java:53)
at ai69.psoui.ParticleActivity$runTests.doInBackground(ParticleActivity.java:50)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
I have looked at different SOF posts about "Looper.prepare()" but the thing is, prior to a few changes in changing static variables to getter/setter methods, my UI was working fine.
Here is my code...
public class ParticleActivity extends AppCompatActivity {
public final static String EXTRA_MESSAGE = "PSOUI.MESSAGE";
private ProgressDialog pd;
private double[] results = {-1.0, -1.0, -1.0};
EditText particles;
EditText iterations;
EditText userSol;
EditText userBatt;
private double battery;
private double solution;
//int numberOfDimensions = MainActivity.dimensions.size();
//public ArrayList<Double> costData = MainActivity.costDATA; //costs that
the user enters for each resource
//public ArrayList<Double> costWlan = MainActivity.costWLAN;
//public ArrayList<Double> costUtilities = MainActivity.costUTILITY;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_particle);
particles = (EditText) findViewById(R.id.particles);
iterations = (EditText) findViewById(R.id.iterations);
userSol = (EditText) findViewById(R.id.solution);
userBatt = (EditText) findViewById(R.id.battery);
pd = null;
runPSOButton();
}
#Override
public void onPause(){
super.onPause();
if(pd != null)
pd.dismiss();
}
public class runTests extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) { //sort this out
results = runTest("CustomUseCase"); //i only want to run this one!!!
return null;
}
#Override
protected void onPostExecute(Void v) {
if (results != null && results.length > 0 && results[0] != -1) {
loadIntent(results);
} //otherwise it will evaluate the next logic statement results[0] != -1 with no chance of NulLPointerException
}
#Override
protected void onPreExecute() {
pd = ProgressDialog.show(ParticleActivity.this, "Busy", "Algorithm is currently executing");
pd.setCancelable(true);
pd.show();
}
}
public void runPSOButton() {
final Button runPSO = (Button) findViewById(R.id.runpso);
runPSO.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
new runTests().execute();
}
});
}
public double[] runTest(String test) {
int noPart = Integer.parseInt(particles.getText().toString());
int noIter = Integer.parseInt(iterations.getText().toString());
return new TestFactory(noPart, noIter).getTest(test).test();
}
public void loadIntent(double[] result) {
double[] results = result;
Intent intent = new Intent(this, SolutionActivity.class);
intent.putExtra(EXTRA_MESSAGE, results);
startActivity(intent);
}
public double setBatteryCost(){
battery = Double.parseDouble(userBatt.getText().toString());
return battery;
}
public double getBatteryCost(){return setBatteryCost();}
public double setUserSolution(){
solution = Double.parseDouble(userSol.getText().toString());
return solution;
}
public double getUserSolution(){return setUserSolution();}
}
Can someone explain whats happening? New to Android Studio and have been developing for only 3 months in Java, so for any solutions can I kindly request an explanation for it too? Much appreciated thank you
UPDATE:
Here is my mainActivity...
public class MainActivity extends AppCompatActivity {
//declare variables
EditText name;
EditText data;
EditText wlan;
EditText utility;
Button addservice;
ListView lv;
ListView lv2;
ListView lv3;
ListView lv4;
public ArrayList<String> servicenames;
public ArrayList<String> dimensions;
public ArrayList<Double> costDATA;
public ArrayList<Double> costWLAN;
public ArrayList<Double> costUTILITY;
ArrayAdapter<String> namesAdapter;
ArrayAdapter<Double> dataAdapter;
ArrayAdapter<Double> wlanAdapter;
ArrayAdapter<Double> utilityAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//map the components to the variables
name = (EditText) findViewById(R.id.servicename);
data = (EditText) findViewById(R.id.data);
wlan = (EditText) findViewById(R.id.wlan);
utility = (EditText) findViewById(R.id.utility);
addservice = (Button) findViewById(R.id.addservice);
lv = (ListView) findViewById(R.id.lv);
lv2 = (ListView) findViewById(R.id.lv2);
lv3 = (ListView) findViewById(R.id.lv3);
lv4 = (ListView) findViewById(R.id.lv4);
//create arraylists for each component
servicenames = new ArrayList<String>();
dimensions = new ArrayList<String>();
costDATA = new ArrayList<Double>();
costWLAN = new ArrayList<Double>();
costUTILITY = new ArrayList<Double>();
//create adapters to pass on the arraylist
namesAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, servicenames);
dataAdapter = new ArrayAdapter<Double>(MainActivity.this, android.R.layout.simple_list_item_1, costDATA);
wlanAdapter = new ArrayAdapter<Double>(MainActivity.this, android.R.layout.simple_list_item_1, costWLAN);
utilityAdapter = new ArrayAdapter<Double>(MainActivity.this, android.R.layout.simple_list_item_1, costUTILITY);
//display each arraylist in the listviews
lv.setAdapter(namesAdapter);
lv2.setAdapter(wlanAdapter);
lv3.setAdapter(dataAdapter);
lv4.setAdapter(utilityAdapter);
namesAdapter.notifyDataSetChanged();
dataAdapter.notifyDataSetChanged();
wlanAdapter.notifyDataSetChanged();
utilityAdapter.notifyDataSetChanged();
dimensions.add("DATA");
dimensions.add("WLAN");
onClickBtn();
}
public void onClickBtn() { //when user clicks button, the user input is added to the listview, and cleared for the next service
addservice.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String namesOfService = name.getText().toString(); //user input for service names
String costOfData = data.getText().toString(); //user input for data costs
String costOfWLAN = wlan.getText().toString(); //user input for wlan costs
String costOfUtility = utility.getText().toString(); //user input for utility costs
Double doubleWLAN = Double.parseDouble(costOfWLAN); //convert user input into double
Double doubleData = Double.parseDouble(costOfData);
Double doubleUtility = Double.parseDouble(costOfUtility);
costDATA.add(doubleData); //add the double costs to each resource arraylist
costWLAN.add(doubleWLAN);
costUTILITY.add(doubleUtility);
servicenames.add(namesOfService);
dimensions.add(namesOfService);
namesAdapter.notifyDataSetChanged();
dataAdapter.notifyDataSetChanged();
wlanAdapter.notifyDataSetChanged();
utilityAdapter.notifyDataSetChanged();
name.setText(""); //empty the edit text fields when button is clicked
wlan.setText("");
data.setText("");
utility.setText("");
}
});
}
public void nextButton(View view) //next button, onto the next activity
{
Intent intent = new Intent(MainActivity.this, ParticleActivity.class);
startActivity(intent);
}
public int getDimensions(){ return dimensions.size();}
public ArrayList<String> getElements(){ return servicenames;}
public ArrayList<Double> getCostDATA(){;return costDATA;}
public ArrayList<Double> getCostWLAN(){return costUTILITY;}
public ArrayList<Double> getCostUTILITY(){return costUTILITY;}
}
As you can see, the arraylists that store the user input is accessible using getters and setters rather than setting the arraylists static (which I did before). I access these arraylists in another class called CustomUseCase and CustomService. Here is the code for customUseCase:
public class CustomUseCase extends Test {
MainActivity mainActivity = new MainActivity();
ParticleActivity particleActivity = new ParticleActivity();
private int numberOfDimensions = mainActivity.getDimensions();
private ArrayList<Double> costData = mainActivity.getCostDATA(); //costs that the user enters for each resource
private ArrayList<Double> costWlan = mainActivity.getCostWLAN();
private ArrayList<Double> costUtilities = mainActivity.getCostUTILITY();
private double batteryCost = particleActivity.getBatteryCost();
private int maxIter;
private int noParticles;
public CustomUseCase(int noParticles, int maxIterations) {
this.noParticles = noParticles;
this.maxIter = maxIterations;
}
#Override
public double[] test() {
long max = 10000; //maximum number of iterations, override //2 bits for the WLAN/DATA and the rest for the amount of services the user inputs
double[] results = new double[numberOfDimensions]; //new array of results with numOfBits as number of elements
for (int i = 1; i <= max; i++) {
BinaryPso bpso = new BinaryPso(noParticles,
numberOfDimensions);
ParticleActivity getUserInput = new ParticleActivity();
CustomService customService =
new CustomService(batteryCost, costData, costWlan, costUtilities);
long start = System.currentTimeMillis(); //start time
bpso.setSolution(getUserInput.getUserSolution()); //changed this to user selection
bpso.optimize(maxIter, customService, true);
this.found += (bpso.getFound() ? 1 : 0);
this.iterations += bpso.getSolIterations(); //use the method in bpso to get number of iterations taken
long end = System.currentTimeMillis() - start; //end time minus start time
this.sumTimes += end; //override the time spent variable
System.out.println("P-value: " + Particle.getValue(Particle.bestGlobal()));
System.out.println("P-bitCombo: " + Arrays.toString(Particle.bestGlobal()));
System.out.println("P-goodness: " + customService.getGoodness(Particle.bestGlobal()));
}
System.out.println("Time: " + sumTimes / max);
System.out.println("Iterations: " + iterations / max);
System.out.println("Success Rate: " + found);
boolean[] bestCombo = Particle.bestGlobal();
for (Boolean b : bestCombo) {
System.out.print(b + " ");
}
System.out.println();
results[0] = sumTimes / max;
results[1] = iterations / max;
results[2] = found;
return results;
}
public static List<Boolean> getBestComboArray() { //method to get best global array
boolean[] bestCombo = Particle.bestGlobal(); //calculate best global
List<Boolean> bestCombi = new ArrayList<>(bestCombo.length);
for (int x = 0; x < bestCombo.length; x++) {
bestCombi.add(bestCombo[x]);
}
return bestCombi;
}
}
And here is my CustomService class:
public class CustomService implements Goodness {
MainActivity mainActivity = new MainActivity();
private int numOfDimensions = mainActivity.getDimensions();
private ArrayList<String> serviceNames = mainActivity.getElements();
private ArrayList<Double> costData = mainActivity.getCostDATA();
private ArrayList<Double> costWlan = mainActivity.getCostWLAN();
private ArrayList<Double> costUtilities = mainActivity.getCostUTILITY();
private double batteryCost;
public void setBatteryCost(double batteryCost) {
this.batteryCost = batteryCost;
}
public CustomService(double batteryCost, ArrayList<Double> costData, ArrayList<Double> costWlan,
ArrayList<Double> costUtilities) {
if (costUtilities == null || costUtilities.size() < 1 || costData.size() < 1 || costWlan.size() < 1) {
throw new RuntimeException("Please add atleast 1 cost to Data, WLAN and Utility");
}
this.batteryCost = batteryCost; //make sure you add battery field to UI, user enters battery level
this.costData = costData;
this.costWlan = costWlan;
this.costUtilities = costUtilities;
}
public double getGoodness(boolean[] bits) {
double utility = 0.0;
double rcost = 0.0;
ArrayList<Double> resourceCost = new ArrayList<Double>();
Collections.sort(costUtilities); //sort the costUtilities arraylist
double maxValue = Collections.max(costUtilities); //get the maximum value from the costUtilities arraylist
if(bits[0] && bits[1]){
return -500;
}
if(!bits[0] || bits[1]){
return -1000;
}
for(int x = 1; x < numOfDimensions; x++){
if(bits[x] == costUtilities.contains(maxValue)){
return -1900;
}
}
if (bits[0]) {
resourceCost = costData;
} else if (bits[1]) {
resourceCost = costWlan;
}
for (int i = 2; i <= serviceNames.size(); i++) { //if i = 2, 2<=4
if (bits[i]) {
utility += costUtilities.get(i-2);
rcost += resourceCost.get(i-2);
}
}
if (rcost < batteryCost) {
return utility;
}
return utility * 0.50;
}
}
you can not update UI items on nonUIThread.
search usage of runOnUiThread on google.
call your method in runOnUiThread().
#Override
protected Void doInBackground(Void... params) { //sort this out
runOnUiThread (new Runnable() {
public void run() {
results = runTest("CustomUseCase");
}
}
return null;
}
This explains all: "Can't create handler inside thread that has not called Looper.prepare()" and it seems your TestFactory() method creates a Handler without a Looper.
Inside a secondary Thread a Handler should be like this
....
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do work with received messages
}
};
Looper.loop();
....
More info : What is the purpose of Looper and how to use it?
I'm trying to sync a list from the handheld to the wearable. On the phone side, I have a listview and you can add items to it and on the wear side I am just displaying the same list. I'm adding items to /card/id path and adding the array size on /counter. OnDataChanged method does gets called when I add items to the list on phoneside, but when I try to read the items on wearside, it's not working. It gives nullpointer exception when I'm trying to get the connected nodes and therefor I'm not able to read the data. Here's the code and the log snapshot:
Error
04-15 12:41:38.075: E/AndroidRuntime(13791): Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.os.Looper com.google.android.gms.common.api.GoogleApiClient.getLooper()' on a null object reference
Wear side:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDefaultCircleRadius = getResources().getDimension(R.dimen.default_settings_circle_radius);
mSelectedCircleRadius = getResources().getDimension(R.dimen.selected_settings_circle_radius);
cards = new ArrayList<GiftCard>();
new LoadCards().execute();
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
//mTextView = (TextView) stub.findViewById(R.id.count_text);
mListView = (WearableListView) stub.findViewById(R.id.card_list_view);
}
});
mHandler = new Handler();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
// DataItem changed
DataItem item = event.getDataItem();
if (item.getUri().getPath().compareTo(COUNT_PATH) == 0) {
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
final String counter = dataMap.getString(CardUtil.CARD_COUNT);
new LoadCards().execute();
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(c,"Card count: "+ counter,Toast.LENGTH_LONG).show();
//mTextView.setText("COUNTER FROM DATACHANGE METHOD: " + counter);
}
});
}
else if(item.getUri().getPath().compareTo(CARD_PATH) == 0){
}
} else if (event.getType() == DataEvent.TYPE_DELETED) {
// DataItem deleted
}
}
}
public GiftCard loadCardData(int id){
//Uri uri = getIntent().getData().buildUpon().encodedPath("/card").appendPath(String.valueOf(id)).build();
Uri uri = getUriForDataItem("/counter");
Log.d("URI", uri.getPath());
DataApi.DataItemResult result = Wearable.DataApi.getDataItem(mGoogleApiClient,uri).await();
DataMapItem item = DataMapItem.fromDataItem(result.getDataItem());
Asset cardImageAsset = item.getDataMap().getAsset(CardUtil.CARD_IMAGE);
//Asset barcodeImageAsset = item.getDataMap().getAsset(CardUtil.BARCODE_IMAGE);
String card_type = item.getDataMap().getString(CardUtil.CARD_TYPE);
Bitmap cardImage = BitmapFactory.decodeStream(Wearable.DataApi.getFdForAsset(mGoogleApiClient, cardImageAsset).await().getInputStream());
// Bitmap barcodeImage = BitmapFactory.decodeStream(Wearable.DataApi.getFdForAsset(mGoogleApiClient,barcodeImageAsset).await().getInputStream());
GiftCard card = new GiftCard();
card.setCardImage(cardImage);
card.setCardName(card_type);
card.setCardID(id);
return card;
}
public class LoadCards extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... arg0) {
// Uri uri = getIntent().getData().buildUpon().encodedPath("/counter").build();
Uri uri = getUriForDataItem("/counter");
Toast.makeText(c,uri.toString(),Toast.LENGTH_LONG).show();
DataApi.DataItemResult result = Wearable.DataApi.getDataItem(mGoogleApiClient,uri).await();
DataMapItem item = DataMapItem.fromDataItem(result.getDataItem());
int card_count = Integer.parseInt(item.getDataMap().getString(CardUtil.CARD_COUNT));
// int card_count = Integer.parseInt(loadCardCounter());
if(card_count <= 0){
Toast.makeText(c,"No cards available to show!",Toast.LENGTH_LONG).show();
} else {
for (int i = 1; i <= card_count; i++) {
GiftCard c = loadCardData(i);
cards.add(c);
}
}
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
//update the card list
mAdapter = new CardListAdapter(c,cards);
mListView.setAdapter(mAdapter);
// mListView.setClickListener();
}
}
private Uri getUriForDataItem(String path) {
String nodeId = getNodeId();
return new Uri.Builder().scheme(PutDataRequest.WEAR_URI_SCHEME).authority(nodeId).path(path).build();
}
private String getNodeId() {
NodeApi.GetConnectedNodesResult nodesResult = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
List<Node> nodes = nodesResult.getNodes();
if (nodes.size() > 0) {
return nodes.get(0).getId();
} else {
Toast.makeText(c,"NO NODES AVAILABLE",Toast.LENGTH_LONG).show();
}
return null;
}}
From the stacktrace it's pretty obvious that you are trying to use Wearable DataAPI from the thread without Looper - in doInBackground() method I believe. That is why it crashes.
Move this code directly into onDataChanged() method and it should solve the issue.
So, I am creating a little trivia game for learning purposes, but I ran into a problem.
First, I had a specific Android Fragment obtaining the data from JSON, and I will simply use that data on the callback method and display it on TextViews and Buttons. Everything was working fine, however, every time I returned to that fragment, the same questions would be there. So I decided to handle that in a better way outside of the callback method.
The problem here is that apparently my Arrays are either null or their lengths is zero. Which is weird, because according to my LOG, data is being passed to those arrays on the callback method.
Here's my full fragment code. Thanks!
public class GameFragment extends Fragment {
private TextView txtQuestion;
private Button btnAnswer1;
private Button btnAnswer2;
private Button btnAnswer3;
private Button btnAnswer4;
private Questions[] gameQuestions;
private Questions[] animeQuestions;
private Questions[] techQuestions;
private Questions[] movieQuestions;
private Questions[][] gameCategories = new Questions[4][];
int correctAnswer = -1;
private TransparentProgressDialog progressBar;
private Handler handler;
private Runnable runnable;
Callback cb = new Callback<MyApiData>(){
#Override
public void success(MyApiData myApiData, Response response) {
gameCategories[0] = new Questions[myApiData.getCategory()[0].getQuestions(0).length];
gameCategories[1] = new Questions[myApiData.getCategory()[1].getQuestions(1).length];
gameCategories[2] = new Questions[myApiData.getCategory()[2].getQuestions(2).length];
gameCategories[3] = new Questions[myApiData.getCategory()[3].getQuestions(3).length];
//gameCategories = new Questions[][] {gameQuestions, animeQuestions, techQuestions, movieQuestions};
for(int i = 0; i < 4 ; i++){
for(int j = 0; j < gameCategories[i].length ; j++){
gameCategories[i][j] = myApiData.getCategory()[i].getQuestions(i)[j];
//Log.d("GameFragment", "gameCategories[i][j] - gameCategories["+i+"]["+j+"]: " + gameCategories[i][j].getQuestion());
}
}
//displayQuestion();
progressBar.dismiss();
displayQuestion();
}
#Override
public void failure(RetrofitError error) {
Log.d("GameScreen", "Callback failed!");
}
};
public GameFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_game, container, false);
txtQuestion = (TextView) view.findViewById(R.id.txtQuestion);
btnAnswer1 = (Button) view.findViewById(R.id.btnAnswer1);
btnAnswer2 = (Button) view.findViewById(R.id.btnAnswer2);
btnAnswer3 = (Button) view.findViewById(R.id.btnAnswer3);
btnAnswer4 = (Button) view.findViewById(R.id.btnAnswer4);
btnAnswer1.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) { checkAnswer(view); } });
btnAnswer2.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) { checkAnswer(view); } });
btnAnswer3.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) { checkAnswer(view); } });
btnAnswer4.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
checkAnswer(view);
}
});
handler = new Handler();
progressBar = new TransparentProgressDialog(getActivity(), R.drawable.loading_spinner);
runnable = new Runnable() {
#Override
public void run() {
if (progressBar.isShowing()) {
progressBar.dismiss();
}
}
};
//launchRingDialog();
//RestClient.get().getQuestions(cb);
// Inflate the layout for this fragment
return view;
}
public void launchRingDialog() {
new Thread(new Runnable() {
public void run(){
try {
Log.d("Thred", "Try");
progressBar.show();
RestClient.get().getQuestions(cb);
//Thread.sleep(10000);
} catch (Exception e) {
}
//progressBar.dismiss();
}
}).start();
}
public void checkAnswer(View v){
switch(v.getId()){
case R.id.btnAnswer1:
if(correctAnswer == 1){
feedback(true, btnAnswer1);
}else {
feedback(false, btnAnswer1);
}
break;
case R.id.btnAnswer2:
if(correctAnswer == 2){
feedback(true, btnAnswer2);
}else {
feedback(false, btnAnswer2);
}
break;
case R.id.btnAnswer3:
if(correctAnswer == 3){
feedback(true, btnAnswer3);
}else {
feedback(false, btnAnswer3);
}
break;
case R.id.btnAnswer4:
if(correctAnswer == 4){
feedback(true, btnAnswer4);
}else {
feedback(false, btnAnswer4);
}
break;
default: txtQuestion.setText("Error");
break;
}
}
public void feedback(Boolean correct, Button btn){
if(correct){
btn.setBackgroundColor(Color.GREEN);
btn.setText("CORRECT!");
}else{
btn.setBackgroundColor(Color.RED);
btn.setText("WRONG!");
}
}
#Override
public void onResume() {
super.onResume();
//displayQuestion();
}
public void displayQuestion(){
Random randomizer = new Random();
int randomQuestion;
int category = GTMain.choosenCategory;
if(category == 5){
category = randomizer.nextInt(4);
}
randomQuestion = randomizer.nextInt(25);
Log.d("displayQuestion", "Before if statements");
if(gameCategories != null && gameCategories.length != 0) {
Log.d("displayQuestion", "First if");
if(gameCategories[category] != null && gameCategories[category].length != 0){
Log.d("displayQuestion", "Second if");
txtQuestion.setText(gameCategories[category][randomQuestion].getQuestion());
correctAnswer = gameCategories[category][randomQuestion].getCorrectAnswer();
Log.d("displayQuestion()", "correctAnswer: " + correctAnswer);
btnAnswer1.setText(gameCategories[category][randomQuestion].getAnswers().getA1());
btnAnswer2.setText(gameCategories[category][randomQuestion].getAnswers().getA2());
btnAnswer3.setText(gameCategories[category][randomQuestion].getAnswers().getA3());
btnAnswer4.setText(gameCategories[category][randomQuestion].getAnswers().getA4());
}
}
}
}
PS: On my main activity, I check to see which fragment should be loaded. If it's the fragment that contains the components to display the questions and answer (the one from the code above), I call the following method: gameFragment.launchRingDialog(); (and yes, I have created an instance of my GameFragment fragment before calling that method!)
When onResume() is called, your RestClient.get().getQuestions(cb) is still running in background, and your call displayQuestion(), so of course nothing is shown.
Can you put displayQuestion() inside success() of your callback?
Callback cb = new Callback<MyApiData>(){
#Override
public void success(MyApiData myApiData, Response response) {
....
for(int i = 0; i < 4 ; i++){
for(int j = 0; j < gameCategories[i].length ; j++){
...
}
}
displayQuestion();
}
....
};
I would also suggest you to remove displayQuestion() in onResume() method.
i have a problem with handler in android, i don't understand not display result, this's code:
public class Main extends Activity implements OnClickListener {
private EditText nhap;
private Button btTinh;
private Button btHuy;
private TextView kq;
private ProgressDialog progress;
private Handler handle = new Handler();
private int count = 0;
private String s = "";
private long n;
handlemessage:
Handler mhandle = new Handler() {
#Override
public void handleMessage(Message msg) {
kq.setText(msg.obj.toString());
}
};
onCreate:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
nhap = (EditText) findViewById(R.id.nhap);
btTinh = (Button) findViewById(R.id.btTinh);
btHuy = (Button) findViewById(R.id.btHuy);
kq = (TextView) findViewById(R.id.kq);
btTinh.setOnClickListener(this);
btHuy.setOnClickListener(this);
}
public boolean checkPrime(long n) {
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0)
return false;
}
return true;
}
outprime:
public void outPrime(long t) {
// String s="";
progress.setCancelable(true);
progress.setMessage("File downloading ...");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setProgress(0);
progress.setMax(Integer.parseInt(nhap.getText().toString()));
progress.show();
n = t;
new Thread() {
public void run() {
for (int i = 2; i < n; i++) {
count = i;
if (checkPrime(i))
s = s + i + " ";
handle.post(new Runnable() {
public void run() {
// TODO Auto-generated method stub
progress.setProgress(count);
}
});
}
if (count == n - 1) {
progress.dismiss();
Message msg = handle.obtainMessage(1, (String)s);
handle.sendMessage(msg);
}
}
}.start();
}
onclick:
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btTinh:
progress = new ProgressDialog(this);
outPrime(Long.parseLong(nhap.getText().toString()));
break;
case R.id.btHuy:
nhap.setText("");
break;
}
}}
this's handlemessage:
Handler mhandle = new Handler() {
#Override
public void handleMessage(Message msg) {
kq.setText(msg.obj.toString());
}
};
i don't understand handlemessage don't return value, "kq.setText(msg.obj.toString());" don't display to screen, sorry because my english not good
I think the answer for your question is "Watch out your variable's names!" Look - you've created 2 Handlers - named "mhandle" and "handle". You want to parse message in Handler named "mhandle", but in your Thread send it to "handle", which is doing nothing from your code.
Hope it will help if you still trying to find the answer.