Android decompiler inserts 'this' keyword everywhere in the code? - java

I have original code which is given below.But i tried decompiling original apk it gave me this keyword everywhere(shown after this code below) :
public class Aboutt extends Activity {
WebView web;
ProgressBar progressBar;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aboutt);
web = (WebView) findViewById(R.id.webview01);
if (savedInstanceState != null)
web.restoreState(savedInstanceState);
else
web.loadUrl("http://www.google.com");
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
web.setWebViewClient(new myWebClient());
web.getSettings().setJavaScriptEnabled(true);
web.getSettings().setBuiltInZoomControls(true);
}
But the decompiled code gives me:
public class Aboutt
extends Activity {
ProgressBar progressBar;
WebView web;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_aboutt);
this.web = (WebView)this.findViewById(R.id.webview01));
if (savedInstanceState != null) {
this.web.restoreState(savedInstanceState);
} else {
this.web.loadUrl("http://www.google.com");
}
this.progressBar = (ProgressBar)this.findViewById(R.id.progressBar1);
this.web.setWebViewClient((WebViewClient)new myWebClient());
this.web.getSettings().setJavaScriptEnabled(true);
this.web.getSettings().setBuiltInZoomControls(true);
}
Here it gives this everywhere.
Will it affect working of the app or can i use this everywehere.

The this keyword refers to the current instance of the class i.e. the object that the method is called on.
Usually, this is omitted because if you have something like this:
private int i;
public int getI () { return i}
everyone knows that you are referring to i. If you want to add the this keyword, it's just more wordy and will not affect the compiled code.
Whenever you see your code reference a non-static member, you can add the this suffix. Like in the above example, you can change i to this.i.
However, this does not work in a static method. I mean it will NEVER appear in a static context.
But other than that, this is fine to appear anywhere else.

this is a reference to the current instance of a class. It is mostly used un cases where there are similar names of parameters and local variables (they live as long as the method) and member variables (which live as long as the object).
So while it's not okay to use it everywhere (will not work in static context for instance) you're safe with what the decompiler created.

Related

Calling methods without reference variable [duplicate]

This question already has answers here:
Calling a method inside another method in same class
(5 answers)
Why am I able to access a method without object in java [duplicate]
(2 answers)
Closed 3 years ago.
Could someone explain to me one thing about call methods, viz. When I was learning at Neatbeans, calling a method was always done using a reference variable, where I had to create a real object before, for example:
public class Question {
public static void main(String[] args) {
Test test = new Test();
test.method();
}
}
class Test {
void method() {
System.out.println("Test");
}
}
In this case, I had to create an object, assign its reference to the test variable, and then call the method.
However, in Android Studio, to call a method, I do not have to create a reference variable or an object, I only directly call the method ... for example:
public class SecondActivity extends AppCompatActivity {
EditText editText;
Button button2;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = findViewById(R.id.editText);
button2 = findViewById(R.id.button);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
prepareResult();
}
});
}
public void prepareResult() {
Intent i = new Intent();
name = editText.getText().toString();
i.putExtra("name", name);
setResult(RESULT_OK, i);
finish();
}
}
In this case, I do not create an object, and I do not assign its reference to 'X' variables, I immediately call the prepareResult method. Why is this happening?
In Java, when you call another method in the same class, you do not need to reference by it's class object.
Where when you call the method from same class, you can access method directly.
It's all a matter of scope. In your first example, you were trying to use the method method() from the class Test from within another class, Question.
In the second example, you can call prepareResult() directly because the method from where that call is issued, onCreate(), belongs to the same class SecondActivity.
This is possible because, essentially, they are in the same scope. All methods and variables in a particular class are visible amongst each other. Visibility outside of the class depends on the access modifiers, public, private, protected or the default package-private
You can find more details in this Oracle Java tutorial:
https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
In Java, whenever you call a function which is outside the activity, you are calling. You have to use a reference variable to call the other class constructor to build an object. It can be done in your case.
Test test = new Test();
test.method();
OR
new Test().method();
Whenever you call a function which is inside the same class(within where you defined the function), you can call directly using its name directly because you do not have to call the constructor of the class which is already created. Like you have done in your other code.
You can see the class do not change here.
public class SecondActivity extends AppCompatActivity {
EditText editText;
Button button2;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = findViewById(R.id.editText);
button2 = findViewById(R.id.button);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
prepareResult();
}
});
}
public void prepareResult() {
Intent i = new Intent();
name = editText.getText().toString();
i.putExtra("name", name);
setResult(RESULT_OK, i);
finish();
}
}

