Creating AspectJ project for Android - android

I want to create project that reacts to OnCreate() method.
So, for example, I have activity
public class MainActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
//do something
}
}
And i want my AspectJ class to do something before and after OnCreate method call.
public aspect onCreate
{
pointcut captureOnCreate() : (execution(* onCreate(Bundle)));
before(): captureOnCreate()
{
System.out.println("Aspect BEFORE called");
}
after(): captureOnCreate()
{
System.out.println("Aspect AFTER called");
}
}
I tried to convert project to AspectJ and run it as Android application project, but it doesn't work. What is wrong?
SOLVED
Solved it myself.
In Eclipse AspectJ tools -> Inpath -> Add External JARs and link it to aspectjrt.jar file.
And executoin looks like that:
execution(* onCreate(*))&& !within(com.xxx.automation.onCreate);

Related

two build types - duplicate code. Not good solution

Android Studio 3.4
I have the next activity:
public class CartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod()
}
private void someCommonMethod() {
// some code
}
}
Now I have 2 build types: debug and release.
In debug I add method someDebugMethod() to activity
public class CartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod()
someDebugMethod()
}
private void someCommonMethod() {
// some code
}
private void someDebugMethod() {
// some debug code
}
}
In release I add method someReleaseMethod() to activity
public class CartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod()
someReleaseMethod()
}
private void someCommonMethod() {
// some code
}
private void someReleaseMethod() {
// some debug code
}
}
I read official documentation
and now project's stucture is:
app\src\debug\java\com\myproject\CartActivity.java
app\src\release\java\com\myproject\CartActivity.java
I remove CartActivity.java from app\src\main\java.
So, as a result, I have two files CartActivity.java.
Nice.
And now when I start the app in debug build type then runCartActivity in debug folder.
And when I start the app in release build type then runCartActivity in release folder.
Nice. It's work fine.
But suppose now I need to update the common method someCommonMethod(). This method used in both build types.
As a result, I need to update TWICE this method. First in app\src\debug\java\com\myproject\CartActivity.java and
then update same method with same code in app\src\release\java\com\myproject\CartActivity.java
So I think this is not good.
Because this is duplicate code. I need to copy & paste EVERY time in TWO files when update method someCommonMethod().
It's really bad.
How to avoid this duplicate code?
The ideal approach is when in CartActivity.java has only delta.
In app\src\debug\java\com\myproject\CartActivity.java has ONLY method someDebugMethod()
In app\src\release\java\com\myproject\CartActivity.java has ONLY method someReleaseMethod()
and common code is in app\src\main\java\com\myproject\CartActivity.java
Is it possible?
P.S. Suppose I have 3 build types.
As result, I need to update same code in three files. It's really not good.
Just create a CommonCartActivity in
app\src\main\java\com\myproject\CommonCartActivity.java
Then extend the class overriding the methods in the flavor implementations.
public class CartActivity extends CommonCartActivity {
protected void someCommonMethod() {
// some code
}
}
In this way CartActivity just inherits from CommonCartActivity with nothing else, duplicated in two flavors.
I think you do not need to complicate the structure of the project. Just use the real-time check.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
someCommonMethod();
if(BuildConfig.DEBUG){
someDebugMethod();
}else{
someReleaseMethod();
}
}
private void someCommonMethod() {
// some code
}
private void someDebugMethod() {
// some debug code
}
private void someReleaseMethod() {
// some release code
}
But, if you need to separate the code, try using one activity, but create a new class (for example, Fork) in two copies for release and debug. Create an instance of the class in the activity. In this class there will be a doMetnod() which will have the necessary code depending on the type of project. So you avoid duplication of the activity code.

when the .jar contains EventBus module

