android java context explanation - java

I have the following question:
I have to use the following function from BT printer SDK:
StarIOPort port = null;
byte[] texttoprint = new byte[]{0x1b, 0x40, 0x1b,0x74,0x0D,(byte) 0x91,(byte) 0x92,(byte) 0x93,(byte) 0x94,(byte) 0x95,(byte) 0x96,(byte) 0x97,(byte) 0x98,(byte) 0x99,0x0A,0x0A,0x0A,0x0A,0x0A};
try
{
port = StarIOPort.getPort(portName, portSettings, 10000, context);
port.writePort(textToPrint, 0, textToPrint.length);
port.writePort(new byte[] {0x0a}, 0, 1);
}
catch (StarIOPortException e)
{
Builder dialog = new AlertDialog.Builder(context);
dialog.setNegativeButton("Ok", null);
AlertDialog alert = dialog.create();
alert.setTitle("Failure");
alert.setMessage("Failed to connect to printer");
alert.show();
}
I have understand everything except of context.
The manufacturer mention that
* #param context - Activity for displaying messages to the user
How can I use the above function because in the way I use it I do not receive any error neither any alert message.

To display Alert (or any other UI component) you need Activity context, that's right. If you do not have any Activity running at the moment, you can't display Alert.
But you can display Toast, using static method of class Toast:
public static Toast makeText(Context context, CharSequence text, int duration);
passing to it Application Context as first parameter.
Application context is always available while your app is running, even if there are no UI running at the moment. You can get it by calling getApplicationContext() method from your context. If you don't have any context at all, you can always use YourAppClass (public class YourAppClass extends Application), defined in your manifest under xml tag.
Most common practice is to make YourAppClass a singleton, and it always be available at any point of code within your app.

The context is your Activity.
private Context context;
context = this;
Here is a complete sample activity.
package com.example.helloworld;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import <my_star_io_library>;
public class HelloWorld extends Activity
{
private Context context;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//Save context
context = this;
StarIOPort port = null;
byte[] texttoprint = new byte[]{0x1b, 0x40, 0x1b,0x74,0x0D,(byte) 0x91,(byte) 0x92,(byte) 0x93,(byte) 0x94,(byte) 0x95,(byte) 0x96,(byte) 0x97,(byte) 0x98,(byte) 0x99,0x0A,0x0A,0x0A,0x0A,0x0A};
try
{
port = StarIOPort.getPort(portName, portSettings, 10000, context);
port.writePort(textToPrint, 0, textToPrint.length);
port.writePort(new byte[] {0x0a}, 0, 1);
}
catch (StarIOPortException e)
{
Builder dialog = new AlertDialog.Builder(context);
dialog.setNegativeButton("Ok", null);
AlertDialog alert = dialog.create();
alert.setTitle("Failure");
alert.setMessage("Failed to connect to printer");
alert.show();
}
}
}

Context is a class related with an Activity,that you use when you have to show and AlertDialog, Toast, get system services... It is related with the arquitecture MVC,which is a bit longer to explain. About using it, there are two ways. One is explained by droidhot and another way is, for example, MainActivity.this, if you are using the AlertDialog in the Main Activity (MainActivity.java file), so the Main Activity will be the one that launches the Alert Dialog. If it is launched from another class which is not an Activity, you have to put the context as a parameter (for example, new Class(MainActivity.this)) and inside the class,it would be, for example, public class( Context context) ant the parameter context is the one you have to use.

Activity is subclass of Context so if you printing code is part of your Activity class, then simply provide this as required context to fulfill SDK requirements:
port = StarIOPort.getPort(portName, portSettings, 10000, this);
and later
Builder dialog = new AlertDialog.Builder(this);

I have posted answer here:
Android Phonegap Plugin different result on virtual and real device (Looper.prepare() ERROR)
I had the same problem which appeared on some devices. Successfully one smart boy, Toby, helped me. So, solution is the next:
- before you call any StarIOPort's methods you have to check if looper exist:
if (Looper.myLooper() == null) {
Looper.prepare();
}
in your case it's will looks like this:
try
{
if (Looper.myLooper() == null) {
Looper.prepare();
}
port = StarIOPort.getPort("BT:", "mini", 10000, null);
try
{
Thread.sleep(500);
}
catch(InterruptedException e) {}
port.writePort(texttoprint, 0, texttoprint.length);
try
{
Thread.sleep(3000);
}
catch(InterruptedException e) {}
resultType = "success";
}
catch (StarIOPortException e)
{
resultType = "error";
}
One more advise:
instead
port = StarIOPort.getPort("BT:", "mini", 10000, null);
use just
port = StarIOPort.getPort("BT:", "mini", 10000);
in plugin you will not use Context
Good luck.

