keeping data updated between two activities in android - java

How can I keep data updated between two android activities. I am working on a android album project where the mainactivity is album activity(where I can add remove and rename albums). But when the user clicks on one of the albums just created I start a intent with a photo activity where he can add remove and move photos. All the operations are done for the album in the photoactivity and I use serialization to write the data back to a text file in both activities. The problem is when I back out to the main activity from the photo activity making some changes on a particular album. The mainactivity doesn't know about the updates.
Code in main activity to start the photo intent on a particular album selected by user
albumGridView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
//Toast.makeText(MainActivity.this, "" + position, Toast.LENGTH_SHORT).show();
Intent photoIntent = new Intent(MainActivity.this, Photo.class);
photoIntent.putExtra("userNode", user);
photoIntent.putExtra("position", position);
startActivity(photoIntent);
// Toast.makeText(MainActivity.this, position, Toast.LENGTH_SHORT).show();
}
});
You see I pass in the user object which is linkedlists of all album and photo nodes which added removed or moved. It is basically the entire user data of the that user. So whenever I start the old reference of the user node is passed on to the photo intent. I have implemented readerUser() and writeUser methods using serialization. I need to keep the reference of the user object in the main activity updated with all the changes in the photo activity..

Use contentProvider to provide unique access to your photo data and implement an Observer design pattern. That is , in on side, inside the the ContentProvider, when dataset changed due to insert ,update,or delete, notify the the contentResolver;on the other side, user has to register the notification by calling getContentResolover().registerContentObserver
Check out those links:
http://developer.android.com/reference/android/content/ContentProvider.html
http://developer.android.com/reference/android/content/ContentResolver.html
http://mylifewithandroid.blogspot.com/2008/03/observing-content.html

Look into implementing an Android Application. The Application class essentially gives you a GUI-less activity that remains constant for the duration of your session. Instead of serializing objects (slow, excess overhead), you can just call a method on your Application to save images to a data structure in the Application.
Using an Application means that any of your normal Activities can obtain a reference to the Application singleton and access any field or method which you expose.
Read the offical doc and do a Google search for some implementation examples, of which there are many.

I think what you need is database. Use sqlite http://developer.android.com/reference/android/database/sqlite/package-summary.html .
That is guessing you also want the data persisted and restored when the application is run a second time.

Implement broadcast receivers.
http://developer.android.com/reference/android/content/BroadcastReceiver.html

I used as #Vegito1044 proposed a local BroadcastReceiver in the main Activity that can be triggered from other activities. The relevant code for this looks like this:
public class AlbumActivity extends Activity {
private BroadcastReceiver myReceiver = null;
class _AlbumUpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
Log.i(Global.LOG_CONTEXT, "AlbumActivity.onReceive(intent='" + intent + "')");
reloadGui();
}
}
#Override
public void onResume() {
super.onResume();
if (myReceiver == null)
{
myReceiver = new _AlbumUpdateReceiver();
IntentFilter filter = new IntentFilter(Global.REFRESH_GUI);
registerReceiver(myReceiver, filter);
}
reloadGui();
}
#Override
public void onPause() {
if (myReceiver != null)
{
unregisterReceiver(myReceiver);
myReceiver = null;
}
super.onPause();
}
void reloadGui()
{
Log.d(Global.LOG_CONTEXT, "AlbumActivity.refreshGui()");
... do what is neccessary to update gui
}
}

Related

How can I turn off localbroadcast listener in recyclerview adapter? Of is there a better way to communicate with an activity called from it?

