I'm wondering how to pass data/variables through classes?
Class.java
public class AddItem extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mlocListener = new CurrentLocation();
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
}
}
public void sendDataDetail(View v){
// This is where my HTTPPOST goes, need the location here
}
public class CurrentLocation implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
// TODO Auto-generated method stub
loc.getLatitude();
loc.getLongitude();
String Text = "My Current Location is: " + "Lat = " + loc.getLatitude() + "Long = " + loc.getLongitude();
Toast.makeText(getApplicationContext(),Text,Toast.LENGTH_SHORT).show();
}
}
SO basically, I have CurrentLocation() in onCreate, and then I have an HTTPPOST script in sendDataDetail. And then I have a class that gets the location.
How do I get that location and send it to sendDataDetail? What methods should I take?
Please note that I'm still learning android,
Thank you in advance!
In Android, sharedpreferences are used to pass information between classes.
This is the simplest example I know to explain how it works. http://android-er.blogspot.com/2011/01/example-of-using-sharedpreferencesedito.html
One way is to Extend the Application class and get the instance with the data, populate it in one class and use it in another. See this question on StackOverflow.
Basically what you do is that you extend the Application object and add your fields (location in your case) and set it at one place and get it at another. Here is the example code from the link I have mentioned:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
#Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
There are other ways, but this solution is pretty good!
In some use cases, you can put a static variable somewhere for both classes to reference. That would be easiest, and it would give pedants the shivers, which is always a good thing. Well, except when they're right, of course.
Related
I am developing an app where I am using clean architecture. In presenter, when something comes to method onCompleted then I must call function from Main activity.
this is my Presenter:
public class CheckInPresenter implements Presenter {
UseCase postCheckInUseCase;
Context context;
#Inject
CheckInPresenter(#Named("putCheckIn") UseCase postCheckInUseCase){
this.postCheckInUseCase = postCheckInUseCase;
}
public void initialize(){this.initializeCheckIn();}
public void initializeCheckIn(){this.putCheckIn();}
public void putCheckIn(){
this.postCheckInUseCase.execute(new CheckInSubscriber());
}
#Override
public void resume() {
}
#Override
public void pause() {
}
#Override
public void destroy() {
}
private final class CheckInSubscriber extends DefaultSubscriber<EventEntity>{
#Override
public void onCompleted() {
Log.d("onCompleted", "OnCompleted");
}
#Override
public void onError(Throwable e) {
Log.d("onError", "OnError: " + e.getMessage());
}
#Override
public void onNext(EventEntity eventEntity) {
Log.d("onNext", "OnNext");
}
}
}
And this is my function from MainActivity that I have to call:
public void getDataForToolbar() {
SharedPreferences sharedPreferences = getSharedPreferences(getResources().getString(R.string.Account_json), Context.MODE_PRIVATE);
final String account = sharedPreferences.getString(getResources().getString(R.string.account_json), null);
if (account != null) {
Gson gson = new Gson();
mAccount = gson.fromJson(account, AccountModel.class);
for (CompanyModel com : mAccount.getCompanies()) {
String name = com.getName();
company_name.setText(name);
logo_url = com.getLogo_url();
}
if (logo_url == null || logo_url.isEmpty()) {
Picasso
.with(this)
.load(R.drawable.default_company)
.resize(70, 58)
.transform(new RoundedTransformation(8, 0))
.into(toolbarImage);
} else {
picassoLoader(this, toolbarImage, logo_url);
}
String username = mAccount.getUsername();
if(mAccount.getStatus()){
aUsername.setText(username + "/" + getResources().getString(R.string.on_duty));
aUsername.setBackgroundColor(ContextCompat.getColor(mContext, R.color.colorGreen));
}else{
aUsername.setText(username + "/" + getResources().getString(R.string.off_duty));
aUsername.setBackgroundColor(ContextCompat.getColor(mContext, R.color.colorWhite));
}
}
}
Could someone helps me how to call this function into my onCompleted method in Presenter? Thanks in advance.
If you want to call some Activity's function from another object, you'll have to pass Activity's reference to that object. This means that you need to add Activity parameter to presenter's constructor.
Side note
I know that what you're implementing is called a "clean architecture" in many places (including the official MVP tutorials by Google), but you might want to read my posts on the subject in order to get an alternative view on what "clean" on Android should look like.
Why activities in Android are not UI elements
MVC and MVP architectural patterns in Android
Create interface IView and make your Activity to implement it.
In IView create method void getDataForToolbar();
I see #Inject annotation in your CheckInPresenter, so if you are using Dagger 2, update you Dagger module's constructor with IView, create a provider method for it and provide it for CheckInPresenter in this module.
Place IView in constructor of CheckInPresenter and update provider method for CheckInPresenter in Dagger module and Dagger component initialization in your Activity.
For example, it might look like this:
public class YourActivity implements IView {
...
}
#Module
public class YourModule {
private IView view;
public YourModule(IView view) {
this.view = view;
}
#Provides
public IView provideView() {
return view;
}
#Provides
#YourScope
public Presenter providePresenter() {
return new YourPresenter(view);
}
}
Just complete your existing Presenter and Module with IView.
After that call in your onCompleted method view.getDataForToolbar().
I was wondering if I could change the way my method function, similar to Blocks iOS.
So I have this interface create in class API.java
public interface APIListener {
void apiResponseSuccess(String output);
void apiResponseFailed(String output);
}
public APIListener listener = null;
public void myMethod{
listener.apiResponseSuccess("output");
}
In order to call my interface created, i have to implements
API.APIListener. and override the functions
#Override
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
#Override
public void apiResponseFailed(String output) {
}
And to call it, I have to use :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
API api = new API();
api.listener = this;
api.myMethod();
}
But drawbacks using this, It's hard to maintain if I call many methods inside the API, because all the results will go to apiResponseSuccess in my class, and have to tag which one coming from. Where the iOS comes with Blocks, it becomes easier. so basically, Is there a way to return the interface methods direct when we call it. similar to this
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
API api = new API();
api.listener = this;
api.myMethod(
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
public void apiResponseFailed(String output) {
}); //so the result will go in separately inside the where the function is called.
}
You can achieve it easily.
Your api method should get APIListener as a parameter - so when you'll call it you'll have something like this:
api.myMethod(new APIListener() {
#Override
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
#Override
public void apiResponseFailed(String output) {
}
});
You can also pass more params of course:
api.myMethod(new APIListener() {
#Override
public void apiResponseSuccess(Object output) {
Log.i("output from api",(String) output);
}
#Override
public void apiResponseFailed(String output) {
}
}, "my String", true);
BUT... notice that with your current implementation that the activity is the listener of your API call you'll have a memory leak!
You can solve it in several ways:
Don't make the listener anonymous ("ios block") but an inner static class that takes the activity as a WeakReference
Encapsulate the WeakReference inside your API and manage your listeners there.
I want to store my API result in a Array List, need to store, ID and ImageURL.
I am able to store the data using my class ImgModel. But I can't figureout how to access it later on.
public class ImgModel{
private String url, id;
public ImgModel(String id, String url) {
this.id = id;
this.url = url;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getId() {
return id;
}
public void setId(String photoId) {
this.id = photoId;
}
}
in MainActivity I call the API
public class MainActivity ....{
...
List<ImgModel> photosList = new ArrayList<ImgModel>();
....
//>>in the result API... after parse the json
String id = imgOgj.getString("id");
String url = imgOgj.getString("url");
ImgModelp p = new ImgModel(id, url);
photosList.add(p); //THIS WORKS
}
This Part I don't know how to implement - pls help
Now in the ImagePreview Activity I want to access these images and Id to display in Image view.
public class ImagePreviewActivity ....{
//List<ImgModel> mProcessedImg= new ArrayList<ImgModel>(); //If I do this, that means I am creating a new list, and not accessing the store data right ?
ProcessedImg mProcessedImg;
ImageView mImageView;
onCreate{
....
mProcessedImg.size(); //Get the size .i.e how make images url
mImageView.setImage(mProcessedImg.getUrl(0);//sample how can I get the url of position 0 ?
}
}
The photosList variable that you have declared in MainActivity is a local variable, which means that its scope is limited to only the code block in which it has been declared. This is the reason that you cannot access the data you have stored in that variable elsewhere in your code.
In order to use and access that same variable again outside of the code block in which it was declared you could instead use an instance variable of the MainActivity class, by amending your class declaration as follows:
public class MainActivity extends Activity {
List<ImgModel> mPhotosList;
...
// Override the OnCreate method of Activity
#Override
public void onCreate(Bundle savedInstanceState) {
// Create the mPhotosList instance variable
mPhotosList = new ArrayList<ImgModel>;
...
}
// other methods where you call the API and store the data in mPhotosList
...
}
These pages may help to explain the differences between the types of variables that you can use in Java:
what is the difference between local and instance variables in Java
http://www.cs.umd.edu/~clin/MoreJava/Objects/local.html
In terms of the next part of your problem, to access the mPhotosList member variable from another Activity, the following post may help:
Passing a Bundle on startActivity()?
If you neeed to share a list between lots of activities,putting it into MyApp's instance maybe a solution.
Create constructor inside ImagePreviewActivity.class which allows one List parameter.
public class ImagePreviewActivity ....{
List<ImgModel> imgList;
ImageView mImageView;
public ImagePreviewActivity(List<ImgModel> imageList){
this.imgList = imageList;
}
onCreate{
mImageView.setImage(imageList.get(0).getUrl();
}
}
Creating a object of ImagePreviewActivity.class
public class MainActivity ....{
...
List<ImgModel> photosList = new ArrayList<ImgModel>();
....
String id = imgOgj.getString("id");
String url = imgOgj.getString("url");
ImgModelp p = new ImgModel(id, url);
photosList.add(p);
//Craeate Object of ImagePreviewActivity
ImagePreviewActivity ipa = new ImagePreviewActivity(photosList);
}
I have following code. This is a class where I work with Map fragment, but I need to use these methods in other classes.
public class FragmentMap extends Fragment {
private LocationManager locationManager;
private Location myLocation;
private Location getBestLocation() {
Location gpslocation = getLocationByProvider(LocationManager.GPS_PROVIDER);
Location networkLocation =
getLocationByProvider(LocationManager.NETWORK_PROVIDER);
if (gpslocation == null) {
return networkLocation;
}
if (networkLocation == null) {
return gpslocation;
}
long old = System.currentTimeMillis() - 1000;
boolean gpsIsOld = (gpslocation.getTime() < old);
boolean networkIsOld = (networkLocation.getTime() < old);
if (!gpsIsOld) {
return gpslocation;
}
if (!networkIsOld) {
return networkLocation;
}
if (gpslocation.getTime() > networkLocation.getTime()) {
return gpslocation;
} else {
return networkLocation;
}
}
private Location getLocationByProvider(String provider) {
Location location = null;
locationManager = (LocationManager) getActivity().getApplicationContext()
.getSystemService(Context.LOCATION_SERVICE);
try {
if ( locationManager.isProviderEnabled(provider) ) {
location = locationManager.getLastKnownLocation(provider);
}
} catch (IllegalArgumentException e) {
Log.d("FragmentMap", "Cannot access Provider " + provider);
}
return location;
}
public String getCity(){
String result = "";
Geocoder gcd = new Geocoder(getActivity(), Locale.getDefault());
try {
List<Address> addresses = gcd.getFromLocation(myLocation.getLatitude(), myLocation.getLongitude(), 1);
if (addresses.size() > 0){
result = addresses.get(0).getLocality();
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
And I need to use it in 3 classes. How can I write it once and use it everywhere, so I don't have to duplicate it in each class. As I understand I should use public static. But java doesn't allow me.
I want to see what is the best practice for implementing such kind of thing.
Thank you.
First, you do not seem to define a class. Even if you only need static methods, you have to create a class :
public class MyClass {
[...]
}
Now, you are using a non-static attribute here :
private Location myLocation;
So you cannot use it in a static method.
Either you define this attribute and the method that uses it as static,
Or you declare both attribute and method as non-static.
Ask yourself if it makes sense to have this attribute as non-static (does it depend of a class instance or should it be shared by all instances?)
If you chose the non-static option, it becomes :
public class MyClass {
//Useless because you are only using a static field of this class.
//private LocationManager locationManager;
//Static attributes must be named with UPPER CASE letters
private static Location MY_LOCATION;
private static Location getBestLocation() {
private static Location getLocationByProvider(String provider) {
...
}
public static String getCity(){
...
}
}
There are several ways:
a) You could use a class to access public static methods. Not sure why you are facing an issue with it
b) You can declare an application class in your manifest and add these methods in the application class. The application class can be accessed from all activities and fragments. More details about application class can be found at http://developer.android.com/reference/android/app/Application.html
c) You can declare a base class which extends Activity class and add your methods here. Later you can create all your new activities by extending this base class and thereby can access these location retrieving methods. This way even the fragments would be able to access these methods.
You're probably missing a base class...
example:
class myLocationClass {
public static Location getBestLocation() {..}
public static Location getLocationProvider() {...}
public static String getCity {...}
}
and then use is via the class directly:
myLocationClass.getBestLocation() or myLocationClass.getLocationProvider() or myLocationClass.getCity
There are several ways of approaching this. The Application class is a singleton, so you could have a public method there and access it from wherever you can get a Context. A better approach would be to use a Bus like Otto and subscribe to it where you want location updates delivered.
I am trying to unzip a folder using Android's AsyncTask. The class (called Decompress) is an inner class of Unzip where Unzip itself is a non-Activity class. The pseudo-code is:
public class Unzip {
private String index;
private String unzipDest; //destination file for storing folder.
private Activity activity;
private boolean result; //result of decompress.
public void unzip(String loc) {
Decompress workThread = new Decompress(loc, activity);
workThread.execute();
if(unzip operation was successful) {
display(index);
}
//Class Decompress:
class Decompress extends AsyncTask<Void, Integer, Boolean> {
private ProgressDialog pd = null;
private Context mContext;
private String loc;
private int nEntries;
private int entriesUnzipped;
public Decompress(String location, Context c) {
loc = location;
mContext = c;
nEntries = 0;
entriesUnzipped = 0;
Log.v(this.toString(), "Exiting decompress constructor.");
}
#Override
protected void onPreExecute() {
Log.v(this.toString(), "Inside onPreExecute.");
pd = new ProgressDialog(mContext);
pd.setTitle("Unzipping folder.");
pd.setMessage("Unzip in progress.");
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
Log.v(this.toString(), "Showing dialog and exiting.");
pd.show();
}
#Override
protected Boolean doInBackground(Void... params) {
//unzip operation goes here.
unzipDest = something; //unzip destination is set here.
if(unzip operation is successful) {
result = true;
index = url pointing to location of unzipped folder.
} else {
result = false;
}
}
#Override
protected void onPostExecute(Boolean result) {
if(result) {
if(pd != null) {
pd.setTitle("Success");
pd.setMessage("folder is now ready for use.");
pd.show();
pd.dismiss();
pd = null;
Log.v(this.toString(), "Unzipped.");
index = unzipDest + "/someURL";
Log.v(this.toString(), "index present in: " + index);
}
} else {
pd = ProgressDialog.show(mContext, "Failure", "Cannot unzip.");
pd.dismiss();
}
}
}
Problems I am facing:
1. The value of unzipDest and index, updated in doInBackground, remain null to Unzip and all its objects. How can I ensure that the values remain updated?
2. I know that doInBackground occurs in a thread separate from the main UI thread. Does that mean that any values updated in the new thread will be lost once that thread returns?
How can I ensure that the values remain updated?
They will be updated since they are member variables. However, since AsyncTask is asynchrounous, they might not be updated yet when you check them. You can use an interface to create a callback when these values are updated. This SO answer covers how to do this
Does that mean that any values updated in the new thread will be lost once that thread returns?
No they shouldn't be "lost". They probably just haven't been changed in the AsyncTask when you check them.
Since this isn't your actual code I can't see when you are trying to access them but you can use the interface method or call the functions that need these values in onPostExecute(). You also can do a null check before trying to access them. It just depends on the functionality and flow that you need as to which is the best way. Hope that helps.
Edit
In the answer I linked to, you tell the Activity that you will use that interface and override its method(s) with implements AsyncResponse in your Activity declaration after creating the separate interface class
public class MainActivity implements AsyncResponse{
then, in your Activity still, you override the method you declared in that class (void processFinish(String output);)
#Override
void processFinish(String output){ // using same params as onPostExecute()
//this you will received result fired from async class of onPostExecute(result) method.
}
then this is called in onPostExecute() when the listener sees that it is done with delegate.processFinish(result); delegate is an instance of AsyncResponse (your interface class)
public class AasyncTask extends AsyncTask{
public AsyncResponse delegate=null;
#Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
Interface example taken from linked answer above and adjusted/commented for clarity. So be sure to upvote that answer if it helps anyone.