3

I'm writing (for the first time) an Android library (with its own Activities) that will be imported in other Android projects using Android aar package.

My goal would be to publish only one class (let's call it MyPlugin) that does all the stuff (calling activities etc.) offering public methods; but it seems, to me, that all Activities must be public; so I would like to separate classes the user wants to use from classes i don't want to be used. Something like:

com.mycompany.myplugin.api
 |--> MyPlugin (public class with public methods)
com.mycompany.myplugin.activities
 |--> Acitivty1
 |--> ....
 |--> ActivityN (public? activities)
com.mycompany.myplugin.mystuff
 |--> Services (protected? class with protected? methods)

With this design I could say to the user "You should use only api package".

The problem is the Serivice class: it's used by Activities and MyPlugin, and it should be in the same package if I want it (or its methods) to be protected (so the final user can't see it).

I know that with reflection the final user could do anything but I want to be as clean and simple as possible.

The only solution I found is to have just one package with all the classes, but, as I said, I would like to separate MyPlugin from Activities.

Adrian Cid Almaguer
  • 7,815
  • 13
  • 41
  • 63
Fabio Filippi
  • 1,732
  • 25
  • 40
  • 1
    You could use something like friend concept: http://stackoverflow.com/questions/182278/is-there-a-way-to-simulate-the-c-friend-concept-in-java – Javi Mollá Feb 17 '15 at 15:18

2 Answers2

2

You can't create non-public Android components (Activity, Service, BroadcastReceiver). Neither can their constructors be non-public.

It's often good idea to populate your package by feature, not by component: e.g.

|-awesomefeatureone
|----Activity1
|----Fragment1
|----AsyncTask1
|----Service1
|-awesomefeaturetwo
|----BroadcastReceiver2
|----Service2

In this case you may play some useful tricks with encapsulation (package-local visibility, protected stuff).

I guess you won't be able to hide your component classes from end-user. But you might prohibit running one of your components directly from client code: use approach @billmuell suggested in comment, or just use package-local extras to start the Activity, package-local argument extras to create Fragment...you got the idea.

public class SomeFragment extends Fragment{
    static final String ARG = "package_local_arg";
    protected void onCreate(Bundle state){
        super.onCreate(state);
        Bundle args = getArguments();
        if(args == null || !args.contains(ARG)){       
            throw new IllegalStateException();
        }
    }
}


public class SamePackageActivity extends Activity {

   public void doSometh(){
        Fragment f = new SomeFragment();
        Bundle args = new Bundle();
        args.putInt(SomeFragment.ARG, 1);
        f.setArguments();
        ...
   }
}
Drew
  • 3,307
  • 22
  • 33
2

A common convention is to use a package named internal for private implementation/internal classes .

com.mycompany.myplugin // all public stuff here and in its subpackages
com.mycompany.myplugin.internal // all non public stuff

Also, follow @Drew's answer advice:

It's often good idea to populate your package by feature, not by component

References:

Community
  • 1
  • 1
Filipe Borges
  • 2,712
  • 20
  • 32
  • internal must have some public methods otherwise could not be used by myplugin package (myplugin.internal is a different package from myplugin) – Fabio Filippi Feb 25 '15 at 19:14
  • 1
    There will be lots of public classes and methods, but, by convetion, clients shall not use those as they are internal and intended to be used only by your own code. – Filipe Borges Feb 25 '15 at 21:19