I have to bind a (.jar) file which contains an Eventbus module. When I call it vs reported an exception: XXXActivity has no public methods called onEvent.
but in reality the activity had an onEvent method.
Can help me?
Here is my code!
[Activity(Label = "BaseActivity")]
public class BaseActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
//EventBus.Default.Register(this);
try
{
JMessageClient.RegisterEventReceiver(this.Application.ApplicationContext);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(" ==ex==" + ex.Message);
}
// Create your application here
}
public void onEventMainThread(CN.Jpush.IM.Android.Api.Event.MessageEvent Event)
{
System.Diagnostics.Debug.WriteLine(" ==1==");
}
...
}
IMRecActivity
[Activity(Label = "IMRecActivity")]
public class IMRecActivity : BaseActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
}
public void onEvent(CN.Jpush.IM.Android.Api.Event.MessageEvent Event)
{
// CN.Jpush.IM.Android.Api.Event.MessageEvent me = (MessageEvent)Event;
CN.Jpush.IM.Android.Api.Model.Message msg = Event.Message;
switch (msg.ContentType.ToString())
{
case "text":
TextContent textContent = (TextContent)msg.Content;
System.Diagnostics.Debug.WriteLine(" ==JMessage OnEvent==" + textContent.Text);
break;
default:
System.Diagnostics.Debug.WriteLine(" ==JMessage OnEvent==" + msg.Content);
break;
}
System.Diagnostics.Debug.WriteLine(" ==JMessage OnEvent==");
}
}
JMessageClient.RegisterEventReceiver(this.Application.ApplicationContext); this used to register an EventBus in the .JAR.With the code,you can see that I have declare onEvent method,but it not working.
By the way,I already uesed a tool like jd-gui to see how it work.
Here is the way to download the .JAR file:
https://www.jpush.cn/downloads/sdk/android/
The Official website,which is a Chinese website.
https://www.jpush.cn/common/products
I would recommend investigating the respective .jar using a tool like jd-gui(http://jd.benow.ca/) to see what the expected method visibility is. You can then use respective Metadata fixes to resolve any issues you find there after the generated binding is created.
I've created a generic guide to help out with this task in which you can look into:
https://gist.github.com/JonDouglas/dda6d8ace7d071b0e8cb

OpenCV with Android Studio

For use OpenCV in my app with Android Studio I complete the following instructions to Step 6. But I don't know how and where include
static { System.loadLibrary("opencv_java"); }
?
In main activity, like this:
public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2{
static {
if(!OpenCVLoader.initDebug())
Log.d(sLog, "OpenCv load fail!");
else
Log.d(sLog, "OpenCv succes.");
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
...
}
...
}
instead of using System.loadLibrary(...), you can use OpenCVLoader.initDebug() which is suggested by OpenCv

Using activities within libraries in main application project

I am working on an Android project where I have a library project which has an activity.
I have a main app project which references the library project and tries to start the activity within the library project. In the library project I have the following activity:
public class DirectoryPicker extends Activity
{
GridView gridView = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.directory_picker);
gridView = (GridView)findViewById(R.id.directory_picker_gridview);
DirectoryAdapter.directories.add("String1");
DirectoryAdapter.directories.add("String2");
DirectoryAdapter.directories.add("String3");
DirectoryAdapter.directories.add("String4");
gridView.setAdapter(new DirectoryAdapter());
}
}
I am trying to start the activity using the following in my main application project.
protected OnPreferenceClickListener mPrefDefaultBackupClickListener = new OnPreferenceClickListener()
{
#Override
public boolean onPreferenceClick(Preference preference)
{
Intent intent = new Intent(getActivity(), DirectoryPicker.class);
startActivity(intent);
return false;
}
};
In my main application project AndroidManifest file I've added the following:
<activity android:name="com.MyCompany.Library.DirectoryPicker">
</activity>
When I try and launch the activity I get the following exception:
java.lang.NoClassDefFoundError: com.MyCompany.Library.DirectoryPicker
I can't see any reason why it doesn't work.
I've managed to find out the problem finally. Didn't manage to find any documentation but just trial and error and found if I go to File > Project Structure > Depdencies and then select my library and change the scope from compile to Provided and clean and rebuild everything the activity is then launched correctly.

How can I set Orientation Fixed for all activities