I'm new to SO and fairly new to coding, so please accept my apologies in advance if I break rules or expectations here.
I have an unusual setup involving two recyclerViews, which I'll explain here and also paste a simplified version of the code below (as there is so much not relevant to this question).
In what I'll call verticalRecyclerViewActivity, a verticalRecyclerViewAdapter is called, with data it fetches from Firebase and loads into arrayLists.
If the user clicks on an item in the vertical recyclerview, a new dialog fragment which I'll call horizontalRecyclerViewDialogFragment is inflated, and that loads what I'll call horizontalRecyclerView (which has similar items to the vertical one, in more detail, with options to click on them to review them).
If the user clicks on an item in the horizontalRecyclerView, a new activity which I'll call reviewItem is started (through an Intent). When the user submits their review, it finishes and returns (through the backstack) to the horizontal RecyclerView. That can also happen if they press the back button without actually submitting a review. That all works fine, but I need the horizontalRecyclerView to show that they have (or haven't) reviewed the item and state the score they gave it in a review.
Calling notifyDataSetChanged won't work for this because of how information comes through two recyclerViews and Firebase calls (or, at least, it would be very inefficient).
I've tried using startActivityForResult (I know it's deprecated, but if I could get that to work I could try using the newer equivalent which I don't yet understand) but the problem is that the result is returned to the original (VerticalRecylcerView) activity, which is two recyclerView adapters and one fragment beneath what needs to be updated, and I don't know how to pass that data to the horizontal Recyclerview.
I've also tried using interfaces but was unable to pass it through the Intent (tried using Parcelable and Serializable, but it seems neither can work in this situation?).
Since the review is updated on Firebase, I could have the horizontal Recyclerview listen for a change, but that seems very inefficient?
So I've found a solution using localBroadcast (which I know is also deprecated). The Intent (with the review score) is transmitted when it is reviewed and received in the horizontal recyclerView adapter. But when and how should I unregister the adapter? Ideally the receiver would be turned on when the user goes to the Review activity and turned off once the user returns from that activity and the (horizontal) recyclerView holder is updated, whether the review is successfully submitted or whether the user just presses the back button and never submits a review.
My question is similar to this one: How to unregister and register BroadcastReceiver from another class?
That is noted as a duplicate of this one: How to unregister and register BroadcastReceiver from another class?
There's a lot in those questions I don't understand, but the important difference I think between their and my cases is that I would just like the receiver to know when a review is submitted, and ideally be unregistered then, or possibly when the viewHolder is recycled, which I tried but also didn't work since it's not connected to the viewHolder (should it be?).
Any help would be much appreciated, thank you!
public class verticalRecyclerViewActivity extends AppCompatActivity {
// Loads an XML file and assembles an array from Firebase.
mVerticalRecyclerView = findViewById(R.id.verticalRecyclerView);
verticalRecyclerViewAdaptor mVerticalRecyclerViewAdaptor = new verticalRecyclerViewAdaptor (this); // also pass other information it needs
mVerticalRecyclerView .setAdapter(mVerticalRecyclerViewAdaptor);
}
public class verticalRecyclerViewAdaptor extends RecyclerView.Adapter<verticalRecyclerViewAdaptor.singleHolder> {
// Usual recyclerView content
holder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
horizontalRecyclerViewFragment mHorizontalRecyclerViewFragment = new horizontalRecyclerViewFragment();
// lots of arguments passed it needs.
FragmentManager fragmentManager = ((FragmentActivity) view.getContext()).getSupportFragmentManager();
mHorizontalRecyclerViewFragment.show(fragmentManager, null);
}
public class mHorizontalRecyclerViewFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity().getApplicationContext(); // Not sure why I need this, but it works.
View horizontalRecyclerViewView = getActivity().getLayoutInflater().inflate(R.layout.horizontal_recyclerview_holder, new CardView(getActivity()), false);
Dialog horizontalRecyclerViewDialog = new Dialog(getActivity());
horizontalRecyclerViewDialog.setContentView(horizontalRecyclerViewView);
mHorizontalRecyclerView = horizontalRecyclerViewView.getRootView().findViewById(R.id.horizontalRecyclerView);
mHorizontalRecyclerViewAdapter = new horizontalRecyclerViewAdapter (mContext)
// Other arguments passed
mHorizontalRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(),
LinearLayoutManager.HORIZONTAL, false));
mHorizontalRecyclerView.setAdapter(mHorizontalRecyclerViewAdapter);
}
public class horizontalRecyclerViewAdapter extends RecyclerView.Adapter<horizontalRecyclerViewAdapter.horizontalRecyclerViewHolder> {
public horizontalRecyclerViewAdapter(){}
// Blank constructor and also one with lots of arguments for it to work.
public horizontalRecyclerViewAdapter.horizontalRecyclerViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.horizontal_recyclerview_adaptor_holder, parent, false);
return new horizontalRecyclerViewAdapter.horizontalRecyclerViewHolder(view);
}
public void onBindViewHolder(#NonNull horizontalRecyclerViewHolder holder, int position) {
// Connect up various views.
holder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LocalBroadcastManager.getInstance(mContext).registerReceiver(reviewSubmittedListener, new IntentFilter("reviewSubmitted"));
Intent reviewNow = new Intent(view.getContext(), ReviewActivity.class);
// Put extra details with the intent
view.getContext().startActivity(reviewNow);
}
BroadcastReceiver reviewSubmittedListener = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent reviewFinishedIntent) {
int reviewScore = reviewFinishedIntent.getExtras().getInt("reviewScore");
// Update the horizontal RecyclerView with the information received from the review Activity.
}
};
}
public class ReviewActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_review_item);
// Set up the review, using Firebase and data passed through the intent.
}
public void submitReview() {
// Check that the review is complete/valid and submit it through Firebase
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(ReviewItemActivity.this);
Intent reviewFinishedIntent = new Intent("reviewSubmitted");
reviewFinishedIntent.putExtra("reviewScore", overallScore);
LocalBroadcastManager.getInstance(this).sendBroadcast(reviewFinishedIntent);
finish();
}
If you are using RxJava you can use the RxBus else you can use one of many EventBus implementation for this.
If that is not the path you want to take then you can have a shared view model object that can be used only for communication between fragments see this article.