How to replace deprecated code in class derived from PreferenceActivity? [duplicate]

I just noticed the fact that the method addPreferencesFromResource(int preferencesResId) is marked deprecated in Android's documentation (Reference Entry).
Unfortunately, no alternative method is provided in the method's description.
Which method should be used instead in order to connect a preferenceScreen.xml to the matching PreferenceActivity?
No alternative method is provided in the method's description because the preferred approach (as of API level 11) is to instantiate PreferenceFragment objects to load your preferences from a resource file. See the sample code here: PreferenceActivity
To add more information to the correct answer above, after reading an example from Android-er I found you can easily convert your preference activity into a preference fragment. If you have the following activity:
public class MyPreferenceActivity extends PreferenceActivity
{
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.my_preference_screen);
}
}
The only changes you have to make is to create an internal fragment class, move the addPreferencesFromResources() into the fragment, and invoke the fragment from the activity, like this:
public class MyPreferenceActivity extends PreferenceActivity
{
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.my_preference_screen);
}
}
}
There may be other subtleties to making more complex preferences from fragments; if so, I hope someone notes them here.
#Garret Wilson Thank you so much! As a noob to android coding, I've been stuck with the preferences incompatibility issue for so many hours, and I find it so disappointing they deprecated the use of some methods/approaches for new ones that aren't supported by the older APIs thus having to resort to all sorts of workarounds to make your app work in a wide range of devices. It's really frustrating!
Your class is great, for it allows you to keep working in new APIs wih preferences the way it used to be, but it's not backward compatible. Since I'm trying to reach a wide range of devices I tinkered with it a bit to make it work in pre API 11 devices as well as in newer APIs:
import android.annotation.TargetApi;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
public class MyPrefsActivity extends PreferenceActivity
{
private static int prefs=R.xml.myprefs;
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
try {
getClass().getMethod("getFragmentManager");
AddResourceApi11AndGreater();
} catch (NoSuchMethodException e) { //Api < 11
AddResourceApiLessThan11();
}
}
#SuppressWarnings("deprecation")
protected void AddResourceApiLessThan11()
{
addPreferencesFromResource(prefs);
}
#TargetApi(11)
protected void AddResourceApi11AndGreater()
{
getFragmentManager().beginTransaction().replace(android.R.id.content,
new PF()).commit();
}
#TargetApi(11)
public static class PF extends PreferenceFragment
{
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(MyPrefsActivity.prefs); //outer class
// private members seem to be visible for inner class, and
// making it static made things so much easier
}
}
}
Tested in two emulators (2.2 and 4.2) with success.
Why my code looks so crappy:
I'm a noob to android coding, and I'm not the greatest java fan.
In order to avoid the deprecated warning and to force Eclipse to allow me to compile I had to resort to annotations, but these seem to affect only classes or methods, so I had to move the code onto two new methods to take advantage of this.
I wouldn't like having to write my xml resource id twice anytime I copy&paste the class for a new PreferenceActivity, so I created a new variable to store this value.
I hope this will be useful to somebody else.
P.S.: Sorry for my opinionated views, but when you come new and find such handicaps, you can't help it but to get frustrated!
My approach is very close to Garret Wilson's (thanks, I voted you up ;)
In addition it provides downward compatibility with Android < 3.
I just recognized that my solution is even closer to the one by Kevin Remo. It's just a wee bit cleaner (as it does not rely on the "expection" antipattern).
public class MyPreferenceActivity extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
onCreatePreferenceActivity();
} else {
onCreatePreferenceFragment();
}
}
/**
* Wraps legacy {#link #onCreate(Bundle)} code for Android < 3 (i.e. API lvl
* < 11).
*/
#SuppressWarnings("deprecation")
private void onCreatePreferenceActivity() {
addPreferencesFromResource(R.xml.preferences);
}
/**
* Wraps {#link #onCreate(Bundle)} code for Android >= 3 (i.e. API lvl >=
* 11).
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void onCreatePreferenceFragment() {
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new MyPreferenceFragment ())
.commit();
}
}
For a "real" (but more complex) example see NusicPreferencesActivity and NusicPreferencesFragment.
Instead of exceptions, just use:
if (Build.VERSION.SDK_INT >= 11)
and use
#SuppressLint("NewApi")
to suppress the warnings.
Instead of using a PreferenceActivity to directly load preferences, use an AppCompatActivity or equivalent that loads a PreferenceFragmentCompat that loads your preferences. It's part of the support library (now Android Jetpack) and provides compatibility back to API 14.
In your build.gradle, add a dependency for the preference support library:
dependencies {
// ...
implementation "androidx.preference:preference:1.0.0-alpha1"
}
Note: We're going to assume you have your preferences XML already created.
For your activity, create a new activity class. If you're using material themes, you should extend an AppCompatActivity, but you can be flexible with this:
public class MyPreferencesActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_preferences_activity)
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, MyPreferencesFragment())
.commitNow()
}
}
}
Now for the important part: create a fragment that loads your preferences from XML:
public class MyPreferencesFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.my_preferences_fragment); // Your preferences fragment
}
}
For more information, read the Android Developers docs for PreferenceFragmentCompat.

Java - How is it possible to use a method without a Object reference

I am curious to understand how I am able to call a method without calling it ON and object reference.
Here is a method I created:
public void changeAlpha(float f, View v) {
v.animate().alpha(f).setDuration(5000);
}
Here you can see that inside of the If/elif flow, I am calling changeAlpha without calling it on an object reference. How is that possible?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
imageView = (ImageView) findViewById(R.id.dragonImage);
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (imageView.getAlpha() == 1) {
changeAlpha(0, imageView);
} else if (imageView.getAlpha() == 0) {
changeAlpha(1, imageView);
}
}
});
}
In Java, if you do not explicitly mention an object, there is an implicit this added.
This is for example how the findViewById method is being called, it is equivalent to this.findViewById
Additionally in this case, you have an anonymous inner class (extending View.onClickListener). Inner classes in Java can access the containing classes' methods, which is why you can call changeAlpha where you do. This is actually equivalent to ContainingClass.this.changeAlpha. ContainingClass.this is the way in Java to reference the instance of the containing class (this would only reference the inner class). Again, the reference is implicit without you having to type it and allows access to the changeAlpha method.
In your example code, you are calling the method from an inner class. In order to this code work you must indicate what Class the the this (implicitly or nor).
Fore example, if the onCreate method belongs to MainActivity class, you will call the changeAlpha by typing MainActivity.this.changeAlpha

In android, when is a context different from "this"?

I am at baby step level of programming on Android (and in Java in general). I do understand that Activity inherits from the Context class. However in every code snippet I have come across, every time a context must be mentionned, it is set to "this".
My question is : when is a context different from "this" ? Could you provide an real life example of context needing to be different from "this"?
Thank you very much.
Typically, you will want to use this when you are "inside" of an Activity. However, when you are using for example a Helper class, the reference this will not work. An example can be something like this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
A case, where you cannot:
public class MyHelper
{
/* some code of yours */
public void lockOrientation(Activity activity)
{
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
The above code locks the orientation to the current orientation. Notice that you need to supply the method with an Activity parameter, since you cannot use:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
In the first example, you could use this to achieve this, because you were "inside" of an Activity.
Another type of example, how do you set onClickListener.
First example, when you use this:
public class MyActivity extends Activity implements View.OnClickListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
//handle the click event
}
}
In this example, you can use this because in the first line, we wrote implements View.OnClickListener, so the class inherits from the given interface. Without the implements thingie, you couldn't do it. An example of setting the onClickListener without this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//handle the click event
}
});
}
}
In the second example, we are defining an Anonymous Inner Class, which will handle the click event of the button. Notice that in this case, our Activity does NOT implements View.OnClickListener.
In Outer Class you directly use "this" reference
In Inner Class Or Abstract Class implementation Or Interface implementation use "classname.this" reference
Example:
class Example{
int number = 0;
public Example(int number){
this.number = number;
}
}
notice that number in the contructor and number in the class are not the same. Altough they have the same name. Saying number = number doesn't make sense. Be using this you can asses number in the class.
For example when you are implementing an OnClickListener the "this" is different.
this is a reference to the current object — the object whose method or constructor is being called.
Inside an Activity's method this can be used as a Context object because Activity inherits from ContextThemeWrapper, which inherits from ContextWrapper, which inherits from Context.
A Fragment on the other hand does not inherit from Context. So to get the Context inside a Fragment you would have to call getActivity() for example.
This applies to any object you are calling this from.
Consider you are inside the OnClick() method of a View.OnClickListener and you want to start an Activity:
button.setOnClickListener (new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(this, NextActivity.class); // wrong because 'this' is the OnClickListener object
Intent intent = new Intent(CurrentActivity.this, NextActivity.class); // correct because 'this' is the CurrentActivity object
startActivity(intent);
}
});