Related

Android: Why won't this code run in onCreate, or how can I make it work without a thread?

I have this piece of code that runs alright when I put it in Eclipse, but for some reason it does not want to execute when I put it in an activity's onCreate method in Android studio.
Here is the code:
public class ItemListView extends AppCompatActivity{
String itemURL;
int listSize;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list_view);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Bundle itemData = getIntent().getExtras();
if(itemData==null){
return;
}
//Gets URL from search bar
itemURL = itemData.getString("itemURL");
try {
Document doc = Jsoup.connect("https://www.amazon.com/s/ref=nb_sb_ss_c_1_6?url=search-alias%3Daps&field-keywords=rx+390&sprefix=rx+390%2Caps%2C166&crid=2MTUBA4KGNY06").get();
String link = doc.select("h2#s-result-count").first().text();
System.out.println(link);
System.out.println(link.substring(1));
if (link.substring(1, 2).equals("-")) {
System.out.println("run1");
listSize = Integer.parseInt(link.substring(2, 3));
System.out.println(listSize);
try {
listSize = Integer.parseInt(link.substring(2, 4));
System.out.println(listSize);
} catch (Exception e) {
}
} else {
System.out.println("run2");
listSize = Integer.parseInt(link.substring(0, 1));
System.out.println(listSize);
try {
listSize = Integer.parseInt(link.substring(0, 2));
System.out.println(listSize);
} catch (Exception e) {
}
}
} catch (Exception e) {
}
System.out.println("listSize: " +listSize);
...
}
}
I need listSize to create a variable array depending on the URL, but when I print the value to make sure it's working it always gives me 0. I have tried running the code in a separate Java Class with AsyncTask and it works, but by the time the code executes in onPostExecute, it's too late since the class above has already tried to initialize the array.
Any advice would be appreciated, thanks!
What you need is a callback to allow you to initialize variable onPostExecute:
interface OnCallCompleteCallBack {
void onCallComplete(int listSize);
}
In your AsyncTask do this:
public class MyTask extends AsyncTask < ... > {
// Maintain a ref to callback
OnCallCompleteCallBack callback;
MyTask(OnCallCompleteCallBack callback) {
this.callback = callback;
}
...
#Override
protected void onPostExecute(Void aVoid) {
if (callback != null) {
callback.onCallComplete(listSize);
}
}
}
Make your Activity implement OnCallCompleteCallBack and start the AsyncTask like this:
new MyTask(this).execute();
You can then use the value inside your activity's implementation of onCallComplete()
Before I answer, just a few observations:
Naming your activity ItemListView seems wrong (an Activity is not a View).
You should never perform networks calls on the UI thread.
If you want to log, you should use Log instead of System.out.println().
And now to the answer. You should execute the code that fetches the data in an AsyncTask (as you mentions it works). Once the data is fetched, you should update array and at that point update the UI in onPostExecute().
Android works pretty well using the MVC (Model-View–Controller) pattern and your problem is a classic case where you need to update the model using data from the server and update the views accordingly. The activity represents controller in this case.
Please go through the topic in android developer site Android Developer, Read the section "Introducing Network Operations on a Separate Thread" - To avoid creating an unresponsive UI, don't perform network operations on the UI thread. By default, Android 3.0 (API level 11) and higher requires you to perform network operations on a thread other than the main UI thread; if you don't, a NetworkOnMainThreadException is thrown.
Thanks Ashish

Toast in not showing in asynctask

