I am creating an android application for my fyp i have compelete all my code but stuck with firebase push notifications.There are two different users of this application one is customer and other one is shop keeper. I tried to implement push notification in my shop keeper app. In shop keeper app when he accept the order of customer i want to send notification in customer app i tried with this code but unable to send notification. I am using firebase realtime database for this application.
I have tried last 3 days to solve this problem but unable to solve this problem. I also search on youtube and stackover flow but can not get any satisfactory solution.
Code i write to implement firebase push notification is mentioned.
fragmentOrder
public class fragmentOrders extends Fragment {
private View orderView;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private IFCMService ifcmService;
private DatabaseReference tokenRef;
public fragmentOrders() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
orderView = inflater.inflate(R.layout.fragment_orders, container, false);
ifcmService = RetrofitFCMClient.getInstance().create(IFCMService.class);
tokenRef = FirebaseDatabase.getInstance().getReference(common.TOKEN_REF);
return orderView;
}
#Override
public void onStop() {
super.onStop();
compositeDisposable.clear();
}
private void showOrders() {
FirebaseRecyclerOptions<OrderModel> options = new FirebaseRecyclerOptions.Builder<OrderModel>()
.setQuery(orderRef,OrderModel.class)
.build();
FirebaseRecyclerAdapter<OrderModel,OrderViewHolder> adapter = new FirebaseRecyclerAdapter<OrderModel, OrderViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull OrderViewHolder holder, int position, #NonNull OrderModel model) {
holder.CustomerName.setText(model.getName());
holder.CustomerNumber.setText(model.getNodePhone());
holder.ShippingAddress.setText(model.getAddress());
holder.OrderDateTime.setText(model.getDate() + " , " + model.getTime());
holder.TotalPrice.setText(model.getTotalprice());
holder.btnConfirmOrder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.cancelLayout.setVisibility(View.GONE);
holder.btnConfirmOrder.setText(model.getUid());
confirmOrder(model);
}
});
}
#NonNull
#Override
public OrderViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.view_order_items,parent,false);
return new OrderViewHolder(view);
}
};
orderList.setAdapter(adapter);
adapter.startListening();
}
}
});
}
private void confirmOrder(OrderModel model) {
tokenRef.child(model.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
TokenModel tokenModel = dataSnapshot.getValue(TokenModel.class);
Map<String,String> notiData = new HashMap<>();
notiData.put(common.NOTI_TITLE,"Order Confirmed");
notiData.put(common.NOTI_CONTENT,"Your Shopping Order is Confirmed and Shipped");
//ShowNotification(tokenModel,notiData);
FCMSendData sendData = new FCMSendData(tokenModel.getToken(),notiData);
compositeDisposable.add(ifcmService.sendNotification(sendData)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<FCMResponse>() {
#Override
public void accept(FCMResponse fcmResponse) throws Exception {
if (fcmResponse.getSuccess() == 1){
Toast.makeText(getContext(), "Order confirmed success", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(getContext(), "Order confirmed success but faild to send notification", Toast.LENGTH_SHORT).show();
}
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
Toast.makeText(getContext(), throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
})
);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(getContext(), databaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
public class OrderViewHolder extends RecyclerView.ViewHolder{
TextView CustomerName,CustomerNumber,ShippingAddress,OrderDateTime,TotalPrice;
Button btnViewOrderProducts,btnConfirmOrder,btnCancelOrder,btnCallCustomer;
RelativeLayout cancelLayout;
public OrderViewHolder(#NonNull View itemView) {
super(itemView);
CustomerName = itemView.findViewById(R.id.customer_name);
CustomerNumber = itemView.findViewById(R.id.customer_phone);
ShippingAddress = itemView.findViewById(R.id.customer_shipping_address);
OrderDateTime = itemView.findViewById(R.id.order_date_time);
btnViewOrderProducts = itemView.findViewById(R.id.btn_view_order_product);
TotalPrice = itemView.findViewById(R.id.order_total_price);
btnConfirmOrder = itemView.findViewById(R.id.btn_confirm_order);
btnCancelOrder = itemView.findViewById(R.id.btn_cancel_order);
btnCallCustomer = itemView.findViewById(R.id.btn_call_customer);
cancelLayout = itemView.findViewById(R.id.canel_layout);
}
}
}
common
public class common {
public static final String NOTI_TITLE = "title";
public static final String NOTI_CONTENT = "content";
public static final String TOKEN_REF = "Tokens";
public static void showNotification(Context context, int id, String title, String content, Intent intent) {
PendingIntent pendingIntent = null;
if (intent !=null){
pendingIntent = PendingIntent.getActivity(context,id,intent,PendingIntent.FLAG_UPDATE_CURRENT);
String NOTIFICATION_CHANNEL_ID = "Designer_Club_App";
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID
, "Designer Club", NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setDescription("Designer Club");
notificationChannel.enableLights(true);
notificationChannel.setVibrationPattern(new long[]{0,1000,500,1000});
notificationChannel.enableVibration(true);
notificationChannel.setLightColor(android.R.color.white);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(title)
.setContentText(content)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
if (pendingIntent != null){
builder.setContentIntent(pendingIntent);
Notification notification = builder.build();
notificationManager.notify(id,notification);
}
}
}
}
FCMResponse
import java.util.List;
public class FCMResponse {
private long multicast_id;
private int success,failure,canonical_ids;
private List<FCMResult> results;
private long message_id;
public FCMResponse() {
}
public long getMulticast_id() {
return multicast_id;
}
public void setMulticast_id(long multicast_id) {
this.multicast_id = multicast_id;
}
public int getSuccess() {
return success;
}
public void setSuccess(int success) {
this.success = success;
}
public int getFailure() {
return failure;
}
public void setFailure(int failure) {
this.failure = failure;
}
public int getCanonical_ids() {
return canonical_ids;
}
public void setCanonical_ids(int canonical_ids) {
this.canonical_ids = canonical_ids;
}
public List<FCMResult> getResults() {
return results;
}
public void setResults(List<FCMResult> results) {
this.results = results;
}
public long getMessage_id() {
return message_id;
}
public void setMessage_id(long message_id) {
this.message_id = message_id;
}
}
FCMResult
public class FCMResult {
private String message_id;
public FCMResult() {
}
public String getMessage_id() {
return message_id;
}
public void setMessage_id(String message_id) {
this.message_id = message_id;
}
}
FCMSendData
import java.util.Map;
public class FCMSendData {
private String to;
private Map<String,String> data;
public FCMSendData(String to, Map<String, String> data) {
this.to = to;
this.data = data;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public Map<String, String> getData() {
return data;
}
public void setData(Map<String, String> data) {
this.data = data;
}
}
IFCMService
import io.reactivex.Observable;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface IFCMService {
#Headers({
"Content-Type:application/json",
"Authorization:key=AAAAzkiH50E:APA91bETfnykxzAHx7Q4g5EFcPqZRHuyWi8S72OlnzFvxY4x_9o5MWl-BuxSB2ZUYt73Im1RJsOb55d7cTe3IPZR4fLIAaoJd_CaH1THCq3lxV4Rs6DfDdTtrC2HgIKNEgON2rD2ICGb"
})
#POST("fcm/send")
Observable<FCMResponse> sendNotification(#Body FCMSendData body);
}
RetrofitFCMClient
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitFCMClient {
private static Retrofit instance;
public static Retrofit getInstance(){
if (instance == null)
instance = new Retrofit.Builder()
.baseUrl("https://fcm.googleapis.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return instance;
}
}
MyFCMService
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class MyFCMService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Map<String,String> dataRecv = remoteMessage.getData();
if (dataRecv != null){
common.showNotification(this,new Random().nextInt(),
dataRecv.get(common.NOTI_TITLE),
dataRecv.get(common.NOTI_CONTENT),
null);
}
}
#Override
public void onNewToken(String s) {
super.onNewToken(s);
common.updateToken(this,s);
}
}
dependencies
implementation 'com.google.firebase:firebase-auth:19.3.0'
implementation 'com.google.firebase:firebase-database:19.2.1'
implementation 'com.google.firebase:firebase-messaging:20.1.4'
implementation 'com.google.firebase:firebase-storage:19.1.1'
implementation 'com.firebaseui:firebase-ui-database:5.0.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.9'
manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.designerclubadmin">
<application
<service android:name=".services.MyFCMService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>
you should updateTokens in mainActivity in serverAPP like the Client App
the same in two app
like this
private void GotoHomeActivity(ServerUserModel serverUserModel) {
FirebaseInstanceId.getInstance()
.getInstanceId()
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
dialog.dismiss();
common.currentServerUser = serverUserModel;
startActivity(new Intent(MainActivity.this , HomeActivity.class));
finish();
}
}).addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
dialog.dismiss();
common.currentServerUser = serverUserModel;
//this what i talk about (Update Token)
common.UpdateToken(MainActivity.this, task.getResult().getToken());
startActivity(new Intent(MainActivity.this , HomeActivity.class));
finish();
}
});
}
UpdateToken in Common Class
public static void UpdateToken(Context context, String newToken) {
FirebaseDatabase.getInstance()
.getReference(common.TOKEN_REF)
.child(common.currentServerUser.getUid())
.setValue(new TokenModel(common.currentServerUser.getPhone() , newToken))
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(context, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
Related
does anyone here encountered when you are updating a data it duplicates the existing data visually only but when I will back and go to the activity again it shows the real data.
Data 1 and Data 2, when I delete Data 2, it will show Data 1 Data2 and Data 1. However like I said, it is just visual had to go back and go to the activity again to show the current data which is Data 1 only since Data 2 has been deleted. I have tried searching but none of them are related to my problem and I genuinely do not know if this is from the database or the card or in the recyclerview. Any help will be much appreciated.
MainActivity
public class AdminReqFormsActivity extends AppCompatActivity {
RecyclerView adminreqform_recycler;
ImageView adminreqfromfield_backbtn;
DatabaseReference databaseReference;
ArrayList<ResearchReqForm> reqFormArrayList;
AdminRequestFormAdapter adminRequestFormAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin_req_forms);
adminreqform_recycler = findViewById(R.id.adminreqform_recycler);
adminreqfromfield_backbtn = findViewById(R.id.adminreqfromfield_backbtn);
databaseReference = FirebaseDatabase.getInstance().getReference("ResearchRequest");
adminreqform_recycler.setLayoutManager(new LinearLayoutManager(this));
reqFormArrayList = new ArrayList<ResearchReqForm>();
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot : snapshot.getChildren()){
ResearchReqForm researchReqForm = dataSnapshot.getValue(ResearchReqForm.class);
reqFormArrayList.add(researchReqForm);
}
adminRequestFormAdapter = new AdminRequestFormAdapter(AdminReqFormsActivity.this, reqFormArrayList);
adminreqform_recycler.setAdapter(adminRequestFormAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(AdminReqFormsActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
adminreqfromfield_backbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getApplicationContext(), WelcomeAdminActivity.class));
}
});
}
}
Model
public class ResearchReqForm {
String studentName;
String requestedtitle;
String requestedtags;
String requestMessage;
String requestid;
String requestStatus;
public ResearchReqForm() {
}
public ResearchReqForm(String studentName, String requestedtitle, String requestedtags, String requestMessage, String requestid, String requestStatus) {
this.studentName = studentName;
this.requestedtitle = requestedtitle;
this.requestedtags = requestedtags;
this.requestMessage = requestMessage;
this.requestid = requestid;
this.requestStatus = requestStatus;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getRequestedtitle() {
return requestedtitle;
}
public void setRequestedtitle(String requestedtitle) {
this.requestedtitle = requestedtitle;
}
public String getRequestedtags() {
return requestedtags;
}
public void setRequestedtags(String requestedtags) {
this.requestedtags = requestedtags;
}
public String getRequestMessage() {
return requestMessage;
}
public void setRequestMessage(String requestMessage) {
this.requestMessage = requestMessage;
}
public String getRequestid() {
return requestid;
}
public void setRequestid(String requestid) {
this.requestid = requestid;
}
public String getRequestStatus() {
return requestStatus;
}
public void setRequestStatus(String requestStatus) {
this.requestStatus = requestStatus;
}
}
Adapter
public class AdminRequestFormAdapter extends RecyclerView.Adapter<AdminRequestFormAdapter.AdminRequestFormViewHolder> {
Context context;
ArrayList<ResearchReqForm> requestFormArrayList;
public AdminRequestFormAdapter(Context c, ArrayList<ResearchReqForm> reqFormsList){
context = c;
requestFormArrayList = reqFormsList;
}
#NonNull
#Override
public AdminRequestFormViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new AdminRequestFormAdapter.AdminRequestFormViewHolder(LayoutInflater.from(context).inflate(R.layout.admin_request_list,parent,false));
}
#Override
public void onBindViewHolder(#NonNull AdminRequestFormViewHolder holder, final int position) {
holder.adminsudentname_reqcv.setText(requestFormArrayList.get(position).getStudentName());
holder.adminrelatedtopic_requestcv.setText(requestFormArrayList.get(position).getRequestedtitle());
holder.admintopictags_requestcv.setText(requestFormArrayList.get(position).getRequestedtags());
holder.adminbriefmessage_reqeuestcv.setText(requestFormArrayList.get(position).getRequestMessage());
holder.deleteresearch_request.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle("Delete Request Research?");
alert.setMessage("Are you sure you want to delete?");
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("ResearchRequest");
final String uniqueKey = requestFormArrayList.get(position).getRequestid();
databaseReference.child(uniqueKey).removeValue();
Toast.makeText(context, "Student's Request has been deleted.", Toast.LENGTH_SHORT).show();
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(context, "Form Closed.", Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
});
alert.show();
}
});
holder.acceptresearch_request.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "Test Toast For Accept", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return requestFormArrayList.size();
}
class AdminRequestFormViewHolder extends RecyclerView.ViewHolder{
TextView adminsudentname_reqcv, adminrelatedtopic_requestcv, admintopictags_requestcv, adminbriefmessage_reqeuestcv;
Button deleteresearch_request, acceptresearch_request;
public AdminRequestFormViewHolder(#NonNull View itemView) {
super(itemView);
adminsudentname_reqcv = itemView.findViewById(R.id.adminsudentname_reqcv);
adminrelatedtopic_requestcv =itemView.findViewById(R.id.adminrelatedtopic_requestcv);
admintopictags_requestcv = itemView.findViewById(R.id.admintopictags_requestcv);
adminbriefmessage_reqeuestcv = itemView.findViewById(R.id.adminbriefmessage_reqeuestcv);
deleteresearch_request = itemView.findViewById(R.id.deleteresearch_request);
acceptresearch_request = itemView.findViewById(R.id.acceptresearch_request);
}
}
}
Yes, this is actually quite common and comes from a misunderstanding of how Firebase snapshots work.
Whenever your onDataChange is called it gets a full snapshot of all the data at databaseReference. So even if there's only one change since you rendered the data, you get called with a full snapshot of all data at databaseReference including the change. And since you add all data in snapshot to reqFormArrayList, you end up duplicating it each time onDataChange gets called.
The simplest solution is to clear reqFormArrayList inside onDataChange:
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
reqFormArrayList.clear(); // this is the new line
for (DataSnapshot dataSnapshot : snapshot.getChildren()){
ResearchReqForm researchReqForm = dataSnapshot.getValue(ResearchReqForm.class);
reqFormArrayList.add(researchReqForm);
}
adminRequestFormAdapter = new AdminRequestFormAdapter(AdminReqFormsActivity.this, reqFormArrayList);
adminreqform_recycler.setAdapter(adminRequestFormAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(AdminReqFormsActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
}
})
I've added some code to make my question more clear.
Retrofit interface:
public interface JsonPlaceHolderAPI {
public static final String BASE_URL = "https://jsonplaceholder.typicode.com/";
#GET("todos/{number}")
Call<ResponseBody> getJsonResponse(#Path("number") String number);
}
The repository: --> fetchResponse() takes Viewmodel's MutableLiveData as parameter and uses it to update its value and then trigger View to change its UI.
public class Repository {
private final JsonPlaceHolderAPI api;
public Repository() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.build();
api = retrofit.create(JsonPlaceHolderAPI.class);
}
public void fetchResponse(String number, final MutableLiveData<CharSequence> mld){
final MutableLiveData<CharSequence> ml = new MutableLiveData<>();
api.getJsonResponse(number).enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
mld.setValue(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {}
});
}
}
The viewModel:
public class MainActivityViewModel extends AndroidViewModel {
MutableLiveData<CharSequence> response = new MutableLiveData<>();
Repository repository;
public MainActivityViewModel(#NonNull Application application) {
super(application);
repository = new Repository();
}
public void fetchData(String number) {
response.setValue("Loading data");
repository.fetchResponse(number, response);
}
public LiveData<? extends CharSequence> getLiveData() {
return response;
}
}
The View:
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
initViews();
viewModel.getLiveData().observe(this, new Observer<CharSequence>() {
#Override
public void onChanged(CharSequence charSequence) {
if (charSequence != null) {
txt.setText(charSequence);
}
}
});
}
...
I am not sure if I should pass the MutableLiveData from the viewModel to the Repository.
Is there any recommended way to let viewModel know that data is ready to be published from Repository??
I have read a lot of questions and articles and still I don't get it. I would love if somebody explain to me a nice way to achieve it!
Api
public interface TodoApi {
#GET("todos/")
Call<List<Todo>> getTodos();
#GET("todos/{id}")
Call<Todo> getTodo(#Path("id") long id);
}
Respository
public class TodoRepository {
private static final String TAG = "TodoRepository";
private static final TodoRepository ourInstance = new TodoRepository();
private TodoApi api;
private MutableLiveData<List<Todo>> todoListLiveData = new MutableLiveData<>();
private MutableLiveData<Todo> todoLiveData = new MutableLiveData<>();
public static TodoRepository getInstance() {
return ourInstance;
}
private TodoRepository() {
api = ApiBuilder.create(TodoApi.class);
}
public LiveData<List<Todo>> getTodos() {
api.getTodos().enqueue(new Callback<List<Todo>>() {
#Override
public void onResponse(#NonNull Call<List<Todo>> call, #NonNull Response<List<Todo>> response) {
todoListLiveData.setValue(response.body());
}
#Override
public void onFailure(#NonNull Call<List<Todo>> call, #NonNull Throwable t) {
Log.d(TAG, "onFailure: failed to fetch todo list from server");
}
});
return todoListLiveData;
}
public LiveData<Todo> getTodo(long id) {
api.getTodo(id).enqueue(new Callback<Todo>() {
#Override
public void onResponse(#NonNull Call<Todo> call, #NonNull Response<Todo> response) {
todoLiveData.setValue(response.body());
}
#Override
public void onFailure(#NonNull Call<Todo> call, #NonNull Throwable t) {
Log.d(TAG, "onFailure: failed to get todo");
}
});
return todoLiveData;
}
}
ViewModel
public class MainActivityViewModel extends ViewModel {
private static final String TAG = "MainActivityViewModel";
private TodoRepository repository = TodoRepository.getInstance();
private MutableLiveData<Boolean> isLoading = new MutableLiveData<>();
private LiveData<List<Todo>> todoLiveData;
public MainActivityViewModel() {
super();
isLoading.setValue(true);
todoLiveData = repository.getTodos();
}
#Override
protected void onCleared() {
super.onCleared();
}
public MutableLiveData<Boolean> getIsLoading() {
return isLoading;
}
public LiveData<List<Todo>> getTodoLiveData() {
return todoLiveData;
}
}
View
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
todoListRecyclerView = findViewById(R.id.todo_recycler_view);
loadingIndicator = findViewById(R.id.todo_loading_indicator);
mViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
getSupportActionBar().setTitle("Todos");
mViewModel.getIsLoading().observe(this, new Observer<Boolean>() {
#Override
public void onChanged(Boolean isLoading) {
if (isLoading) loadingIndicator.setVisibility(View.VISIBLE);
else loadingIndicator.setVisibility(View.GONE);
}
});
mViewModel.getTodoLiveData().observe(this, new Observer<List<Todo>>() {
#Override
public void onChanged(List<Todo> todos) {
mViewModel.getIsLoading().postValue(false);
initRecyclerView(todos);
}
});
}
For full sample
https://github.com/AnvarNazar/RetrofitTypicodeApiExample
I have searched the internet and notice this problem hasn't been solved. About two questions on this has also been asked but not related to my problem and i guess their questions wasn't structured well.
I use firebase to authenticate users on my app and upload a picture. But when a user wants to change or add a picture, the app crashes.
Obviously, the App generates Profile Picture from the account when the user signs in with a social network account (gmail or facebook) but uses default when logged in or registered directly.
This is my code, Kindly Help check if there is something i am doing wrong.
package com.classic.classic.profile.presenter;
import android.graphics.Bitmap;
import android.widget.TextView;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.storage.StorageReference;
import com.classic.classic.login.data_model.Authentication;
import com.classic.classic.login.service.LoginService;
import com.classic.classic.navigation.ProfileNavigator;
import com.classic.classic.profile.service.ProfileService;
import com.classic.classic.profile.view.ProfileDisplayer;
import com.classic.classic.storage.StorageService;
import com.classic.classic.user.data_model.User;
import com.classic.classic.user.service.UserService;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Action1;
/**
* Created by Debasis on 14/01/17.
*/
public class ProfilePresenter {
private final LoginService loginService;
private final UserService userService;
private final ProfileService profileService;
private final StorageService storageService;
private final ProfileDisplayer profileDisplayer;
private final ProfileNavigator navigator;
private User self;
private Subscription loginSubscription;
private Subscription userSubscription;
private String userImage;
private StorageReference desertRef;
public ProfilePresenter(LoginService loginService,
UserService userService,
ProfileService profileService,
StorageService storageService,
ProfileDisplayer loginDisplayer,
ProfileNavigator navigator) {
this.loginService = loginService;
this.userService = userService;
this.profileService = profileService;
this.storageService = storageService;
this.profileDisplayer = loginDisplayer;
this.navigator = navigator;
}
public void startPresenting() {
navigator.attach(dialogListener);
profileDisplayer.attach(actionListener);
loginSubscription = loginService.getAuthentication()
.subscribe(new Action1<Authentication>() {
#Override
public void call(final Authentication authentication) {
if (authentication.isSuccess()) {
userService.getUser(authentication.getUser().getUid())
.subscribe(new Subscriber<User>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(User user) {
self = user;
profileDisplayer.display(user);
}
});
} else {
navigator.toParent();
}
}
});
}
public void stopPresenting() {
navigator.detach(dialogListener);
profileDisplayer.detach(actionListener);
loginSubscription.unsubscribe();
if (userSubscription != null)
userSubscription.unsubscribe();
}
private ProfileDisplayer.ProfileActionListener actionListener = new ProfileDisplayer.ProfileActionListener() {
#Override
public void onUpPressed() {
navigator.toParent();
}
#Override
public void onNamePressed(String hint, TextView textView) {
navigator.showNameTextDialog(hint,textView,self);
}
#Override
public void onStatusPressed(String hint, TextView textView) {
navigator.showStatusextDialog(hint,textView,self);
}
#Override
public void onPasswordPressed(String hint) {
navigator.showInputPasswordDialog(hint,self);
}
#Override
public void onImagePressed() {
navigator.showImagePicker();
}
#Override
public void onSavePressed() {
navigator.showSaveDialog();
}
#Override
public void onRemovePressed() {
navigator.showRemoveDialog();
}
};
private ProfileNavigator.ProfileDialogListener dialogListener = new ProfileNavigator.ProfileDialogListener() {
#Override
public void onNameSelected(String text, User user) {
userService.setName(user,text);
}
#Override
public void onStatusSelected(String text, User user) {
userService.setStatus(user,text);
}
#Override
public void onPasswordSelected(String text) {
profileService.setPassword(text);
}
#Override
public void onRemoveSelected() {
profileService.removeUser();
}
#Override
public void onImageSelected(final Bitmap bitmap) {
userImage = self.getImage();
if(bitmap != null) {
if (userImage.length() != 0 && !userImage.equals("") && userImage != null) {
if(!userImage.startsWith("https://")) {
desertRef = storageService.getProfileImageReference(userImage);
desertRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
storageService.uploadImage(bitmap)
.subscribe(new Action1<String>() {
#Override
public void call(final String image) {
if (image != null) {
profileDisplayer.updateProfileImage(bitmap);
userService.setProfileImage(self, image);
}
}
});
}
});
}else{
storageService.uploadImage(bitmap)
.subscribe(new Action1<String>() {
#Override
public void call(final String image) {
if (image != null) {
profileDisplayer.updateProfileImage(bitmap);
userService.setProfileImage(self, image);
}
}
});
}
} else {
storageService.uploadImage(bitmap)
.subscribe(new Action1<String>() {
#Override
public void call(final String image) {
if (image != null) {
profileDisplayer.updateProfileImage(bitmap);
userService.setProfileImage(self, image);
}
}
});
}
} else {
if (userImage.length() != 0 && !userImage.equals("") && userImage != null) {
if(!userImage.startsWith("https://")) {
desertRef = storageService.getProfileImageReference(userImage);
desertRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
String img = "";
userService.setProfileImage(self, img);
}
});
} else {
String img = "";
userService.setProfileImage(self, img);
}
}
}
}
};
}
I am using quickblox for my android application. I am able to register, login user, even add custom objects and retrieve them from the quick-blox server, but in chatting listing screen my count is coming wrong.
I am getting issue with unread count
Here is my code flow:-
public class ConversationFragment extends Fragment implements Observer, DialogsManager.ManagingDialogsCallbacks {
ConversationViewModel conversationViewModel;
FragmentConversationBinding binding;
QBChatDialogMessageListener allDialogsMessagesListener;
SystemMessagesListener systemMessagesListener;
QBSystemMessagesManager systemMessagesManager;
QBIncomingMessagesManager incomingMessagesManager;
private DialogsManager dialogsManager;
public ConversationFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_conversation, container, false);
getActivity().getWindow().setBackgroundDrawableResource(R.drawable.bg_img);
View view = binding.getRoot();
systemMessagesListener = new SystemMessagesListener();
dialogsManager = new DialogsManager();
return view;
}
private void setUpModel() {
Bundle mBundle = getArguments();
if (mBundle != null) {
conversationViewModel = new ConversationViewModel(getActivity(), binding, getArguments().getString("DialogIdData"));
} else {
conversationViewModel = new ConversationViewModel(getActivity(), binding, "");
}
binding.setConversationViewModel(conversationViewModel);
setUpObserver(conversationViewModel);
}
private void setUpObserver(ConversationViewModel observer) {
observer.addObserver(this);
}
#Override
public void update(Observable o, Object arg) {
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onResume() {
super.onResume();
setUpModel();
}
#Override
public void onPause() {
super.onPause();
unregisterQbChatListeners();
}
public void unregisterQbChatListeners() {
if (incomingMessagesManager != null) {
incomingMessagesManager.removeDialogMessageListrener(allDialogsMessagesListener);
}
if (systemMessagesManager != null) {
systemMessagesManager.removeSystemMessageListener(systemMessagesListener);
}
dialogsManager.removeManagingDialogsCallbackListener(this);
}
#Override
public void onDialogCreated(QBChatDialog chatDialog) {
}
#Override
public void onDialogUpdated(String chatDialog) {
}
#Override
public void onNewDialogLoaded(QBChatDialog chatDialog) {
}
private class SystemMessagesListener implements QBSystemMessageListener {
#Override
public void processMessage(final QBChatMessage qbChatMessage) {
dialogsManager.onSystemMessageReceived(qbChatMessage);
}
#Override
public void processError(QBChatException e, QBChatMessage qbChatMessage) {
}
}
private BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
}
Here is my Fragment viewModel code :-
public class ConversationViewModel extends Observable implements DialogsManager.ManagingDialogsCallbacks {
private static final int REQUEST_DIALOG_ID_FOR_UPDATE = 165;
public Context mContext;
FragmentConversationBinding binding;
private ActionMode currentActionMode;
public QBRequestGetBuilder requestBuilder;
private int skipRecords = 0;
private DialogsAdapter dialogsAdapter;
private QBChatDialogMessageListener allDialogsMessagesListener;
private SystemMessagesListener systemMessagesListener;
private QBSystemMessagesManager systemMessagesManager;
private QBIncomingMessagesManager incomingMessagesManager;
private DialogsManager dialogsManager;
private QBUser currentUser;
private String id;
public ConversationViewModel(Context mContext, FragmentConversationBinding binding, String Dialogid) {
this.mContext = mContext;
this.binding = binding;
this.id = Dialogid;
initUI();
}
public void initUI() {
allDialogsMessagesListener = new AllDialogsMessageListener();
systemMessagesListener = new SystemMessagesListener();
dialogsManager = new DialogsManager();
currentUser = ChatHelper.getCurrentUser();
initList();
registerQbChatListeners();
if (QbDialogHolder.getInstance().getDialogs().size() > 0) {
loadDialogsFromQb(true, true);
} else {
loadDialogsFromQb(false, true);
}
if (!id.isEmpty()) {
loadUpdatedDialog(id);
id = "";
} else {
updateDialogsList();
}
}
public void initList() {
dialogsAdapter = new DialogsAdapter(mContext, new ArrayList<>(QbDialogHolder.getInstance().getDialogs().values()));
binding.listDialogsChats.setAdapter(dialogsAdapter);
binding.listDialogsChats.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
QBChatDialog selectedDialog = (QBChatDialog) parent.getItemAtPosition(position);
if (currentActionMode == null) {
ChatActivity.startForResult(((Activity) mContext), REQUEST_DIALOG_ID_FOR_UPDATE, selectedDialog);
} else {
dialogsAdapter.toggleSelection(selectedDialog);
}
}
});
binding.listDialogsChats.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
QBChatDialog selectedDialog = (QBChatDialog) parent.getItemAtPosition(position);
dialogsAdapter.selectItem(selectedDialog);
return true;
}
});
requestBuilder = new QBRequestGetBuilder();
binding.swipyRefreshLayout.setOnRefreshListener(new SwipyRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh(SwipyRefreshLayoutDirection direction) {
requestBuilder.setSkip(skipRecords += ChatHelper.DIALOG_ITEMS_PER_PAGE);
loadDialogsFromQb(true, false);
}
});
}
private void loadUpdatedDialog(String dialogId) {
ChatHelper.getInstance().getDialogById(dialogId, new QbEntityCallbackImpl<QBChatDialog>() {
#Override
public void onSuccess(QBChatDialog result, Bundle bundle) {
QbDialogHolder.getInstance().addDialog(result);
updateDialogsAdapter();
}
#Override
public void onError(QBResponseException e) {
}
});
}
public void updateDialogsList() {
requestBuilder.setSkip(skipRecords = 0);
loadDialogsFromQb(true, true);
}
#Override
public void onDialogCreated(QBChatDialog chatDialog) {
updateDialogsAdapter();
}
#Override
public void onDialogUpdated(String chatDialog) {
updateDialogsAdapter();
}
#Override
public void onNewDialogLoaded(QBChatDialog chatDialog) {
updateDialogsAdapter();
}
private void registerQbChatListeners() {
incomingMessagesManager = QBChatService.getInstance().getIncomingMessagesManager();
systemMessagesManager = QBChatService.getInstance().getSystemMessagesManager();
if (incomingMessagesManager != null) {
incomingMessagesManager.addDialogMessageListener(allDialogsMessagesListener != null
? allDialogsMessagesListener : new AllDialogsMessageListener());
}
if (systemMessagesManager != null) {
systemMessagesManager.addSystemMessageListener(systemMessagesListener != null
? systemMessagesListener : new SystemMessagesListener());
}
dialogsManager.addManagingDialogsCallbackListener(this);
}
private class SystemMessagesListener implements QBSystemMessageListener {
#Override
public void processMessage(final QBChatMessage qbChatMessage) {
dialogsManager.onSystemMessageReceived(qbChatMessage);
}
#Override
public void processError(QBChatException e, QBChatMessage qbChatMessage) {
}
}
private class AllDialogsMessageListener extends QbChatDialogMessageListenerImp {
#Override
public void processMessage(final String dialogId, final QBChatMessage qbChatMessage, Integer senderId) {
if (!senderId.equals(ChatHelper.getCurrentUser().getId())) {
dialogsManager.onGlobalMessageReceived(dialogId, qbChatMessage);
}
}
}
public void updateDialogsAdapter() {
dialogsAdapter.updateList(new ArrayList<>(QbDialogHolder.getInstance().getDialogs().values()));
}
public void loadDialogsFromQb(final boolean silentUpdate, final boolean clearDialogHolder) {
if (!silentUpdate) {
binding.progressDialogs.setVisibility(View.VISIBLE);
}
ChatHelper.getInstance().getDialogs(requestBuilder, new QBEntityCallback<ArrayList<QBChatDialog>>() {
#Override
public void onSuccess(ArrayList<QBChatDialog> dialogs, Bundle bundle) {
binding.progressDialogs.setVisibility(View.GONE);
binding.swipyRefreshLayout.setRefreshing(false);
if (clearDialogHolder) {
QbDialogHolder.getInstance().clear();
}
QbDialogHolder.getInstance().addDialogs(dialogs);
updateDialogsAdapter();
}
#Override
public void onError(QBResponseException e) {
binding.progressDialogs.setVisibility(View.GONE);
binding.swipyRefreshLayout.setRefreshing(false);
Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
Here is my Chat Activity:-
public class ChatActivity extends BindingActivity<ActivityChatBinding> implements OnImagePickedListener {
ChatViewModel chatViewModel;
public static final int REQUEST_CODE_ATTACHMENT = 721;
public static final String EXTRA_DIALOG_ID = "dialogId";
#Override
protected int getLayoutId() {
return R.layout.activity_chat;
}
public static void startForResult(Activity activity, int code, QBChatDialog dialogId) {
Intent intent = new Intent(activity, ChatActivity.class);
intent.putExtra(ChatActivity.EXTRA_DIALOG_ID, dialogId);
activity.startActivityForResult(intent, code);
}
#Override
public void setInitBinding() {
getWindow().setBackgroundDrawableResource(R.drawable.bg_img);
chatViewModel = new ChatViewModel(this, binding);
binding.setChatViewModel(chatViewModel);
}
#Override
protected void setUpObserver() {
chatViewModel.addObserver(this);
}
#Override
public void update(Observable o, Object arg) {
}
#Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
#Override
public void onBackPressed() {
binding.getChatViewModel().releaseChat();
binding.getChatViewModel().sendDialogId();
super.onBackPressed();
}
#Override
public void onImagePicked(int requestCode, File file) {
switch (requestCode) {
case REQUEST_CODE_ATTACHMENT:
binding.getChatViewModel().attachmentPreviewAdapter.add(file);
break;
}
}
#Override
public void onImagePickError(int requestCode, Exception e) {
Toast.makeText(this, e.toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onImagePickClosed(int requestCode) {
}
}
Chat Activity View Model :-
public class ChatViewModel extends Observable {
public Context mContext;
ActivityChatBinding binding;
public static final String TAG = ChatActivity.class.getSimpleName();
public static final int REQUEST_CODE_ATTACHMENT = 721;
public static final String PROPERTY_SAVE_TO_HISTORY = "save_to_history";
public static final String EXTRA_DIALOG_ID = "dialogId";
public ChatAdapter chatAdapter;
public AttachmentPreviewAdapter attachmentPreviewAdapter;
public QBChatDialog qbChatDialog;
public ArrayList<QBChatMessage> unShownMessages;
public int skipPagination = 0;
public ChatMessageListener chatMessageListener;
QBPrivacyList qbPrivacyList;
public static boolean mBlock;
public static int userId, recipientId;
public QBPrivacyListsManager privacyListsManager;
public ObservableField<String> chatMessage = new ObservableField<>("");
public ChatViewModel(Context mContext, ActivityChatBinding binding) {
this.mContext = mContext;
this.binding = binding;
Log.v(TAG, "onCreate ChaActivity on Thread ID = " + Thread.currentThread().getId());
qbChatDialog = (QBChatDialog) ((Activity) mContext).getIntent().getSerializableExtra(EXTRA_DIALOG_ID);
Log.v(TAG, "deserialized dialog = " + qbChatDialog);
qbChatDialog.initForChat(QBChatService.getInstance());
chatMessageListener = new ChatMessageListener();
qbPrivacyList = new QBPrivacyList();
privacyListsManager = QBChatService.getInstance().getPrivacyListsManager();
qbChatDialog.addMessageListener(chatMessageListener);
initViews();
initChat();
}
public void initViews() {
try {
recipientId = qbChatDialog.getRecipientId();
userId = qbChatDialog.getUserId();
getPrivacyList();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
}
attachmentPreviewAdapter = new AttachmentPreviewAdapter(mContext,
new AttachmentPreviewAdapter.OnAttachmentCountChangedListener() {
#Override
public void onAttachmentCountChanged(int count) {
binding.attachmentContainer.setVisibility(count == 0 ? View.GONE : View.VISIBLE);
}
},
new AttachmentPreviewAdapter.OnAttachmentUploadErrorListener() {
#Override
public void onAttachmentUploadError(QBResponseException e) {
Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
}
});
binding.attachmentAdapter.setAdapter(attachmentPreviewAdapter);
}
public void onAttachmentsClick(View view) {
new ImagePickHelper().pickAnImage(((FragmentActivity) mContext), REQUEST_CODE_ATTACHMENT);
}
private void initChat() {
switch (qbChatDialog.getType()) {
case PRIVATE:
loadDialogUsers();
break;
default:
Toaster.shortToast(String.format("%s %s", getString(R.string.chat_unsupported_type), qbChatDialog.getType().name()));
((Activity) mContext).finish();
break;
}
}
public void loadDialogUsers() {
ChatHelper.getInstance().getUsersFromDialog(qbChatDialog, new QBEntityCallback<ArrayList<QBUser>>() {
#Override
public void onSuccess(ArrayList<QBUser> users, Bundle bundle) {
String chatName = QbDialogUtils.getDialogName(qbChatDialog);
binding.dialogName.setText(chatName);
loadChatHistory();
}
#Override
public void onError(QBResponseException e) {
Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
}
});
}
public void loadChatHistory() {
ChatHelper.getInstance().loadChatHistory(qbChatDialog, skipPagination, new QBEntityCallback<ArrayList<QBChatMessage>>() {
#Override
public void onSuccess(ArrayList<QBChatMessage> messages, Bundle args) {
Collections.reverse(messages);
if (chatAdapter == null) {
chatAdapter = new ChatAdapter(mContext, qbChatDialog, messages);
chatAdapter.setPaginationHistoryListener(new PaginationHistoryListener() {
#Override
public void downloadMore() {
loadChatHistory();
}
});
chatAdapter.setOnItemInfoExpandedListener(new ChatAdapter.OnItemInfoExpandedListener() {
#Override
public void onItemInfoExpanded(final int position) {
if (isLastItem(position)) {
((Activity) mContext).runOnUiThread(new Runnable() {
#Override
public void run() {
binding.listChat.setSelection(position);
}
});
} else {
binding.listChat.smoothScrollToPosition(position);
}
}
private boolean isLastItem(int position) {
return position == chatAdapter.getCount() - 1;
}
});
if (unShownMessages != null && !unShownMessages.isEmpty()) {
List<QBChatMessage> chatList = chatAdapter.getList();
for (QBChatMessage message : unShownMessages) {
if (!chatList.contains(message)) {
chatAdapter.add(message);
}
}
}
binding.listChat.setAdapter(chatAdapter);
binding.listChat.setAreHeadersSticky(false);
binding.listChat.setDivider(null);
} else {
chatAdapter.addList(messages);
binding.listChat.setSelection(messages.size());
}
binding.progressBar.setVisibility(View.GONE);
}
#Override
public void onError(QBResponseException e) {
binding.progressBar.setVisibility(View.GONE);
skipPagination -= ChatHelper.CHAT_HISTORY_ITEMS_PER_PAGE;
Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
}
});
skipPagination += ChatHelper.CHAT_HISTORY_ITEMS_PER_PAGE;
QBRestChatService.markMessagesAsRead(qbChatDialog.getDialogId(), null);
}
public class ChatMessageListener extends QbChatDialogMessageListenerImp {
#Override
public void processMessage(String s, QBChatMessage qbChatMessage, Integer integer) {
showMessage(qbChatMessage);
}
}
public void showMessage(QBChatMessage message) {
if (chatAdapter != null) {
chatAdapter.add(message);
scrollMessageListDown();
} else {
if (unShownMessages == null) {
unShownMessages = new ArrayList<>();
}
unShownMessages.add(message);
}
}
public void scrollMessageListDown() {
binding.listChat.setSelection(binding.listChat.getCount() - 1);
}
public void onSendChatClick(View view) {
int totalAttachmentsCount = attachmentPreviewAdapter.getCount();
Collection<QBAttachment> uploadedAttachments = attachmentPreviewAdapter.getUploadedAttachments();
if (!uploadedAttachments.isEmpty()) {
if (uploadedAttachments.size() == totalAttachmentsCount) {
for (QBAttachment attachment : uploadedAttachments) {
sendChatMessage(null, attachment);
}
} else {
Toaster.shortToast(R.string.chat_wait_for_attachments_to_upload);
}
}
String text = binding.getChatViewModel().chatMessage.get().trim();
if (!TextUtils.isEmpty(text)) {
sendChatMessage(text, null);
}
}
public void sendChatMessage(String text, QBAttachment attachment) {
QBChatMessage chatMessage = new QBChatMessage();
if (attachment != null) {
chatMessage.addAttachment(attachment);
} else {
chatMessage.setBody(text);
}
chatMessage.setProperty(PROPERTY_SAVE_TO_HISTORY, "1");
chatMessage.setDateSent(System.currentTimeMillis() / 1000);
chatMessage.setMarkable(true);
if (!QBDialogType.PRIVATE.equals(qbChatDialog.getType()) && !qbChatDialog.isJoined()) {
Toaster.shortToast("You're still joining a group chat, please wait a bit");
return;
}
try {
qbChatDialog.sendMessage(chatMessage);
if (QBDialogType.PRIVATE.equals(qbChatDialog.getType())) {
showMessage(chatMessage);
}
if (attachment != null) {
attachmentPreviewAdapter.remove(attachment);
} else {
binding.getChatViewModel().chatMessage.set("");
}
} catch (SmackException.NotConnectedException e) {
Log.w(TAG, e);
Toaster.shortToast("Can't send a message, You are not connected to chat");
}
}
public void leaveGroupDialog() {
try {
ChatHelper.getInstance().leaveChatDialog(qbChatDialog);
} catch (XMPPException | SmackException.NotConnectedException e) {
Log.w(TAG, e);
}
}
public void releaseChat() {
qbChatDialog.removeMessageListrener(chatMessageListener);
if (!QBDialogType.PRIVATE.equals(qbChatDialog.getType())) {
leaveGroupDialog();
}
}
public void sendDialogId() {
Intent result = new Intent();
result.putExtra(EXTRA_DIALOG_ID, qbChatDialog.getDialogId());
((Activity) mContext).setResult(RESULT_OK, result);
}
public void finishActivity(View view) {
((Activity) mContext).finish();
}
public void clickButtonBlock(View view) {
AppUtils.dialog(mContext);
if (mBlock) {
onClickUnblock();
} else {
onClickBlock();
}
}
public void getPrivacyList() throws SmackException.NotConnectedException, XMPPException.XMPPErrorException, SmackException.NoResponseException {
QBPrivacyListsManager privacyListsManager = QBChatService.getInstance().getPrivacyListsManager();
QBPrivacyList privacyList = privacyListsManager.getPrivacyList("public");
List<QBPrivacyListItem> items = privacyList.getItems();
int i;
for (i = 0; i < privacyList.getItems().size(); i++) {
QBPrivacyListItem item = items.get(i);
String valueForType = item.getValueForType();
String[] splitvalueType = valueForType.split("-");
String blockId = splitvalueType[0];
if (blockId.equalsIgnoreCase(String.valueOf(recipientId))) {
mBlock = true;
binding.tvBlock.setText("Unblock");
break;
} else {
binding.tvBlock.setText("Block");
}
}
}
}
The problem is chatDialog.getUnreadMessageCount() giving me count 2 when I once enter in chat room and come back to my chat listing page.
Description on issue:-
Example:-
I have installed my application in two devices. when i send message from one (Device A) to other (Device B).The device B will display correct Unread count i.e 1 . Now when i click on chat dialog and get entered inside the chat room (of Device B). and come back to it's listing page and then again try to send message from Device A to device B . This time the unread count comes as 2 but it should be one as i already viewed my previous message. This get more worse if i try to open my chat room again to read the message(Device B) and get back to my listing page(Device B) after reading the message . This time if I send the message from Device A to Device B, Then the count came out as "5" just for my one message this thing is making me sick, I debugged the whole code, it's chatDialog .getUnreadMessageCount() who is returning me count "5", I don't know why my previous messages are not counted as being read messages and why everytime I open chat room one additional number gets added up inside the unread count.Please help me out , i am scratching my head from past two days.
Your help will be greatly Appreciated.
Thanks
Problem is that your AllDialogsMessageListener is not getting unregistered so unregister it by calling unregisterQbChatListeners(); when you will be opening your chat room screen . Every thing will work fine once you do that.
This what i mean :-
binding.listDialogsChats.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
QBChatDialog selectedDialog = (QBChatDialog) parent.getItemAtPosition(position);
if (currentActionMode == null) {
unregisterQbChatListeners();
ChatActivity.startForResult(((Activity) mContext), REQUEST_DIALOG_ID_FOR_UPDATE, selectedDialog);
} else {
dialogsAdapter.toggleSelection(selectedDialog);
}
}
});
private void unregisterQbChatListeners() {
if (incomingMessagesManager != null) {
incomingMessagesManager.removeDialogMessageListrener(allDialogsMessagesListener);
}
if (systemMessagesManager != null) {
systemMessagesManager.removeSystemMessageListener(systemMessagesListener);
}
dialogsManager.removeManagingDialogsCallbackListener(this);
}
cheers!!!
Please use this code below :
QBChatService.markMessagesAsRead("YOUR_DIALOG_ID", null, new QBEntityCallback<Void>() {
#Override
public void onSuccess(Void aVoid, Bundle bundle) {
QBRequestGetBuilder requestBuilder = new QBRequestGetBuilder();
requestBuilder.eq("_id", Team.getCurrent().getChatId());
QBChatService.getChatDialogs(null, requestBuilder, new QBEntityCallback<ArrayList<QBDialog>>() {
#Override
public void onSuccess(ArrayList<QBDialog> qbDialogs, Bundle bundle) {
if (qbDialogs != null && qbDialogs.size() > 0) {
QBDialog dialog = qbDialogs.get(0);//here you get your dialog with unreadMessageCount = 0
}
}
#Override
public void onError(QBResponseException e) {
}
});
}
#Override
public void onError(QBResponseException e) {
}
});
I'm buliding a simple android app, and i got this error when i try to send data to API. I use RxJava and Retrofit, and I use Model View Presenter.
I got this error "btnservice is a null object reference"
I always got btnservice null, please help to solve this.
Thank you
This the JSON
request:
{
name: '',
mobile: '',
email: ''
}
This my BaseActivtiy
public abstract class BaseActivity extends AppCompatActivity {
#BindString(R.string.loading)
public String loading;
#BindInt(R.integer.success_code)
public int successCode;
#BindInt(R.integer.success_activication_code)
public int activicationSuccessCode;
protected BTNService btnService;
protected abstract int getLayout();
private ProgressDialog progressDialog;
private CompositeSubscription subscriptions;
protected RxBus bus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayout());
Icepick.restoreInstanceState(this, savedInstanceState);
ButterKnife.bind(this);
this.progressDialog = new ProgressDialog(this);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Icepick.saveInstanceState(this, outState);
}
#Override
protected void onStart() {
super.onStart();
this.subscriptions = new CompositeSubscription();
}
#Override
public void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
this.progressDialog.dismiss();
}
public BTNService getBTNService() {
return btnService;
}
public RxBus getBus() {
return bus;
}
public void showProgressDialog(String message) {
if (progressDialog != null) {
progressDialog.setMessage(message);
progressDialog.show();
}
}
public void dismissProgressDialog() {
progressDialog.hide();
}
public boolean isFragmentNotNull(String tag) {
if (getSupportFragmentManager().findFragmentByTag(tag) != null) {
return true;
} else {
return false;
}
}
public boolean isFragmentVisible(String tag) {
if (isFragmentNotNull(tag)
&& getSupportFragmentManager().findFragmentByTag(tag).isVisible()) {
return true;
} else {
return false;
}
}
}
This my BaseFragment
public abstract class BaseFragment extends Fragment implements Validator.ValidationListener {
#BindString(R.string.loading)
public String loading;
#BindInt(R.integer.success_code)
public int successCode;
#BindInt(R.integer.success_activication_code)
public int activicationSuccessCode;
#BindString(R.string.connection_error)
public String connectionError;
protected abstract int getLayout();
protected Validator validator;
private CompositeSubscription subscriptions;
protected RxBus bus;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.bus = ((BaseActivity) getActivity()).getBus();
}
#Override
public void onStart() {
super.onStart();
this.subscriptions = new CompositeSubscription();
/* this.subscriptions
.add(bus.toObserverable()
.subscribe(new Action1<Object>() {
#Override
public void call(Object event) {
if (event instanceof RxBusObject) {
RxBusObject busObject = (RxBusObject) event;
busHandler();
}
}
})
);*/
}
#Override
public void onStop() {
super.onStop();
this.subscriptions.clear();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(getLayout(), container, false);
ButterKnife.bind(this, view);
return view;
}
public RxBus getBus() {
return this.bus;
}
#Override
public void onValidationSucceeded() {
}
#Override
public void onValidationFailed(List<ValidationError> errors) {
for (ValidationError error : errors) {
View view = error.getView();
String message = error.getCollatedErrorMessage(getActivity());
if (view instanceof EditText) {
EditText et = ((EditText) view);
et.setError(message);
et.requestFocus();
} else {
Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
}
}
}
public void showSuccessDialog(String message, final Boolean isFinishActivity) {
new MaterialDialog.Builder(getActivity())
.iconRes(R.mipmap.ic_launcher)
.title(getString(R.string.success).toUpperCase())
.titleColor(Color.WHITE)
.content(message)
.contentColor(Color.WHITE)
.positiveText(R.string.ok)
.positiveColor(Color.WHITE)
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(MaterialDialog dialog, DialogAction which) {
if (isFinishActivity) {
getActivity().finish();
}
}
})
.cancelable(false)
.show();
}
public void showProgressDialog(String message) {
((BaseActivity) getActivity()).showProgressDialog(message);
}
public Validator getValidator() {
return validator;
}
public BTNService.Api getApi() {
return ((BaseActivity) getActivity()).getBTNService().getApi();
}
public void dismissProgressDialog() {
((BaseActivity) getActivity()).dismissProgressDialog();
}
}
This my Retrofit Class
public BTNService(Context context) {
if (retrofit==null) {
Retrofit retrofit = new Retrofit.Builder()
.client(provideOkHttpClient(context))
.baseUrl(BASE_URL)
.build();
this.api = retrofit.create(Api.class);
}
}
private OkHttpClient provideOkHttpClient(final Context context) {
HttpLoggingInterceptor httpLoggingInterceptorinterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptorinterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(httpLoggingInterceptorinterceptor);
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
return response;
}
});
return httpClient.build();
}
public Api getApi() {
return api;
}
public interface Api {
#POST(PORTAL_URL + "customer/register")
Observable<SignUpResponse> regsiterCustomer(#Path("email") String Email,
#Path("name") String Name,
#Path("mobile") String PhoneNumber);
}
and this my Presenter
public class SignUpPresenter {
private SignUpFragment fragment;
public SignUpPresenter(SignUpFragment fragment) {
this.fragment = fragment;
}
public SignUpRequest constructSignUpRequest() {
SignUpRequest request = new SignUpRequest();
request.setName(getAndTrimValueFromEditText(fragment.etName));
request.setEmail(getAndTrimValueFromEditText(fragment.etEmail));
request.setMobile(getAndTrimValueFromEditText(fragment.etPhone));
return request;
}
private String getAndTrimValueFromEditText(EditText e) {
return e.getText().toString().trim();
}
void signup (){
this.register(constructSignUpRequest());
}
void register(final SignUpRequest signUpRequest) {
fragment.showProgressDialog(fragment.loading);
fragment.getApi().regsiterCustomer(
signUpRequest.getName(),
signUpRequest.getEmail(),
signUpRequest.getMobile())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<GenericResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
fragment.dismissProgressDialog();
Timber.e(e.getLocalizedMessage());
Toast.makeText(fragment.getContext(), fragment.connectionError, Toast.LENGTH_SHORT).show();
}
#Override
public void onNext(GenericResponse genericResponse) {
fragment.dismissProgressDialog();
Toast.makeText(fragment.getContext(), genericResponse.getInfo(), Toast.LENGTH_SHORT).show();
if (genericResponse.getCode() == fragment.successCode) {
/*fragment.gotoActivationCodeActivity(SignUpRequest.getEmail(), SignUpRequest.get());*/
fragment.gotoQuestionActivity(signUpRequest.getEmail(), signUpRequest.getEmail(), signUpRequest.getMobile());
}
}
});
}
public static <T> Function<BaseResponse<T>, Observable<T>> convertDataFlatMap() {
return new Function<BaseResponse<T>, Observable<T>>() {
#Override
public Observable<T> apply(BaseResponse<T> response) {
if (!Constants.SUCCESS_CODE.equals(response.getStatus_code())) {
BaseErrorResponse baseErrorResponse = new BaseErrorResponse();
baseErrorResponse.setError(response.getStatus_code(),
response.getStatus());
return Observable.error(BaseException.toServerError(baseErrorResponse));
}
T data = response.getData();
if (null == data) {
return Observable.empty();
}
return Observable.just(response.getData());
}
};
}
I'm using Rxjava 2, Maybe useful for you.