
In any type of significant project, you will certainly need more than one page. These pages we represent them using Activity or Fragment in android. Routing in this context is the act of navigating from one page to another. The page may be either an activity or fragment.
Data passsing involves passing data from one page to another. That data may be simple primitive types like strings and integers or custom objects, like say a Student or Teacher. You typically use intent and bundles in android but their are libraries that make this process easier, more flexible and less error prone. In this piece we look at these.
(a). CachePot
Questions CachePot helps answer.
Here is a summary of the problems cachepot helps you answer:
- How to Pass Data Between Activities
- How to Pass Data Between Fragments
- How to pass multiple data types between activities/fragments.
- How to Pass Data Between Activities and Fragments
- How to Pass Data From PageAdapter to Fragments.
Difference to other similar Libraries
- Its easy to use.
- Complete, encompassing both fragments and activities.
- Ability to pass single or multiple data or types. Easily pass custom objects or collections for example.
- No annotations or extension of classes.
CachePot - Android Simple Data Cache
CachePot is a simple open source for data cache management and passing data object between Fragments(Activities) without Pacelable and Serializable.
WARNING: It would be inappropriate to pass data both ways between different android applications, it's a better way to use
Intent
properly.
Download
Gradle:
repositories {
jcenter()
}
dependencies {
compile 'com.github.kimkevin:cachepot:1.2.0’
}
Maven:
<dependency>
<groupId>com.github.kimkevin</groupId>
<artifactId>cachepot</artifactId>
<version>1.2.0</version>
</dependency>
Usage
It works anywhere. there're examples as below
- Between
Activity
andActivity
- Between
Activity
andFragment
- Between
Fragment
andFragment
- From
PagerAdapter
to individualFragment
1. Single Type, Single Data
Push your data object to CachePot
instance in your Activity
or Fragment
.
public void push(Object data)
KoreanFood foodItem = new KoreanFood(1, "Kimchi", "Traditional fermented Korean side dish made of vegetables")
CachePot.getInstance().push(foodItem);
// open your activity or fragment
Pop your data object from CachePot
after view changes
public Object pop(Class classType)
public class MainFragment extends Fragment{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
KoreanFood foodItem = CachePot.getInstance().pop(KoreanFood.class);
}
In case of Collection or Map
Push
List<KoreanFood> foodItems = new ArrayList<>();
foodItems.add(new KoreanFood(1, "Kimchi", "Traditional fermented Korean side dish made of vegetables"));
foodItems.add(new KoreanFood(2, "Kkakdugi", "A variety of kimchi in Korean cuisine"));
CachePot.getInstance().push(foodItems);
// open your activity or fragment
Pop
List<KoreanFood> foodItems = CachePot.getInstance().pop(ArrayList.class);
2. Single Type, Multiple Data
How to pass Object(Model) Asynchronously when using ViewPager
First push your data object with position
or id
to CachePot
instance in FragmentStatePagerAdapter
(or FragmentPagerAdapter
)
public void push(long id, Object data)
private class PagerAdapter extends FragmentStatePagerAdapter {
...
public Fragment getItem(int position) {
KoreanFood foodItem = foodItems.get(position);
CachePot.getInstance().push(position, foodItem);
// or
CachePot.getInstance().push(foodItem.getId(), foodItem);
...
}
}
public Object pop(long id)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (getArguments() != null) {
final int position = getArguments().getInt(ARG_POSITION);
foodItem = CachePot.getInstance().pop(position);
// or
foodItem = CachePot.getInstance().pop(id);
}
}
If more complecated views, use TAG
public void push(String tag, Object data) public void push(String tag, long id, Object data)
private class PagerAdapter extends FragmentStatePagerAdapter {
...
public Fragment getItem(int position) {
KoreanFood foodItem = foodItems.get(position);
CachePot.getInstance().push(TAG, position, foodItem);
// or
CachePot.getInstance().push(TAG, foodItem.getId(), foodItem);
...
}
}
public Object pop(String tag) public Object pop(String tag, long id)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (getArguments() != null) {
final int position = getArguments().getInt(ARG_POSITION);
foodItem = CachePot.getInstance().pop(TAG, position);
// or
foodItem = CachePot.getInstance().pop(TAG, id);
}
}
Contributing
All contributions are welcome. Open a Pull Requests or refer to the Issues section.
License
MIT Copyright (c) 2016-present, “KimKevin” Yongjun Kim
Here is a usage example in a Fragment:
public class FoodFragment extends Fragment {
private static final String TAG = FoodFragment.class.getSimpleName();
private static String ARG_POSITION = "position";
private TextView txt;
private Button btn;
private KoreanFood koreanFoodItem;
public static FoodFragment newInstance(int position) {
FoodFragment fragment = new FoodFragment();
Bundle args = new Bundle();
args.putInt(ARG_POSITION, position);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
final int position = getArguments().getInt(ARG_POSITION);
koreanFoodItem = CachePot.getInstance().pop(position);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_food, container, false);
txt = (TextView) rootView.findViewById(R.id.main_txt);
btn = (Button) rootView.findViewById(R.id.main_btn);
return rootView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (koreanFoodItem == null) return;
txt.setText("It's " + koreanFoodItem.getName());
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CachePot.getInstance().push(koreanFoodItem);
NaviUtil.addFragment(getActivity(), new FoodDetailFragment());
}
});
}
}
Here is another example usage with a page adapter:
public class JarFragment extends Fragment {
private static final String TAG = JarFragment.class.getSimpleName();
private ViewPager mViewPager;
private List foodItems;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
foodItems = new ArrayList<>();
foodItems.add(new KoreanFood(1, "Kimchi", "Traditional fermented Korean side dish made of vegetables"));
foodItems.add(new KoreanFood(2, "Kkakdugi", "A variety of kimchi in Korean cuisine"));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
mViewPager = (ViewPager) rootView.findViewById(R.id.main_pager);
return rootView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
PagerAdapter mPagerAdapter = new PagerAdapter(getFragmentManager());
mViewPager.setAdapter(mPagerAdapter);
}
private class PagerAdapter extends FragmentStatePagerAdapter {
public PagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
/**
* Put your Obejct with Position to DataCache
*/
CachePot.getInstance().push(position, foodItems.get(position));
return FoodFragment.newInstance(position);
}
@Override
public int getCount() {
return foodItems.size();
}
}
}
Find full example in the download
(b). RxRouter
Questions RxRouter helps solve
Here are the common problems RxRouter makes easier:
- How to pass data between activities
- Alternative to onActivityResult
- How to route through classes as well as system and custom actions.
What makes RxRouter Unique
Here are the features that stand out in RxRouter:
- Easy to use
- Uses reactive programming
- Provides routing via annotations
- Pass multiple parameters between activities.
- Can route through system and custom actions.
- Firewall system - the ability to intercept a route.
RxRouter
Read this in other languages: 中文, English
A lightweight, simple, smart and powerful Android routing library.
Getting started
Setting up the dependency
Add to your project build.gradle file:
dependencies {
implementation 'zlc.season:rxrouter:x.y.z'
annotationProcessor 'zlc.season:rxrouter-compiler:x.y.z'
}
(Please replace x
and y
and z
with the latest version numbers: )
For Kotlin
you should use kapt
instead of annotationProcessor
Hello World
First add the @url
annotation to the activity we need to route:
@Url("this is a url")
class UrlActivity : AppCompatActivity() {
...
}
Then create a class that is annotated with @Router
to tell RxRouter that there is a router:
@Router
class MainRouter{
}
This class doesn't need to have any remaining code. RxRouter will automatically generate a RouterProvider
based on the class name of the class. For example, MainRouter
will generate MainRouterProvider
.
Then we need to add these routers to RxRouterProviders
:
class CustomApplication : Application() {
override fun onCreate() {
super.onCreate()
RxRouterProviders.add(MainRouterProvider())
}
}
Finally, we can start our performance:
RxRouter.of(context)
.route("this is a uri")
.subscribe()
Parameters
Routing with parameters:
With the with
method, you can add a series of parameters to this route.
RxRouter.of(context)
.with(10) //int value
.with(true) //boolean value
.with(20.12) //double value
.with("this is a string value") //string value
.with(Bundle()) //Bundle value
.route("this is a uri")
.subscribe()
No longer needs the onActivityResult
method
Want to get the value returned by the route? No longer have to write a bunch of onActivityResult
methods! One step in place with RxJava!
RxRouter.of(context)
.with(false)
.with(2000)
.with(9999999999999999)
.route("this is a uri")
.subscribe {
if (it.resultCode == Activity.RESULT_OK) {
val intent = it.data
val stringResult = intent.getStringExtra("result")
result_text.text = stringResult
stringResult.toast()
}
}
If there is a result return, it will be processed in subscribe.
Routing through Class
Do not want to use Url annotations? No problem, RxRouter also supports the original jump of the specified class name, in the same way:
RxRouter.of(context)
.routeClass(ClassForResultActivity::class.java)
.subscribe{
if (it.resultCode == Activity.RESULT_OK) {
val intent = it.data
val stringResult = intent.getStringExtra("result")
result_text.text = stringResult
stringResult.toast()
}
}
Routing through Action
Similarly, RxRouter also supports system Actions and custom Actions.
Routing through custom Action:
<activity android:name=".ActionActivity">
<intent-filter>
<action android:name="zlc.season.sample.action" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
RxRouter.of(context)
.routeAction("zlc.season.sample.action")
.subscribe({
"no result".toast()
}, {
it.message?.toast()
})
Routing through system action:
//dial
RxRouter.of(this)
.addUri(Uri.parse("tel:123456"))
.routeSystemAction(Intent.ACTION_DIAL)
.subscribe()
//send message
val bundle = Bundle()
bundle.putString("sms_body", "this is message")
RxRouter.of(this)
.addUri(Uri.parse("smsto:10086"))
.with(bundle)
.routeSystemAction(Intent.ACTION_SENDTO)
.subscribe()
Firewall
The RxRouter has a small and powerful firewall that can be intercepted according to firewall rules before routing. You can add one or more firewalls.
//create a LoginFirewall
class LoginFirewall : Firewall {
override fun allow(datagram: Datagram): Boolean {
if (notLogin) {
"please log in".toast()
return false
}
return true
}
}
//Add Firewall to Route
RxRouter.of(this)
.addFirewall(LoginFirewall())
.route("this is a url")
.subscribe()
License
Copyright 2018 Season.Zlc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.