Sending a recorded audio file from one activity to another

I am currently recording a message and initialising the objects in one fragment. I'd like to pass it to my main activity. However, I can pass an image between fragments using this:
public void captureImage() {
mCamera.captureImage(new CameraKitEventCallback<CameraKitImage>() {
#Override
public void callback(CameraKitImage cameraKitImage) {
((MainActivity) getActivity()).setBitmapToSend(cameraKitImage.getBitmap());
((MainActivity) getActivity()).openDisplayImageFragment();
}
});
}
I have initialised a media recorder within the class. Is there any way to do this?
If the Main Activity is hosting your fragment, then you can send the data from fragment to its parent Activity by - Interface callbacks or creating a public method in your Activity.
Since you can always get the reference to the parent Activity using getActivity(), you can cast it and pass values to the public method. Eg:
myActivity=(MainActivity) getActivity ();
myActivity.receiveAudio(<"Pass the data as object or in byte[]">);
Sending data from a fragment to another activity require to add Intent extras. Eg:
myIntent.putExtra("myKey",<"Place your object or byte array">);
startActivity(myActivity);

Add data to recyclerView from Sqlite in realtime?

I've made an app that is receiving some data from a TCP Client to my TCP Server that store the data in SQlite DB, and actually i've made a recyclerView where to visualize all that data but now my issue is what i'm trying like 2 weeks to refresh the recyclerView in real Time, i mean if a TCP Client will send a new package to my TCP Server and if i'm in the activity with the recyclerView the data have to be added dynamically.
I will also accept any type of tips and suggestions on how to improve my app.
Actually it's my 1st app i've ever created in Android.
HERE you can find my Server(TCPServer),RecyclerViewAdapter,Adapter(constructor),allert.java(class where i invoke the RecyclerViewAdapter.
Hope someone will be able to help me and ill be very grateful.
Try sending broadcast method. Here are the steps :
Make a inner class that extends BroadcastReceiver in your activity.
private class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//do stuffs here, e.g. getting extras from intent
}
Declare a instance of the class outside any methods.
public class MainActivity extends AppCompatActivity {
private ExampleBroadcastReceiver exampleBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
//stuffs
}
}
Override onResume method. Initialize the instance you just made in this method. Then, register it with a intent-filter. This will make sure that your broadcast receiver ready when user open the activity.
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.MainActivity");
exampleBroadcastReceiver = new ExampleBroadcastReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(exampleBroadcastReceiver, filter);
}
Override onPause method and unregister your receiver.
#Override
protected void onPause() {
super.onPause();
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(exampleBroadcastReceiver);
} catch (IllegalArgumentException e) {
if (!e.getMessage().contains("Receiver not registered")) {
// unexpected, re-throw
throw e;
}
Make sure you use ArrayList for dynamic data.
Whenever you receive data from server, after you store them in your database, send a broadcast with extras contains data you want to display in your activity.
EDITED
I registered the receiver using an instance of LocalBroadcastManager.

Adapter values is not updated from another activity

I am stuck with a problem where I need to update the value of a adapter variable in another activity and coming back to first activity should also get that updated value.
my current flow is like. I am staring the BarDetailsActivity and passing the modal with intent from inside the adapter class like:
Intent barDetailIntent = new Intent(getApplicationContext(), BarDetailActivity.class);
barDetailIntent.putExtra("isfav", barsList.get(position));
barDetailIntent.putParcelableArrayListExtra("barlist",barsList);
mContext.startActivity(barDetailIntent);
Then on another activity I am getting that model from intent and changing its variable values as:
gbar = in.getParcelableExtra("isfav");
blist= in.getParcelableArrayListExtra("barlist");
if (gbar.getmFavourite()) {
gbar.setmFavourite(false);
} else {
gbar.setmFavourite(true);
}
Now on going back to my main Activity Value for "gbar.setmFavourite" is not updated on onresume of the MainActivity.
#Override
protected void onResume() {
super.onResume();
if(mAdapter != null){
mAdapter.notifyDataSetChanged(); // here the adapter value is not updated.
}
}
Please help me on this.
Use Event Bus to handle the problem.
Register your First Activity to listen the Event and override
onEvent method.
Fire the stickyIntent with updated dataset from SecondActivity.
In the onEvent method of the FirstActivity call notifyDataSetChanged
with the updated dataset.

how to end an outgoing call after activity result?

I have a outGoingCall broadcast receiver.
basically I want it to intercept any outgoing call and show a dialog for certain pre-defined numbers.
so I made this broadcast init an activity which inits an FragmentDialog which init a AlertDialog.
When the user click "no"
I want to stop the call from happening.
I know setResultData(null); in the broadcast should do it.
But how can I pass the dialog result to the broadcast ?
there is no onActivityResult() in a broadcast.
I know how to pass it till the activity only.
fragmentDialog code:
public class YesNoDialogFragment extends DialogFragment {
private YesNoDialogFragmentListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
// Instantiate the NoticeDialogListener so we can send events to the
// host
mListener = (YesNoDialogFragmentListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
}
here is my activity code:
public class MainActivity extends FragmentActivity implements
YesNoDialogFragmentListener {
public static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showYesNoDialog();
}
#Override
public void onDialogPositiveClick() {
// how to send result to receiver ??
finish();
}
here is my receiver code:
#Override
public void onReceive(final Context context, final Intent intent) {
Log.v(Constants.LOGTAG, "OutgoingCallReceiver onReceive");
if (intent.getAction()
.equals(OutgoingCallReceiver.OUTGOING_CALL_ACTION)) {
Log.v(Constants.LOGTAG,
"OutgoingCallReceiver NEW_OUTGOING_CALL received");
// get phone number from bundle
String phoneNumber = intent.getExtras().getString(
OutgoingCallReceiver.INTENT_PHONE_NUMBER);
if ((phoneNumber != null)
&& phoneNumber
.equals(OutgoingCallReceiver.ABORT_PHONE_NUMBER)) {
Toast.makeText(
context,
"NEW_OUTGOING_CALL intercepted to number 123-123-1234 - aborting call",
Toast.LENGTH_LONG).show();
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
SharedPreferences sharedPreferences = context
.getSharedPreferences(Constants.SHARED_PREF_NAME,
Context.MODE_PRIVATE);
boolean isBloacked = sharedPreferences.getBoolean(
Constants.IS_NUMBER_BLOCKED, true);
if (isBloacked) {
// dialog and then:
setResultData(null);
}
}
as you can see i tried to share the activity result via shared preferences, how come the code is async and the setResultData(null); is called before the dialog is shown?
from what I know there is no way to end the call besides setResultData(null);
You have to go through an activity (or a fragment) and then pass it to the receiver. Whenever you start a dialog, it has a parent activity, and that is where the result is sent. Just add something to your activity that passes the result on to your receiver.
You might actually consider altering your design to put more of your logic into the activity. Receivers are generally intended to be pretty lightweight objects that receive notification of something, pass it on to somewhere else. and then go away. Anyway, I obviously don't know your code, so maybe this doesn't make sense.
EDIT
Sorry, I understand your problem better now. I'm used to only working with setResultData when one activity has launched another activity, and the 2nd one wants to send something back to the 1st one. But you are using it to stop an ordered broadcast, right?
Unfortunately, Android does now allow you to do what you are trying to do. This section of the doc specifically says that you cannot show a dialog from within a broadcast:
http://developer.android.com/reference/android/content/BroadcastReceiver.html#ReceiverLifecycle
I think what you need to do is always return setResultData(null) right after starting your activity. If the user then clicks "no" in your dialog, then you are done. But if the user clicks "yes" (I'm assuming there is a "yes") then you would have to go ahead and make the call, and make sure you don't catch it again in your receiver.
Does that make sense? Sorry for my confusion earlier.

Categories

Resources