Android Layout. How can I set Orientation Fixed for all activities in application Tag of AndroidMainfest.xml ?
I don't want to set orientation for each activity individually.
Thanks in advance.
The GoogleIO app has a ActivityHelper class. It has a static method called initialize() which handles a lot things that happen for every Activity. Then it is just 1 line of code in the onCreate() method that you need to remember, that could handle setting that value and several others that are necessary for each activity.
Edit: No importing or anything like that. Create a class called ActivityHelper
public class ActivityHelper {
public static void initialize(Activity activity) {
//Do all sorts of common task for your activities here including:
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
Then in all of your activies onCreate() method call ActivityHelper.initialize()
If you are planning on developing for tables as well you may want to consider using:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
I wrote more about this here
Edit: Sorry... you need to pass the the Activity. see the code above
The accepted answer, and anything suggesting setRequestedOrientation, is far from perfect, because, as stated in documentation, calling setRequestedOrientation at runtime may cause the activity to be restarted, which among other things, affects animations between the screens.
If possible, the best is to set the desired orientation in AndroidManifest.xml.
But since it's error prone to rely on each developer to remember to modify the manifest when adding a new activity, it can be done at build time, by editing AndroidManifest file during the build.
There are some caveats to editing AndroidManifest this way that you need to be aware of though:
If you have some <activity-alias> entries in the output manifest, you should match <activity(?!-) instead of <activity to avoid modifying those (and use replaceAll, which matches regex, instead of replace, which matches string)
Be careful to not match the activities that are out of your control. See facebook + android : Only fullscreen opaque activities can request orientation
My requirement was to update all activities to have fixed orientation, but only in release builds. I achieved it with a bit of code in build.gradle which does simple string replacement in AndroidManifest (assuming that none of the activities has orientation specified already):
Android Studio 3.0 compatible solution example (touching only activities that match com.mycompany.*):
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
if (output.name == "release") {
output.processManifest.doLast {
String manifestPath = "$manifestOutputDirectory/AndroidManifest.xml"
def manifestContent = file(manifestPath).getText('UTF-8')
// replacing whitespaces and newlines between `<activity>` and `android:name`, to facilitate the next step
manifestContent = manifestContent.replaceAll("<activity\\s+\\R\\s+", "<activity ")
// we leverage here that all activities have android:name as the first property in the XML
manifestContent = manifestContent.replace(
"<activity android:name=\"com.mycompany.",
"<activity android:screenOrientation=\"userPortrait\" android:name=\"com.mycompany.")
file(manifestPath).write(manifestContent, 'UTF-8')
}
}
}
}
Android Studio 2.3 compatible solution example (matching all activities, but not matching <activity-alias> entries):
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
if (output.name == "release") {
output.processManifest.doLast {
def manifestOutFile = output.processManifest.manifestOutputFile
def newFileContents = manifestOutFile.getText('UTF-8')
.replaceAll(/<activity(?!-)/, "<activity android:screenOrientation=\"userPortrait\" ")
manifestOutFile.write(newFileContents, 'UTF-8')
}
}
}
}
I used userPortrait instead of portrait as I prefer to give the user more flexibility.
The above works out of the box if you just have variants (debug, release). If you additionally have flavors, you might need to tweak it a bit.
You might want to remove if (output.name == "release") depending on your needs.
If you write your project with generics.
And you have something like "BaseActivity" than inside onCreate it you can write code like that:
For Example:
BaseActivity extends AppCompatActivity, later you use YourActivity extends
BaseActivity
Portrait
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Landscape
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
(Monodroid/C# code)
You can create an abstract base class
public abstract class ActBase : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
RequestedOrientation = clsUtilidades.GetScreenOrientation();
}
}
Then all your activities must inherit this class instead Activity
Somehting like
[Activity(Label = "Orders", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.Mcc | ConfigChanges.Mnc)]
public class ActOrders : ActBase
{
....
This way avoids call the ActivityHelper in your events
I got the best solution. You don't have to pass any activity as parameter and stuff.
Here's what you have to do.
Create a class and extend your application like this.
Implement onActivityCreated and onActivityStarted and add the code that sets the orientation to whichever you want.
public class OldApp extends Application {
#Override
public void onCreate() {
super.onCreate();
// register to be informed of activities starting up
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
#Override
public void onActivityStarted(Activity activity) {
activity.setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
#Override
public void onActivityCreated(Activity activity,
Bundle savedInstanceState) {
activity.setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
});
}
}
After this, add the following in your Manifest file inside the <application block>:
android:name=".OldApp"
End result will be like this:
<application
android:name=".OldApp"
...other values... >
<activity
android:name=".SomeActivity"></activity>
</application>

Categories

Resources