Android Final vs Private textviews

simple maybe stupid question. I have a login activity which launches another activity, and here's the code:
public class LoginActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
ActionBar actionBar = getActionBar();
actionBar.hide();
Button btnLogin = (Button) findViewById(R.id.btnLogin);
final TextView tvUsername = (TextView) findViewById(R.id.tvUsername);
final TextView tvPassword = (TextView) findViewById(R.id.tvPassword);
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (tvUsername.getText().toString().length()<1) {
Toast msg = Toast.makeText(LoginActivity.this, "Enter a Username", Toast.LENGTH_LONG);
msg.setGravity(Gravity.TOP|Gravity.LEFT, 0, 70);
msg.show();
tvUsername.requestFocus();
} else if (tvPassword.getText().toString().length()<1) {
Toast msg = Toast.makeText(LoginActivity.this, "Enter a Password", Toast.LENGTH_LONG);
msg.setGravity(Gravity.TOP|Gravity.LEFT, 0, 200);
msg.show();
tvPassword.requestFocus();
} else {
startActivity(new Intent(LoginActivity.this,CrewScheduleActivity.class));
finish();
}
}
});
}
}
My question is about the textviews. Eclipse basically said i had to make them final in order to use them in the onClick event of the button. NP so i did that and it worked.
The question is What is the difference between putting these above the #Override as private vs inside the OnCreate as final?
This has to do with closure in Java. Basically, when you use an anonymous class, the values (not objects themselves) used within it are copied to that class for usage. Therefore, it does not make sense to return or modify those variables within the class, hence they must be final.
However, if the variable is instead part of the class containing the anonymous class, that's different. Basically, your inner class has a reference to the LoginActivity object (as LoginActivity.this), and can use and modify its members and methods.
When you put them "above the #Override", you are making them member variables of the LoginActivity class. Therefore, they can be accessed by the anonymous class.
Succinctly, the difference is that: final variables are local to the method, and copied to the anonymous class; member variables are local to the containing class and are modified by the anonymous class.
If you want to reuse the data from the anonymous class later, use a member variable. If you only need it within onCreate() and the anonymous class, then a final variable will suffice.
When you declare the TextView field (or any field for that matter) as public, it can be accessed directly by any other class, which I don't believe is your intention; there's no reason to make the TextView variable public.
If it is set as private, there is a guarantee that its value won't be overridden in another class, which is what the final keyword was designed to do in the first place. So, simply set it as private, and you won't have to worry about Eclipse correcting you.
So, in summary: making the field private/final ensures that the value cannot be overridden from another class, which is a good design.
Hope this rambling helps. I'll be glad to clarify it better if it doesn't.

Categories

Resources