I am trying to get message from the server to show in toast but it does not appear. The client receives the message from the server without any errors.I have tried opening UI thread in onpost but it didn't work
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
new test().execute();
}
public class test extends AsyncTask<String,String,String>{
#Override
protected String doInBackground(String... params) {
try
{
socket = new Socket("ip", port);
OutputStream outToServer = socket.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
Log.i(debugString, "Connected_reg!");
out.writeUTF("3");
InputStream inFromServer = socket.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
Log.i(debugString, in.readUTF());
string= in.readUTF();
}
catch (Exception e) {
Log.e(debugString, e.getMessage());
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
//super.onPostExecute(s);
Context context = getApplicationContext();
CharSequence text = string;
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
It might be to do with the context.
I've had issues in the past with getApplicationContext not working for certain things, although can't remember what form the top of my head.
Instead of using getApplicationContext, in the activity where you call your async task put this in the constructor call. For example, assuming you are going from MainActivity change the line new test().execute(); to new test(MainActivity.this).execute();
Then in the async class create the constructor as
public test(Context context) and set a global class variable to be the value of context, and then use this in your toast.makeText instead of what is returned from getApplicationContext.
Also take a look in the logcat, see if there are any errors or exceptions being thrown, it might also be worth adding a log line in the onpostexecute method just to double check you're definetely going in there.
Create a constructor in the test class which receive a context and use that context in the Toast.makeText. Pass the host activity context to that constructor.
getApplicationContext() is a Context class method, AsyncTask does not inherent from that class. I suppose you are in a scope where you can invoke that method but that scope context is not valid in the scope that you are invoking the Toast.makeText method.

Checking Azure connected Database onClick for login

So Azure spit the following code for me to insert into an activity (Android Studio is what I'm using)
Add the following line to the top of the .java file containing your launcher activity:
import com.microsoft.windowsazure.mobileservices.*;
Inside your activity, add a private variable
private MobileServiceClient mClient;
Add the following code the onCreate method of the activity:
mClient = new MobileServiceClient("https://pbbingo.azurewebsites.net", this);
Add a sample item class to your project::
public class ToDoItem{ public String id; public String Text;}
In the same activity where you defined mClient, add the following code:
ToDoItem item = new ToDoItem();
item.Text = "Don't text and drive";
mClient.getTable(ToDoItem.class).insert(item, new TableOperationCallback<item>(){
public void onCompleted(ToDoItem entity, Exception exception, ServiceFilter response)
{
if(exception == null){
//Insert Succeeded
} else {
//Insert Failed
}
}});
My goal is to create a login page. I understand that the above was probably offered up more with a ToList in mind. I just want to get the syntax correct today. The problem I think, is my basic class structure. I have created an OnClick Listener within my on create that gets the ID from a button in my layout. I don't need it checking for anything in the database until the button has been actually clicked to either login or register.
public class LoginClass extends AppCompatActivity{
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.MyLoginLayout);
MobileServiceClient mClient = null;
try {
mClient = new MobileServiceClient ("myAzureWebsite", "AzureKey", this);
} catch (MalformedURLException e) {
e.printStackTrace();
}
Button Attempt = (Button) findViewById (R.id.mySubmitButton);
final MobileServiceClient finalMClient = mClient; // finalized so I can use it later.
Attempt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick (View v) {
final View thisView = v;
final MyToDoItemClass item = new MyToDoItemClass();
In MyToDoItemClass I have two variables (Both String) Just left over from
the example of a ToDoList (they are String ID and String Text)
item.Text = "Filler";
item.ID = "Fill";
finalMClient.getTable(MyToDoItemClass.class).insert(new Table OperationCallback<item>() { //<--- I'm getting an error that the variable, item
is from an unknown class...
public void onCompleted (Item entity, Exception exception, ServiceFilterResponse response){
if(exception == null) {
Intent i = new Intent (LoginClass.this, MainActivity.class);
startActivity(i);
}else{
Toast.makeText(thisView.getContext(), "Failed", Toast.LENGTH_LONG).show();
}}
});
}
});
}}
The problem is with that the TableOperationCallback is saying that the item from MyToDoItemClass class is from an unknown class.
There are many issues in your code, as below.
According to the javadoc for class MobileServiceClient, there is not a method insert(TableOperationCallback<E> callback), so the code finalMClient.getTable(MyToDoItemClass.class).insert(new Table OperationCallback<item>() {...} is invalid.
The generics E in Table OperationCallback<E> means that you need to write a POJO class name instead of E, not an object variable name like item, so the correct code should be new Table OperationCallback<MyToDoItemClass>, please see the Oracle tutorial for Generics to know more details.
The figure below shows all methods insert of class MobileServiceClient. The bold word Deprecated under the method name means that you should not use it for developing on new project, it‘s only compatible for old project on the new version of Java SDK.
Please follow the offical tutorial to develop your app. Any concern, please feel free to let me know.

Android Beacon Library, Null Object Reference when calling startRangingBeaconsInRegion

I'm developing an android app using beacon library, part of this app is about to search for a specific beacon via its minor ID (which is inserted by user via dialog).
if I write everything in the same activity things works fine but I'd like to keep dialogs separate in an external pure java class, so in the activity implementing BeaconConsumer I added a "method" creating and binding the beacon manager.
public class Activity03 extends AppCompatActivity
implements BeaconConsumer, RangeNotifier {
...
public void scanForBeacon(Context context, String selectedMinorId){
beaconManager = BeaconManager.getInstanceForApplication(context);
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
Identifier minorIdFilter = Identifier.parse(selectedMinorId);
myRegion = new Region(
"my_region",
null,
null,
minorIdFilter);
beaconManager.bind((BeaconConsumer) context);
}
...
}
The point is that when calling startRangingBeaconsInRegion, i got:
Attempt to invoke virtual method 'void org.altbeacon.beacon.BeaconManager.startRangingBeaconsInRegion(org.altbeacon.beacon.Region)' on a null object reference
The sequence is:
1. the user is asked (via GoogleApiClient) to switch on BLE and localization
2. inside onActivityResult the dialog for inserting minor ID is picked from the java class DialogUtilities
DialogUtilities.showSelectionDialog(Activity03.this);
3. pressing the button dialog is dismissed, an instance of the BeaconConsumer activity is created and the method called:
Activity03 a03 = new Activity03();
a03.scanForBeacon(context, minorId);
4. when the onBeaconServiceConnect() is called I got null object reference on the line of startRangingBeaconsInRegion
#Override
public void onBeaconServiceConnect() {
try {
beaconManager.startRangingBeaconsInRegion(myRegion);
} catch (RemoteException e) {
e.printStackTrace();
}
}
I'm new of java and android but it doesn't seems to me that problem is about the Region because I've the same response even if I set to null all the Identifiers so I cannot understand why null reference.
Is it possible that I create two different BeaconMangers because of the activity's istance I return by Dialog ? If so how I can solve it?
If not, how to avoid this null object reference?
Thanks in advance
EDIT
BeaconManager declaration
public class Activity03 extends AppCompatActivity implements BeaconConsumer, RangeNotifier {
static final int REQUEST_CHECK_SETTINGS = 1000;
private BeaconManager beaconManager;
private Region myRegion;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme);
setContentView(R.layout.activity_03);
}
#Override
protected void onResume() {
#Override
super.onResume();
PermissionsUtilities.switchLocationAndBluetooth(Activity03.this);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode) {
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
DialogUtilities.showSensorSelectionDialog(Activity03.this);
break;
case Activity.RESULT_CANCELED:
...
break;
default:
break;
}
break;
}
}
You can try the code below to avoid null pointer exception:
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection beacons, Region region) {
if (beacons.size() > 0) {
Log.i(TAG, "The first beacon I see is about "+beacons.iterator().next().getDistance()+" meters away.");
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
} catch (RemoteException e) {
e.printStackTrace();
}
The question does not show the declaration of beaconManager and how it is scoped, so it is hard to say the exact cause.
Two tips:
The BeaconManager is a singleton, meaning there is one instance per Java process. So you can always get this instance from within an Activity like this: BeaconManager.getInstanceForApplication(this).startRangingBeaconsInRegion(myRegion);
Manually constructing a new Activity instance as shown below generally will not work in Android programming. You must create new Activity instance using an Intent. In your case I suspect you may not want to create a new Activity instance at all but to get a reference to the existing one. This may be unrelated to what you are asking, but it will certainly need to be changed: Activity03 a03 = new Activity03();
a03.scanForBeacon(context, minorId);

Android JUnit Tests Hang When Run Together

I'll apologize in advance for posting alot of code, this issue has really got me!
I have two Android JUnit tests that are causing me problems. Run each individually and they work fine, but when run together in one go (PasswordEntryActivityTests and then CryptoKeystoreTests) CryptoKeystoreTests hangs indefinitely.
I know it's not just the emulator being slow because each individually finishes in less than a second but it can hang for more than 20 minutes. I also tested it on a real device (Droid Razr) and it does the same thing.
The problematic code is the PasswordEntryActivity.launchNewPasswordActivity(). Removing that function makes everything work fine.
Pausing the function in the debugger while it's hanging says it's in:
MessageQueue.nativePollOnce(int, int) line: not available [native method]
What's going on?
I've copied below:
PasswordEntryActivity
PasswordEntryActivityTests
CryptoManagerKeystoreTests
Please let me know to post any other code you'd like to see.
Thanks!
public class PasswordEntryActivity extends Activity
{
...
private void launchNewPasswordActivity()
{
Intent launchNewPasswordIntent = new Intent(this, NewPasswordActivity.class);
startActivity(launchNewPasswordIntent);
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.password_entry_layout);
...
//this code should be LAST in onCreate because it exits the Activity
//CryptoManager.passwordIsRight returns 0 if no password has been set
passwordExists = CryptoManager.passwordIsRight("x", this) != 0;
if(!passwordExists)
launchNewPasswordActivity();
}
}
That Activity's test:
//supposed to make sure the application responds correctly when no password is set
public class PasswordEntryActivityTests extends android.test.ActivityInstrumentationTestCase2< crypnote.controller.main.PasswordEntryActivity>{
protected void setUp() throws Exception
{
passwordEntryActivity = getActivity();
//delete the database if it exists
File file = passwordEntryActivity.getFileStreamPath(DBInterface.Constants.DatabaseName);
if(file.exists())
assertTrue(file.delete());
file = passwordEntryActivity.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
if(file.exists())
assertTrue(file.delete());
}
//allows us to access the interface
#UiThreadTest
public void testNoPassword() throws Exception
{
passwordEntryActivity = getActivity();
EditText passwordEntryEditText =
(EditText) passwordEntryActivity.findViewById(
crypnote.controller.main.R.id.passwordentrylayout_passwordedittext);
Button unlockButton = (Button) passwordEntryActivity.findViewById(
crypnote.controller.main.R.id.passwordentrylayout_unlockbutton);
int passwordResult = CryptoManager.passwordIsRight("x", getActivity());
assertTrue(passwordResult == 0);
//pass a wrong password to the edittext and click the unlock button
passwordEntryEditText.setText("x");
assertTrue(unlockButton.performClick());
//get the foreground activity class name
ActivityManager am = (ActivityManager) passwordEntryActivity.
getSystemService(Context.ACTIVITY_SERVICE);
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
String foregroundClassName = componentInfo.getShortClassName();
//don't forget the leading '.'
assertTrue(!foregroundClassName.equals(".PasswordEntryActivity"));
}
}
The CryptoKeystoreTests:
public class CryptoKeystoreTests extends android.test.ActivityInstrumentationTestCase2<
crypnote.controller.main.PasswordEntryActivity>
{
public void testKeystore() throws Exception
{
Context context = getActivity();
//delete the database if it exists
File file = context.getFileStreamPath(DBInterface.Constants.DatabaseName);
if(file.exists())
assertTrue(file.delete());
file = context.getFileStreamPath(CryptoManager.Constants.KEYSTORE_PATH);
if(file.exists())
assertTrue(file.delete());
CryptoManager cryptoManager=null;
String password = CryptoManager.Constants.DEBUG_PASSWORD;
FileInputStream fis=null;
//the cryptomanager will generate a new key and keystore
cryptoManager = new CryptoManager(password, context);
Key CRYPTOKEY = cryptoManager.getKey();
cryptoManager.close();
//initialize KeyStore
KeyStore keystore = KeyStore.getInstance(Constants.KEYSTORE_INSTANCE_TYPE);
fis = context.openFileInput(CryptoManager.Constants.KEYSTORE_PATH);
keystore.load(fis, password.toCharArray());
assertTrue(keystore.containsAlias(Constants.APP_ALIAS));
assertTrue(keystore.isKeyEntry(Constants.APP_ALIAS));
Key key = keystore.getKey(CryptoManager.Constants.APP_ALIAS,
password.toCharArray());
assertTrue(key.getAlgorithm().equals(CryptoManager.Constants.PROVIDER_NAME));
assertTrue(key.getAlgorithm().equals(CRYPTOKEY.getAlgorithm()));
assertTrue(key.getFormat().equals(CRYPTOKEY.getFormat()));
if(fis != null)
fis.close();
}
}
EDIT: NewPasswordActivity.onCreate:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.new_password_layout);
}
It hangs because PasswordEntryActivityTests does not release/finish the resources/UI events that has been addressed/created by itself during its own running lifecycle, more specifically, then newly opened NewPasswordActivity.
PasswordEntryActivityTests starts by testing a creation of PasswordEntryActivity, i.e. getActivity(), which in consequence, based on the condition, launch a second NewPasswordActivity, the newly opened NewPasswordActivity occupy the foreground window and stay forever, it is developer's responsibility to release it properly after you have done your testing.
In instrumentation test, the correct way of detecting/monitoring second activity startup from current activity is to use ActivityMonitor, see the pseudo code below:
// No password result starting a second activity.
public void testNoPassword() {
// register NewPasswordActivity that need to be monitored.
ActivityMonitor activityMonitor = getInstrumentation().addMonitor(NewPasswordActivity.class.getName(), null, false);
// Get current activity, it will start NewPasswordActivity in consequence.
PasswordEntryActivity currentActivity = getActivity();
NewPasswordActivity nextActivity = getInstrumentation().waitForMonitorWithTimeout(activityMonitor, 5);
// NewPasswordActivity is opened and captured.
assertNotNull(nextActivity);
// Don't forget to release/finish NewPasswordActivity after test finish.
nextActivity.finish();
}

Categories

Resources