Updated :
I have build a image cropping app its running fine, but now I want to save cropped image name as textbox value.
In short I am trying to set textbox value in object and get object value in java Class. I have tried several techniques, recently I am trying to get,set data by using interface technique and the image is saved as ".jpg"only.
I would love to know where am I going wronk?
Following is the code I have tried.
MainActivity
public class TestActivity extends AppCompatActivity implements CropHandler, View.OnClickListener {
public static final String TAG = "TestActivity";
ImageView mImageView;
EditText formnumber;
String formid;
CropParams mCropParams;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
mCropParams = new CropParams(this);
mImageView = (ImageView) findViewById(R.id.image);
formnumber =(EditText)findViewById(R.id.FormNumber);
findViewById(R.id.bt_crop_capture).setOnClickListener(this);
findViewById(R.id.bt_crop_gallery).setOnClickListener(this);
}
#Override
public void onClick(View v) {
mCropParams.refreshUri();
formid=formnumber.getText().toString();
// Intent i = new Intent(TestActivity.this, CropHelper.class);
// i.putExtra("Id",formid);
if(formid.matches(""))
{
Toast.makeText(getApplicationContext(),"Please Enter Application Id",Toast.LENGTH_SHORT).show();
}
else
{
switch (v.getId()) {
case R.id.bt_crop_capture: {
mCropParams.enable = true;
mCropParams.compress = false;
Intent intent = CropHelper.buildCameraIntent(mCropParams);
startActivityForResult(intent, CropHelper.REQUEST_CAMERA);
}
break;
case R.id.bt_crop_gallery: {
mCropParams.enable = true;
mCropParams.compress = false;
Intent intent = CropHelper.buildGalleryIntent(mCropParams);
startActivityForResult(intent, CropHelper.REQUEST_CROP);
}
break;
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
CropHelper.handleResult(this, requestCode, resultCode, data);
if (requestCode == 1) {
Log.e(TAG, "");
}
}
#Override
public void onTaskComplete(String response) {
onTaskComplete(this.formid);
}
}
CropHelper Class
public class CropHelper {
public static final String TAG = "CropHelper";
/**
* request code of Activities or Fragments
* You will have to change the values of the request codes below if they conflict with your own.
*/
public static final int REQUEST_CROP = 127;
public static final int REQUEST_CAMERA = 128;
public static final int REQUEST_PICK = 129;
public static String AppId;
public static final String CROP_CACHE_FOLDER = "PhotoCropper";
public static Uri generateUri() {
File cacheFolder = new File(Environment.getExternalStorageDirectory() + File.separator + CROP_CACHE_FOLDER);
if (!cacheFolder.exists()) {
try {
boolean result = cacheFolder.mkdir();
Log.d(TAG, "generateUri " + cacheFolder + " result: " + (result ? "succeeded" : "failed"));
} catch (Exception e) {
Log.e(TAG, "generateUri failed: " + cacheFolder, e);
}
}
// String name = String.format("image-%d.jpg", System.currentTimeMillis());
String name = String.format(AppId.toString()+".jpg",System.currentTimeMillis());
return Uri
.fromFile(cacheFolder)
.buildUpon()
.appendPath(name)
.build();
}
#Override
public void onTaskComplete(String response) {
AppId=response;
}
}
Interface
public interface CropHandler
{
void onPhotoCropped(Uri uri);
void onCompressed(Uri uri);
void onTaskComplete(String response);
void onCancel();
void onFailed(String message);
void handleIntent(Intent intent, int requestCode);
CropParams getCropParams();
}
Set formid to EditText value and get the return value in your CropHelper class.
public static String formid=null;
formid=formnumber.getText().toString();
Now create an object of your Activity in a class where you want to call formid value.
MainActivity my_objec= new MainActivity();
String id= my_objec.formid;
String name = String.format(""+id+".jpg",System.currentTimeMillis());
thats all you need to do.
Implement this with your class and get return back your value in interface
public interface onTaskComplete {
void onComplete(String response);
}
Normally what i do is create different class which holds/save all data and values which can used across differnt classes in app.
For example:
// your activity
private CropHelper cropHelper;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CropHelper.REQUEST_CROP) {
cropHelper.onReceivedImageData(data.get...)
}
}
public interface DataCallBack {
public void OnReceivedImageData(Data data);
}
....
// your crop helper
public class CropHelper implements YourActivity.DataCallBack {
#Override
public void OnReceivedImageData(Data data) {
// doing anything with data
}
}
Best Approach for this is using interface try to do as :
Create Interface
public interface MyListener {
// you can define any parameter as per your requirement
public void callback(View view, String result);
}
public class MyActivity extends Activity implements MyListener {
#override
public void onCreate(){
MyButton m = new MyButton(this);
}
// method invoke when mybutton will click
#override
public void callback(View view, String result) {
// do your stuff here
}
}
public class MyButton {
MyListener ml;
// constructor
MyButton(MyListener ml) {
this.ml = ml;
}
public void MyLogicToIntimateOthere() {
ml.callback(this, "success");
}
}
for more Go to this link:
Using Interface
Pass data through arguments in constructor..,
For example.. Create Constructor in your class.
public class CropHelper {
private Context context;
private String msg;
public CropHelper(Context context, String msg) {
this.context = context;
this.msg = msg;
if (msg != null) {
showMsg(msg);
}
}
//Replace with your logic
void showMsg(String msg) {
//Perform your operation
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
And then simple call it from any Activity by Creating instance of that class..
Like..
new CropHelper(this, "Hello from Activity");
Related
I need to access data from my Room database inside a BroadCastReceiver class, but as you know we need a lifecycle owner to get an instance of ViewModel class as shown below.
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationHelper.sendFinanceLoggingNotification(context);
RecurrenceInfoViewModel recurrenceInfoViewModel = new ViewModelProvider(this).get(RecurrenceInfoViewModel.class);
}
}
when passing "this" as the lifecycle owner android studio is throwing error. Can anyone please guide me from where I can get a lifecycle owner inside a BroadCastReceiver or if you can suggest any other way of accessing the data. Below are my ViewModel and Repository classes
public class RecurrenceInfoViewModel extends AndroidViewModel {
private LiveData<List<RecurrenceInfoEntity>> allRecurrenceInfos;
private RecurrenceInfoRepository recurrenceInfoRepository;
public RecurrenceInfoViewModel(#NonNull Application application) {
super(application);
recurrenceInfoRepository=new RecurrenceInfoRepository(application);
}
public void insertRecurrenceInfo(RecurrenceInfoEntity recurrenceInfoEntity) {
recurrenceInfoRepository.insertRecurrenceInfo(recurrenceInfoEntity);
}
public void updateRecurrenceInfo(RecurrenceInfoEntity recurrenceInfoEntity) {
recurrenceInfoRepository.updateRecurrenceInfo(recurrenceInfoEntity);
}
public void deleteRecurrenceInfo(RecurrenceInfoEntity recurrenceInfoEntity) {
recurrenceInfoRepository.deleteRecurrenceInfo(recurrenceInfoEntity);
}
public void deleteAllRecurrenceInfos() {
recurrenceInfoRepository.deleteAllRecurrenceInfo();
}
public LiveData<RecurrenceInfoEntity> getAllRecurrenceInfos(String recurrenceInfoKey) {
return recurrenceInfoRepository.getRecurrenceInfoEntityList(recurrenceInfoKey);
}
}
public class RecurrenceInfoRepository {
private RecurrenceInfoDao recurrenceInfoEntityDao;
private LiveData<List<RecurrenceInfoEntity>> recurrenceInfoEntityList;
public RecurrenceInfoRepository(Context context) {
MoneyManagerDatabase moneyManagerDatabase = MoneyManagerDatabase.getInstance(context);
recurrenceInfoEntityDao = moneyManagerDatabase.getRecurrenceInfoDao();
recurrenceInfoEntityList = recurrenceInfoEntityDao.getAllRecurrenceInfo();
}
public void insertRecurrenceInfo(RecurrenceInfoEntity data) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.INSERT_SINGLE_NODE_DATABASE_OPERATION).execute(data);
}
public void updateRecurrenceInfo(RecurrenceInfoEntity data) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.UPDATE_SINGLE_NODE_DATABASE_OPERATION).execute(data);
}
public void deleteRecurrenceInfo(RecurrenceInfoEntity data) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.DELETE_SINGLE_NODE_DATABASE_OPERATION).execute(data);
}
public void deleteRecurrenceInfo(String type) {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.DELETE_SINGLE_NODE_DATABASE_OPERATION).execute();
}
public void deleteAllRecurrenceInfo() {
new PerformSingleColumnDataOperations(recurrenceInfoEntityDao,
Constants.DELETE_ALL_NODES_DATABASE_OPERATION).execute();
}
public LiveData<RecurrenceInfoEntity> getRecurrenceInfoEntityList(String key) {
return recurrenceInfoEntityDao.getAllRecurrenceInfo(key);
}
private static class PerformSingleColumnDataOperations extends AsyncTask<RecurrenceInfoEntity, Void, Void> {
private RecurrenceInfoDao dataDao;
private String operationType;
PerformSingleColumnDataOperations(RecurrenceInfoDao dataDao, String operationType) {
this.dataDao = dataDao;
this.operationType = operationType;
}
#Override
protected Void doInBackground(RecurrenceInfoEntity... recurrenceInfoEntities) {
switch (operationType) {
case Constants.INSERT_SINGLE_NODE_DATABASE_OPERATION:
dataDao.insertRecurrenceInfo(recurrenceInfoEntities[0]);
break;
case Constants.UPDATE_SINGLE_NODE_DATABASE_OPERATION:
dataDao.updateRecurrenceInfo(recurrenceInfoEntities[0]);
break;
case Constants.DELETE_SINGLE_NODE_DATABASE_OPERATION:
dataDao.deleteRecurrenceInfo(recurrenceInfoEntities[0]);
break;
case Constants.DELETE_ALL_NODES_DATABASE_OPERATION:
dataDao.deleteAllRecurrenceInfo();
}
return null;
}
}
}
Thanks in advance.
I have solved the above problem by NOT using LiveData.
You can access data from Room anywhere by just providing the ApplicationContext as shown below.
DAO:
#Query("SELECT * FROM reference_info where recurrenceInfoPrimaryKey=:recurrenceinfoprimkey")
RecurrenceInfoEntity getAllRecurrenceInfoWithOutLiveData(String recurrenceinfoprimkey);
Repository:
public RecurrenceInfoEntity getRecurrenceInfoEntityWithOutLiveData(String key) {
return recurrenceInfoEntityDao.getAllRecurrenceInfoWithOutLiveData(key);
}
BroadCastReceiver:
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
new Thread(() -> {
RecurrenceInfoEntity recurrenceInfoEntity =
recurrenceInfoRepository.getRecurrenceInfoEntityWithOutLiveData(Constants.LOG_FINANCES_RECURRENCE_KEY);
}).start();
}
I'm developing an app and in first activity it has card view layout. I'm retrieving data from a webservice and relevant data are showed in card view. It's working well. Now when a user clicks a particular card view I need to go for another activity. I'm getting relevant ID for that card view and passing it to the second activity. In second activity I need to show the content according to that unique Id. But I'm not getting any thing. This is what I tried.
Pojo class
public class PromoDetails {
String PromoId;
String PromoName;
String PromoImg;
String promoDetails;
String promoValidty;
public PromoDetails(String PromoId, String PromoName, String PromoImg , String promoDetails , String promoValidity) {
this.PromoId = PromoId;
this.PromoName = PromoName;
this.PromoImg = PromoImg;
this.promoDetails = promoDetails;
this.promoValidty = promoValidity;
}
public String getPromoId() {
return PromoId;
}
public void setPromoId(String promoId) {
PromoId = promoId;
}
public String getPromoName() {
return PromoName;
}
public void setPromoName(String promoName) {
PromoName = promoName;
}
public String getPromoImg() {
return PromoImg;
}
public void setPromoImg(String promoImg) {
PromoImg = promoImg;
}
public String getPromoDetails() {
return promoDetails;
}
public void setPromoDetails(String promoDetails) {
this.promoDetails = promoDetails;
}
public String getPromoValidty() {
return promoValidty;
}
public void setPromoValidty(String promoValidty) {
this.promoValidty = promoValidty;
}}
ApiInterface
public interface ApiInterface {
#POST("ap/promotions.php")
Call<List<Promotions>> getPromotions();
#GET("test.php/promotions/{PromoId}")
Call<List<PromoDetails>> getPromotDetails(#Path("PromoId") String PromoId) ;}
New Activity class
public class PromotionsInside extends Activity {
private ApiInterface apiInterface;
private List<PromoDetails> promoDetails;
TextView prDescription;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.promo_inside);
Bundle extras = getIntent().getExtras();
String promoId = "";
if (extras != null) {
promoId = extras.getString("PROMO_ID");
getPromotionUpdate(promoId);
}
}
private void getPromotionUpdate(String myPromoId) {
apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
Call<List<PromoDetails>> call = apiInterface.getPromotDetails(myPromoId);
call.enqueue(new Callback<List<PromoDetails>>() {
#Override
public void onResponse(Call<List<PromoDetails>> call, Response<List<PromoDetails>> response) {
promoDetails = response.body();
runOnUiThread(new Runnable() {
#Override
public void run() {
prDescription = (TextView)findViewById(R.id.promoDescriptionsss) ;
prDescription.setText(promoDetails.get(0).getPromoName());
}
});
}
#Override
public void onFailure(Call<List<PromoDetails>> call, Throwable t) {
}
});
}}
I have similar case. Try to use this to start second activity:
Intent intent = new Intent(this, PromotionsInside.class);
//Make sure that you put String id in intent
intent.putExtra("PROMO_ID", id);
startActivity(intent);
And this in second activity:
if (getIntent().hasExtra("PROMO_ID")) {
String id = getIntent().getStringExtra("PROMO_ID", null);
//next steps that you need
}
Hope it will help you
I have an Activity1 with a TabLayout of two Fragments (each of them with a presenter). Once I click a button on the Toolbar a new Activity2 is started (with startActivityWithResults) which contains a simple list. At the selection of one of the items in the list the Activity2 returns the selected string to the previous Activity1 (the one with the TabLayout).
Now, once onActivityResult is called in Activity1, this one will call an API (using a presenter) that will get the new results and then it should update the two fragments in the TabLayout. I'm thinking to do it with RxJava but I have no idea where to start from.
The Activity1:
public class Activity1 extends BaseActivity {
#Inject
Actvity1Presenter mPresenter;
public static Intent newIntent(Context packageContext) {
return new Intent(packageContext, Activity1.class);
}
#LayoutRes
protected int getLayoutRedIs() {
return R.layout.app_bar_activity1;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutRedIs());
FwApplication.component(this).inject(this);
mPresenter.attachView(this);
Toolbar tb = (Toolbar) findViewById(R.id.toolbar_chips);
setSupportActionBar(tb);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_back_arrow);
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
mTabLayout.addTab(mTabLayout.newTab().setText("TAB1"));
mTabLayout.addTab(mTabLayout.newTab().setText("TAB2"));
mTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setAdapter(new PagerAdapter(getSupportFragmentManager(),
mTabLayout.getTabCount()));
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
mTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICK_ITEM_CODE) {
if (resultCode == RESULT_OK) {
mPresenter.updateResults(data);
}
if (resultCode == RESULT_CANCELED) {
}
}
}
And the pager:
public class PagerAdapter extends FragmentPagerAdapter {
int mNumOfTabs;
public PagerAdapter(FragmentManager fm, int NumOfTabs) {
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return Fragment1.newInstance();
break;
case 1:
return Fragment2.newInstance();
break;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
EDIT
ActivityPresenter:
public class ActivityPresenter implements Presenter<ActivityView>,
Interactor.OnFinishedListener<Response> {
private static final String TAG = "FW.ActivityPresenter";
#Inject
QueryPreferences mQueryPreferences;
private Interactor mInteractor;
private ActivityView mView;
private NetworkService mNetworkService;
private boolean mUseCache;
private String mQuery;
private int mPage;
private PublishSubject<Response> mPublishSubject = PublishSubject.create();
Observable<Response> getObservableResults() {
return mPublishSubject;
}
#Inject
public ActivityPresenter(NetworkService networkService) {
mNetworkService = networkService;
mInteractor = new InteractorImpl(mNetworkService);
}
public void onSearchQueryListener(String query, int page) {
mQuery = mQueryPreferences.getStoredQuery();
mUseCache = query.equals(mQuery);
if (!mUseCache) {
mQueryPreferences.setStoredQuery(query);
Log.d(TAG, "Query added to cache: " + query);
}
mPage = page;
mInteractor.loadResults(this, query, false, page);
}
#Override
public void onFinished(Response response) {
if (mView != null) {
mPublishSubject.onNext(response);
}
}
#Override
public void onError(Throwable throwable) {
if (mView != null) {
mView.showMessage(throwable.getMessage());
}
}
#Override
public void attachView(ActivityView mvpView) {
mView = mvpView;
}
#Override
public void detachView() {
mView = null;
mInteractor.unSubscribe();
}
}
InteractorImpl:
public class InteractorImpl implements Interactor {
private static final String TAG = "FW.InteractorImpl";
private NetworkService mNetworkService;
private Subscription mSubscription;
public InteractorImpl(NetworkService networkService) {
mNetworkService = networkService;
}
#Override
public void loadResults(final OnFinishedListener listener, String query, boolean useCache, int page) {
Observable<Response> responseObservable = (Observable<Response>)
mNetworkService.getObservable(mNetworkService.getAPI().getResponseObservable(query, page), Response.class, true, useCache);
mSubscription = responseObservable.subscribe(new Observer<Response>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
Log.e(TAG, e.getMessage());
listener.onError(e);
}
#Override
public void onNext(Response response) {
listener.onFinished(response);
}
});
}
public void unSubscribe() {
if(mSubscription != null && !mSubscription.isUnsubscribed()) {
mSubscription.unsubscribe();
}
}
}
FragmentPresenter:
public class FragmentPresenter implements Presenter<FragmentView>,
Interactor.OnFinishedListener<Response> {
private static final String TAG = "FW.FragmentPres";
#Inject
QueryPreferences mQueryPreferences;
private Interactor mInteractor;
private FragmentView mView;
private NetworkService mNetworkService;
private ActivityPresenter mActvityPresenter;
#Inject
public FragmentPresenter(NetworkService networkService) {
mNetworkService = networkService;
mInteractor = new InteractorImpl(mNetworkService);
}
void attachRecipeActivityPresenter(ActivityPresenter activityPresenter) {
mActvityPresenter = activityPresenter;
mActvityPresenter.getObservableResults().subscribe(data -> showData(data));
}
private void showData(Response response) {
if (response.getResults().getModels().isEmpty() && mPage == 0) {
mView.showNoResults();
} else {
mView.showResults(response.getResults().getModels());
}
}
#Override
public void onError(Throwable throwable) {
if (mView != null) {
mView.hideProgressBar();
mView.showMessage(throwable.getMessage());
}
}
#Override
public void attachView(FragmentView mvpView) {
mView = mvpView;
}
#Override
public void detachView() {
mView = null;
mInteractor.unSubscribe();
}
}
Using Retrofit2 and RxAndroid your method will look like this:
public void updateResults(String data) {
yourRetrofitAPI.getSomething(data)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(() -> {
// show your progress dialog
})
.subscribe(result -> {
// pass result to your view
}, error -> {
// hide your progress dialog
// get error message and send to your view
}, () -> {
// hide your progress dialog
});
}
interface YourRetrofitAPI {
#GET("/yourResource/{data}")
Observable<String> getSomething(#Path("data") String data);
}
So, about notify your fragments, with MVP you can make presenter fragments observe a stream from activity presenter, so both fragments will be notified when you query ends.
public class ExampleUnitTest {
#Test
public void testSample() throws Exception {
ActivityPresenter activityPresenter = new ActivityPresenter();
Fragment1Presenter fragment1Presenter = new Fragment1Presenter();
Fragment2Presenter fragment2Presenter = new Fragment2Presenter();
fragment1Presenter.attachActivityPresenter(activityPresenter);
fragment2Presenter.attachActivityPresenter(activityPresenter);
Observable.range(1, 10)
.delay(2, TimeUnit.SECONDS, Schedulers.immediate())
.subscribe(integer -> activityPresenter.queryData("query: " + integer));
}
class ActivityPresenter {
PublishSubject<String> publishSubject = PublishSubject.create();
Observable<String> serverDataAsObservable() {
return publishSubject.map(s -> String.format("%d - %s", System.currentTimeMillis(), s));
}
void queryData(String input) {
// based on your input you should query data from server
// and then emit those data with publish subject
// then all subscribers will receive changes
publishSubject.onNext(input);
}
}
class Fragment1Presenter {
private ActivityPresenter activityPresenter;
void attachActivityPresenter(ActivityPresenter activityPresenter) {
this.activityPresenter = activityPresenter;
this.activityPresenter.serverDataAsObservable()
.subscribe(data -> showData(data));
}
private void showData(String data) {
System.out.println("showing data on fragment1 with " + data);
}
}
class Fragment2Presenter {
private ActivityPresenter activityPresenter;
void attachActivityPresenter(ActivityPresenter activityPresenter) {
this.activityPresenter = activityPresenter;
this.activityPresenter.serverDataAsObservable()
.subscribe(data -> showData(data));
}
private void showData(String data) {
System.out.println("showing data on fragment2 with " + data);
}
}
}
Hope that it helps.
Best regards.
I'm trying to follow the Nest SDK on github and the sample code. My fragment code is as follows -
/**
* A placeholder fragment containing a simple view.
*/
public class ThermoActivityFragment extends Fragment implements View.OnClickListener {
private static final String TAG = ThermoActivity.class.getSimpleName(); // for log
// Nest API instance holder
private NestAPI tNest;
private NestToken tToken;
private Thermostat tThermo;
private Structure tStruct;
// Save the ID's and secret
private static final String CLIENT_ID = Constants.CLIENT_ID;
private static final String CLIENT_SECRET = Constants.CLIENT_SECRET;
private static final String REDIRECT_URL = Constants.REDIRECT_URL;
private static final int AUTH_TOKEN_REQUEST_CODE = 111;
private static final int RESULT_OK = -1;
private static final String THERMOSTAT_KEY = "thermostat_key";
private static final String STRUCTURE_KEY = "structure_key";
private static final String DEG_F = "%d°F";
// Text View
private TextView tTempIncr;
private TextView tTempDecr;
private TextView tSetTemp;
public ThermoActivityFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_thermo, container, false);
tTempIncr = (TextView) view.findViewById(R.id.temp_incr);
tTempDecr = (TextView) view.findViewById(R.id.temp_decr);
tSetTemp = (TextView) view.findViewById(R.id.temp_value);
view.findViewById(R.id.temp_incr).setOnClickListener(this);
view.findViewById(R.id.temp_decr).setOnClickListener(this);
NestAPI.setAndroidContext(getContext());
tNest = NestAPI.getInstance();
tNest.setConfig(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL);
// Auth flow
tToken = ThermoSettings.loadAuthToken(getContext());
if (tToken != null) {
authenticate(tToken);
} else {
tNest.launchAuthFlow(getActivity(), AUTH_TOKEN_REQUEST_CODE);
}
if (savedInstanceState != null) {
tThermo = savedInstanceState.getParcelable(THERMOSTAT_KEY);
tStruct = savedInstanceState.getParcelable(STRUCTURE_KEY);
//updateViews();
}
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(THERMOSTAT_KEY, tThermo);
outState.putParcelable(STRUCTURE_KEY, tStruct);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode != RESULT_OK || requestCode != AUTH_TOKEN_REQUEST_CODE) {
Log.e(TAG, "Finished with no result.");
return;
}
tToken = NestAPI.getAccessTokenFromIntent(intent);
if (tToken != null) {
ThermoSettings.saveAuthToken(getContext(), tToken);
authenticate(tToken);
} else {
Log.e(TAG, "Unable to resolve access token from payload.");
}
}
#Override
public void onStop() {
Log.d(TAG, "onStop");
super.onStop();
tNest.removeAllListeners();
}
#Override
public void onClick(View v) {
if (tThermo == null || tStruct == null)
return;
String tThermoId = tThermo.getDeviceId();
long temp = tThermo.getTargetTemperatureF();
switch (v.getId()) {
case R.id.temp_incr:
System.out.println("Temp Incr");
++temp;
tSetTemp.setText(String.format(DEG_F, temp));
tNest.thermostats.setTargetTemperatureF(tThermoId, temp);
break;
case R.id.temp_decr:
--temp;
tSetTemp.setText(String.format(DEG_F, temp));
tNest.thermostats.setTargetTemperatureF(tThermoId, temp);
break;
}
}
/**
* Authenticate with the Nest API and start listening for updates.
*
* #param token the token used to authenticate.
*/
private void authenticate(NestToken token) {
//NestAPI nest = NestAPI.getInstance();
tNest.authWithToken(token, new NestListener.AuthListener() {
#Override
public void onAuthSuccess() {
Log.v(TAG, "Authentication succeeded.");
fetchData();
}
#Override
public void onAuthFailure(NestException exception) {
Log.e(TAG, "Authentication failed with error: " + exception.getMessage());
ThermoSettings.saveAuthToken(getActivity(), null);
tNest.launchAuthFlow(getActivity(), AUTH_TOKEN_REQUEST_CODE);
}
#Override
public void onAuthRevoked() {
Log.e(TAG, "Auth token was revoked!");
ThermoSettings.saveAuthToken(getActivity(), null);
tNest.launchAuthFlow(getActivity(), AUTH_TOKEN_REQUEST_CODE);
}
});
}
/**
* Setup global listener, start listening, and update view when update received.
*/
private void fetchData() {
tNest.addGlobalListener(new NestListener.GlobalListener() {
#Override
public void onUpdate(#NonNull GlobalUpdate update) {
tThermo = update.getThermostats().get(0);
//System.out.println(tThermo);
tStruct = update.getStructures().get(0);
//updateViews();
}
});
}
}
The Settings file where I save the token is as follows -
public class ThermoSettings {
private static final String TOKEN_KEY = "token";
private static final String EXPIRATION_KEY = "expiration";
public static void saveAuthToken(Context context, NestToken token) {
if (token == null) {
getPrefs(context).edit().remove(TOKEN_KEY).remove(EXPIRATION_KEY).commit();
return;
}
getPrefs(context).edit()
.putString(TOKEN_KEY, token.getToken())
.putLong(EXPIRATION_KEY, token.getExpiresIn())
.commit();
}
public static NestToken loadAuthToken(Context context) {
final SharedPreferences prefs = getPrefs(context);
final String token = prefs.getString(TOKEN_KEY, null);
final long expirationDate = prefs.getLong(EXPIRATION_KEY, -1);
if (token == null || expirationDate == -1) {
return null;
}
return new NestToken(token, expirationDate);
}
private static SharedPreferences getPrefs(Context context) {
return context.getSharedPreferences(NestToken.class.getSimpleName(), 0);
}
}
What I'm trying to do -
I'm using a button on the homepage to enter the Activity. When I press the button, I see the Nest Authorization webpage, When I click on Accept, I see my UI but don't see the 'Authentication Succeeded' message in the log.
Can someone tell me what I'm doing wrong?
I finally got it to work. Earlier I was trying to make it work from a fragment. After I deleted the fragment and moved the code to MainActivity, it started to work.
I have a class "HomeActivity", which is as follows:
public class HomeActivity extends FragmentActivity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
public void Work() {}
}
}
I have another class WebServiceTask, which is as follows:
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// Here I am trying to call the work() method in HomeFragment, How can I do that?
}
My question is how can i call the work() method in HomeFragment class from onPostExecute().
I would propose making a listener for you task, and invoke its method in post execute. It will geve you a lot more flexibility and control on what you want to deafter the task finishes. Here is sample code I would use:
public class MyTask extend AsyncTask<Void, Void, Boolean> {
public interface MyTaskListener {
void onSuccess();
void onFailure();
void onError(Throwable t);
}
private Throwable error;
private MyTaskListener listener;
public MyTask(MyTaskListener listener) {
this.listener = listener;
}
#Overrride
public Boolean doInBackground(Void... params) {
try {
if (workCompleted()) {
//work completed without error - return true
return Boolean.TRUE;
} else {
//work failed to complete - return false
return Boolean.FALSE;
}
} catch(Exception e) {
//unexpected error happened - remember error and return null
this.error = e;
return null;
}
}
#Override
public void onPostExecute(Boolean result){
if (!isCancelled()) { //you only want to process if task wasn't cancelled
if (this.error != null && result == null) { //we have error, process it
if (listener != null) {
listener.onError(this.error);
}
}
if (Boolean.FALSE.equals(result)) { //we have faile, process it
if (listener != null) {
listener.onFail();
}
}
if (Boolean.TRUE.equals(result)) { //we have success
if (listener != null) {
listener.onSuccess();
}
}
}
}
}
And then, in you activit/fragment/service/ use something like this:
public class MyActivity extends Activity {
private void someInstanceMethod() {/ *do your work here */}
#Override
public void onCreate(Bundle savedInstanceState) {
//setup ui, or do whatever you need
//create MyAsyncTask with proper listener
MyAsyncTask task = new MyAsyncTask(new MyAsyncTask.MyAsyncTaskListener() {
#Override
public void onSuccess() {
//call your instance method here
someInstanceMethod();
}
#Override
public void onFailure() {
//process fail
}
#Override
public void onError() {
//process error
}
});
}
}
This is one method. I don't know if it is the best one:
Make work function as public static void. Call it from Asynctask onpostexecute as
HomeActivity.Work();
Edit:
One more way( again not sure if this is the best way):
If you cant make this work, consider putting your asynctask class inside the home activity class
Well using the FragmentManger findFragmentById() or findFragmentByTag() you can get an instance of the current fragment and call your fragment method.
Create an interface file
public interface AsynAction
{
public void Work();
}
Implements AsynAction in HomeActivity
public class HomeActivity extends FragmentActivity implements OnClickListener,AsyncAction {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
#Override
public void Work()
{
}
}
}
Then make changes in you asynctask to receive asyncAction object as reference
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final AyscAction asycAction,final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.asycAction=asycAction;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final AyscAction asycAction,final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(asycAction,activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// You can call work from here
if(asynAction!=null)
asyncAction.Work();
}