I've had an interview and I was given the following code, so that the UserAPI is a utility class for retrieving data from the network.
Assume it operate with its own threading mechanism with no respect to the caller thread.
And I had to find what's wrong with the code:
public class NetworkTestActvitiy extends Activity {
private TextView userNameTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chegg_test_layout);
userNameTextView = (TextView)findViewById(R.id.userName);
}
#Override
protected void onStart() {
super.onStart();
loadUserName();
}
private void loadUserName() {
UserAPI.getInstance().getUserName(new NetworkListener() {
#Override
public void onError(ErrorMessage error) {
Logger.e("Failed to get user use: " + error.getMessage());
}
#Override
public void onSuccess(String userName) {
userNameTextView.setText(userName);
}
});
}
}
My guess would be that the call to userNameTextView.setText can not be from UI thread and has to be marshalled.
Related
I'm new on android development, so decided to learn simple login using MVP architectural pattern, in general everything is working fine, as checking user credentials, calling repository...etc.
However, only the implementations of showProgress() & hideProgress() that works in a weird way, for me at least.
Note that the showProgress() only works if the user inter valid credentials.
Thanks.
// Presenter Class
package com.example.mvp.login;
import android.util.Log;
import com.example.mvp.login.LoginContract;
import com.example.mvp.utils.SharedPrefManager;
public class LoginPresenterImpl implements LoginContract.Presenter{
SharedPrefManager sharedPrefManager;
private LoginContract.View view;
private LoginContract.Service service;
public LoginPresenterImpl(LoginContract.View view, LoginContract.Service service) {
this.view = view;
this.service = service;
sharedPrefManager = SharedPrefManager.getInstance(view.getContext());
}
#Override
public void onLoginClicked() {
String username = view.getUsername();
if (username.isEmpty()){
view.showUsernameError();
view.hideProgress();
return;
}
String password = view.getPassword();
if (password.isEmpty()){
view.showPasswordError();
view.hideProgress();
return;
}
view.showProgress(); // this method is called, but doesn't show in the UI Thread
boolean loginSucceeded = service.login(username, password);
if (loginSucceeded){
sharedPrefManager.userLogin(username);
view.navigateHome();
return;
}
view.hideProgress();
view.showLoginError();
}
#Override
public void isUserLoggedIn() {
if(sharedPrefManager.isLoggedIn())
view.navigateHome();
}
}
// View Class
public class LoginActivity extends AppCompatActivity implements LoginContract.View{
private EditText ed_username, ed_password;
private Button login;
private TextView signUp;
private ProgressBar progressBar;
LoginContract.Presenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView(this);
presenter = new LoginPresenterImpl(this, new LoignServiceImpl());
presenter.isUserLoggedIn();
login.setOnClickListener(click);
}
View.OnClickListener click = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.login:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
presenter.onLoginClicked();
}
}, 1200);
}
}
};
public void initView(LoginActivity view){
ed_username = view.findViewById(R.id.username);
ed_password = view.findViewById(R.id.password);
login = view.findViewById(R.id.login);
signUp = view.findViewById(R.id.sign_up);
progressBar = view.findViewById(R.id.progressBar);
}
#Override
public String getUsername() {
return ed_username.getText().toString();
}
#Override
public String getPassword() {
return ed_password.getText().toString();
}
#Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
#Override
public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
#Override
public void showUsernameError() {
ed_username.setError("Must not be empty");
}
#Override
public void showPasswordError() {
ed_password.setError("Must not be empty");
}
#Override
public void navigateHome() {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
finish();
}
#Override
public void showLoginError() {
Toast.makeText(this,
"User not Found",
Toast.LENGTH_SHORT).show();
}
#Override
public Context getContext() {
return this;
}
}
Thanks to h4rd4r7c0r3 and Ionut J. Bejan, for highlighting several aspects i wasn't a ware of, in particular Working Thread(UI THREAD) and Another Thread(Background Thread).
Although i don't know yet how to implement them very well, i found way after searching the internet.
The main scenario are:
When the user enter username and password, UI should show indication
(Progress Bar) checking credentialiy of the user, implementing
showProgress().
When the checking is finished, UI should stop the indication.
implementing hideProgress().
An action to be taken based on the result, for example: Navigate to
new Activity or Toast "Wrong Username/Passowrd".
//LoginActivity
#Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
#Override
public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
// LoginPresenter
public void onLoginClicked() {
String username = view.getUsername();
if (username.isEmpty()){
view.showUsernameError();
view.hideProgress();
return;
}
String password = view.getPassword();
if (password.isEmpty()){
view.showPasswordError();
view.hideProgress();
return;
}
view.showProgress();
service.login(username,password, this);
}
#Override
public void isUserLoggedIn() {
if(sharedPrefManager.isLoggedIn())
view.navigateHome();
}
// implementing onFinished from FinishedListiner interface, to capture the result
#Override
public void onFinished(boolean bool) {
view.hideProgress();
if (bool){
sharedPrefManager.userLogin(view.getUsername());
view.navigateHome();
return;
}
view.showLoginError();
}
// Service, which will connect to the datasource
public class LoginServiceImpl implements LoginContract.Service {
UserRepository userRepository;
#Override
public void login(final String username, final String password, final FinishedListiner listener) {
userRepository = UserRepositoryImpl.getInstance();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// The method which will be used in the presenter class.
listener.onFinished(userRepository.checkUser(username, password));
}
}, 1200);
}
Try this below snippet :
Step 1:- Create BaseActivity extend to AppCompactActivity
Step 2:-Setting BaseActivity as per your requirement
Step 3:-Create Instance of your Progress Dialog
Step 4:-Create function showProgress()
Like:-
private fun showProgress(){
if(!progress.isShowing){
progress.show()
}
}
Step 5:- Create function HideProgress()
Like:-
private fun hideProgress(){
if(progress.isShowing){
progress.dismiss()
}
}
And use as per your requirement.
Your View just run presenter on another thread. See your Handler. Then it update the view and can not access to the UI. To fix this, just make sure your showProgress() is doing work on UI thread.
runOnUiThread(new Runnable() {
public void run() {
//show your proress here.
}
});
Here is my code I am getting Error: error: not an enclosing class: MainActivity. Please help me what is the issue in my code.
public class MyFirebaseMessagingSerivce extends FirebaseMessagingService {
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN", s);
}
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
}
public void onCreate() {
super.onCreate();
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( MainActivity.this, new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult)
{
String updatedToken = instanceIdResult.getToken();
Log.e("Updated Token",updatedToken);
}
});
}
}
Can we use this one in FirebaseMessagingService?
No the FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener() method is used to get token inside activity
The onNewToken() method is used to get token inside FirebaseMessagingService
For more information check this answer of Frank van Puffelen how onNewToken and FirebaseInstanceId.getInstance().getInstanceId() will work
Also check this for FirebaseMessagingService
SAMPLE CODE
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( MainActivity.this, new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult)
{
String updatedToken = instanceIdResult.getToken();
Log.e("Updated Token",updatedToken);
}
});
}
}
I am learning MVP design for the Android , I am new to it so need your valuable time . I went to the basics of the MVP how it work , Now i got stuck so need your help , I have to post the data to the server , when i hard code the value in presenter then i get the response correct but i need the data that is in the LoginActivity view when user press then that value should pass to the presenter and presenter pass that value to the Retrofit and bring back the result . Here is my try :
My LoginActvity:
public class LoginActivity extends BaseActivity implements LoginView {
#BindView(R.id.company_name)
protected EditText companyName_et;
#BindView(R.id.email)
protected EditText email_et;
#BindView(R.id.password)
protected EditText password_et;
#BindView(R.id.submit)
protected Button submit_btn;
#Inject
LoginPresenter loginPresenter;
#Override
protected int getContentView() {
return R.layout.login_activity;
}
#Override
protected void onViewReady(Bundle savedInstanceState, Intent intent) {
super.onViewReady(savedInstanceState, intent);
submit_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String company=companyName_et.getText().toString();
String username=email_et.getText().toString();
String password=password_et.getText().toString();
/*
I have to put the above String data
to my model class then i have to post the data to the server
*/
loginPresenter.passLoginDataToServer();
}
});
}
#Override
public void onError(String s) {
Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
}
#Override
public void onSuccess(String s) {
}
#Override
public void onResponse(Login login) {
Log.e("-----",""+login.getUserId());
}
#Override
protected void resolveDaggerDependency() {
DaggerLoginComponent.builder().applicationComponent(getApplicationComponent()).loginModule(new LoginModule(this)).build().inject(this);
}
}
Here is Login Presenter :
public class LoginPresenter extends BasePresenter<LoginView> implements Observer<Login>{
#Inject
CreateApiService createApiService;
#Inject
public LoginPresenter(){};
public void passLoginDataToServer(){
/*
when i hard code the data , i get the successful response.Like :
String user="raj";
String check="true";
Map<String,String> headers=new HashMap();
headers,put("xyz","pqr");
Login loginObject = new Login("xyzs", "pqr","Qtch","mvp");
*/
/*
But I need the data here from my LoginActivity ? Dunno how to pass the data from LoginActivity to presenter
*/
Observable<Login> loginObservable=createApiService.loginUser(user, check, headers, loginObject);
subscribeToLogin(loginObservable,this);
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Login login) {
getmView().onResponse(login);
}
#Override
public void onError(Throwable e) {
getmView().onError("Error "+e);
Log.e("---",""+e);
}
#Override
public void onComplete() {
getmView().onSuccess("Successfully Loaded");
}
}
Here is My Interface :
public interface LoginView extends BaseView {
void onError(String s);
void onSuccess(String s);
void onResponse(Login login);
}
Could you add the parameters to the method?
In your activity:
#Override public void onClick(View view) {
String company=companyName_et.getText().toString();
String username=email_et.getText().toString();
String password=password_et.getText().toString();
loginPresenter.passLoginDataToServer(compay, username, password);
}
In your presenter:
public void passLoginDataToServer(String company, String username, String password){
// Now create your request from the dynamic parameters
Observable<Login> loginObservable=createApiService.loginUser(username, check, headers, loginObject);
subscribeToLogin(loginObservable,this);
}
I hope you understand the errors in my coding. I want to retrieve value from function "ambilKey()" to get the value for "hasilKey". "hasilKey" is the node of my firebase database structure.
MyPictureDatabaseFirebase:
MyPictureResultLog:
value -KkonCYNZV6BX5BmWUI not saved to variable "hasilKey". So, this code doesn't work: dbAmbilDataProduk=FirebaseDatabase.getInstance().getReference().child("DataBisnis").child(hasilKey).child("DataProduk").
public class IbuActivity extends AppCompatActivity {
private Fireb][1]aseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private DatabaseReference mCekBisnis_Id;
private String nilaiBisnis="error";
private String hasilKey="error";
private RecyclerView mProdukList;
private DatabaseReference dbAmbilKeyPengguna;
private DatabaseReference dbAmbilDataProduk;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ibu);
Log.i("Aktivitas :","OnCreate");
mAuth=FirebaseAuth.getInstance();
cekAkunBisnis();
//Retrieve Value hasilKey is my problem
ambilKey();
//Check Value
Log.i("Result=",hasilKey);
//Not working function ambilkey() ?????
dbAmbilDataProduk=FirebaseDatabase.getInstance().getReference().child("DataBisnis").child(hasilKey).child("DataProduk");
mProdukList=(RecyclerView) findViewById(R.id.ibuRvProduk);
mProdukList.setHasFixedSize(true);
mProdukList.setLayoutManager(new LinearLayoutManager(this));
}
private void ambilKey() {
dbAmbilKeyPengguna=FirebaseDatabase.getInstance().getReference().child("DataPengguna").child(mAuth.getCurrentUser().getUid()).child("BisnisId");
dbAmbilKeyPengguna.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
hasilKey=dataSnapshot.getValue(String.class);
Log.i("ResultKeyAmbilKey=",hasilKey);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.i("Pesan","DatabaseError");
}
});
}
#Override
public void onStart() {
super.onStart();
FirebaseRecyclerAdapter<AmbilDataProduk,ProdukViewHolder> firebaseRecyclerAdapter=new FirebaseRecyclerAdapter<AmbilDataProduk, ProdukViewHolder>(
AmbilDataProduk.class,
R.layout.listprodukrow,
ProdukViewHolder.class,
dbAmbilDataProduk
) {
#Override
protected void populateViewHolder(ProdukViewHolder viewHolder, AmbilDataProduk model, int position) {
viewHolder.setNamaProduk(model.getNamaProduk());
viewHolder.setHargaProduk(model.getHargaProduk());
viewHolder.setFotoProduk(getApplicationContext(),model.getFotoProduk());
}
};
mProdukList.setAdapter(firebaseRecyclerAdapter);
}
public static class ProdukViewHolder extends RecyclerView.ViewHolder{
View view;
public ProdukViewHolder(View itemView) {
super(itemView);
view=itemView;
}
public void setNamaProduk(String namaProduk){
TextView buNamaProduk=(TextView) view.findViewById(R.id.prowTvNama);
buNamaProduk.setText(namaProduk);
}
public void setHargaProduk(String hargaProduk) {
TextView kelolaHargaProduk=(TextView) view.findViewById(R.id.prowTvHarga);
kelolaHargaProduk.setText("Harga : Rp."+hargaProduk);
}
public void setFotoProduk(final Context ctx, final String fotoProduk){
final ImageView imageViewFotoProduk=(ImageView) view.findViewById(R.id.prowIvFoto);
//Picasso.with(ctx).load(fotoProduk).into(imageViewFotoProduk);
Picasso.with(ctx).load(fotoProduk).networkPolicy(NetworkPolicy.OFFLINE).into(imageViewFotoProduk, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Picasso.with(ctx).load(fotoProduk).into(imageViewFotoProduk);
}
});
}
}
//Cek Akun sudah Login Jika sudah login apakah sudah terdaftar / punya bisnis
private void cekAkunBisnis() {
//CekAkunLogin
if(mAuth.getCurrentUser()!=null){
mCekBisnis_Id= FirebaseDatabase.getInstance().getReference().child("DataPengguna").child(mAuth.getCurrentUser().getUid()).child("BisnisId");
mCekBisnis_Id.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
nilaiBisnis=dataSnapshot.getValue(String.class);
//Cek sudah punya bisnis belum?
if(!nilaiBisnis.equals("belumada")){
//Sudah ada
}
else if(nilaiBisnis.equals("error")){
}
else{
//Belum ada
Intent bisnisIntent=new Intent(IbuActivity.this, BisnisActivity.class);
//Data activitynya dilupakan
bisnisIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(bisnisIntent);
Toast.makeText(IbuActivity.this, "Selamat Datang. Silahkan Isi nama Bisnis Anda", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(IbuActivity.this, "Database Error!!!", Toast.LENGTH_SHORT).show();
}
});
}
else{
//User tidak ada
Intent loginRegister=new Intent(IbuActivity.this, LoginRegister.class);
loginRegister.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(loginRegister);
}
}
//Membuat menu
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_tambahproduk, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==R.id.actionTambahProduk){
startActivity(new Intent(IbuActivity.this,KelolaProduk.class));
}
return super.onOptionsItemSelected(item);
}
}
You cannot use that variable outside the onDataChange() method in the way you do. This is happening because onDataChange() is called asynchronously. This means that your method is executed before onDataChange has been called. That's why is not displaying the correct value. So in order to use that variable, you need to use it inside the onDataChange() method.
For other approach, please visit this post and this post. You'll understand for sure better how things works.
I am using Retrofit connect electronic devices .but it responding with incorrect data.
Please suggest me some solution to this problem. Do you guys have any idea is it related to connect ?
myUrl :http://11.10.88.23/ajax_control&/
Interface Exapi
public interface ExApi {
#GET("/ajax_control&")
public void getFeed(Callback<Document> response);
}
Mainclass
public class MainActivity extends Activity implements RequestInterceptor{
Button mButton;
public static final String BASE_URL="http://11.10.88.23/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
requestData(BASE_URL);
}
});
}
private void requestData(String url){
RestAdapter adapter=new RestAdapter.Builder()
.setEndpoint(url).build();
ExApi api=adapter.create(ExApi.class);
api.getFeed(new Callback<Document>() {
#Override
public void success(Document document, Response response) {
Toast.makeText(getApplicationContext(), "value: " + document.getElementsByTagName("LED").item(0).getChildNodes().item(0).getNodeValue(), Toast.LENGTH_SHORT).show();
}
#Override
public void failure(RetrofitError retrofitError) {
Log.d("lai loi: ", retrofitError.getMessage());
}
});
}
#Override
public void intercept(RequestFacade requestFacade) {
final String author=encodeCredentialsForBasicAuthorization();
requestFacade.addHeader("Authorization", author);
}
private String encodeCredentialsForBasicAuthorization() {
final String userAndPassword = "user:admin";
return "Basic " + Base64.encodeToString(userAndPassword.getBytes(), Base64.NO_WRAP);
}
}
Error 401 unauthorized means request is denied due to invalid credentials. This kind of authentication is called Basic Authentication, and you can pass these parameters in an HTTP header as well.
Here's an article about how that can be done in Retrofit: https://futurestud.io/blog/android-basic-authentication-with-retrofit/