I need to update my app's widget every time the settings are changed by the user.
I have a settings activity:
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
public class SettingsActivity extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String customIntent = "CUSTOM_SETTINGS_CHANGED";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new MainActivity.SettingsFragment())
.commit();
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
Intent intent = new Intent();
intent.setAction(customIntent);
this.sendBroadcast(intent);
}
}
I've added that custom intent to the manifest:
<action android:name="CUSTOM_SETTINGS_CHANGED" />
But the widget is not updated immediately after the settings are changed. So my custom broadcast either is not sent or not received. What's wrong with my code?
// this part important in manifest declaration
package com.xmpls.onetwothree.abc;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
public class SettingsActivity {
public class SettingsActivity extends Activity implements
SharedPreferences.OnSharedPreferenceChangeListener {
// Change like this
public static final String CUSTOM_SETTINGS_CHANGED = "com.xmpls.onetwothree.abc.custompls";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction();
/* More code here. . .*/
}
/* And some here. . .*/
}
================================================================================
and in manifest U must registred ACTION like this:
<action android:name="com.xmpls.onetwothree.abc.CUSTOM_SETTINGS_CHANGED" />
I've used a different approach.
In my main activity I've added this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
<...>
SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Intent intent = new Intent();
intent.setAction(customIntent);
sendBroadcast(intent);
}
};
<...>
}
It seems that onSharedPreferenceChanged was never called for some reason. I don't know why but at least I've found a way to make this work.
Related
I created a ListDialog extending a DialogFragment class and I have a problem with understanding of this code in the DijalogX class
((MainActivity)getActivity()).setTextField(selectedItem);
I understand that with this code above I put selected String variable to the setTextField method as an argument and after that this variable is showed in TextView on MainActivity class.
My questions:
Why I need a cast from getActivity() to the MainActivity and how I get access from DijalogX(fragment) to the method setTextField in MainActivity? Please explain a little about this process.
I also tried instead of ((MainActivity)getActivity()).setTextField(selectedItem)
use an Interface and everything works nice and I got the same resoult but I am wondering what is better solution here Interface or ((MainActivity)getActivity()).setTextField(selectedItem)?
MainActivity
package com.example.dezox.dijaloglist;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity{
private Button btnStartDialog;
private TextView tvSelectedOption;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWidgets();
setupListener();
}
private void initWidgets() {
btnStartDialog = findViewById(R.id.btnDialog);
tvSelectedOption = findViewById(R.id.tvselectedOption);
}
private void setupListener() {
btnStartDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DijalogX dijalogX = new DijalogX();
dijalogX.show(getSupportFragmentManager(), "dx");
tvSelectedOption.setText("");
}
});
}
public void setTextField(String odabrano){
tvSelectedOption.setText(odabrano);
}
public String getTextField(){
return tvSelectedOption.getText().toString();
}
}
DijalogX
package com.example.dezox.dijaloglist;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
public class DijalogX extends DialogFragment {
private String[] languageList;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initListResource();
}
private void initListResource() {
languageList = getResources().getStringArray(R.array.language_list);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
android.R.style.Theme_Material_Dialog_Alert)
.setTitle("Select Language: ")
.setItems(languageList, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String selectedItem = languageList[which];
//THIS PART OF THE CODE I DONT UNDERSTAND:
((MainActivity)getActivity()).setTextField(selectedItem);
}
});
return builder.create();
}
}
You have declared a method in MainActivity called setTextField. If you called
Activity a = getActivity();
you would not be able to call your custom method (it is on your derived class, not the base Activity class).
a.setTextField(selectedIte); // WON'T WORK - NO SUCH METHOD
If instead you call
MainActivity ma = (MainActivity)getActivity();
it is now cast as your derived class and you can then call
ma.setTextField(selectedItem);
Doing it in two lines like this is the same as calling the one-liner in your code
((MainActivity)getActivity()).setTextField(selectedItem);
As far as casting vs. an interface, an interface is a bit more flexible of an approach. If you tried to use this fragment in a different activity (not MainActivity) the casting approach would fail. If you are only ever going to use the fragment in this Activity then either would work.
I am sending a broadcast from App A to App B and I am already receiving it in app B. After receiving the broadcast I want to bring the App B to the front. How can I bring the App B to the front after receiving the broadcast from the App A?
package com.mysender;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Intent intent=new Intent();
intent.setAction("com.mysender.Data");
intent.putExtra("path", "/Download/income_tax_return.pdf");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
sendBroadcast(intent);
}
}
In the App B I am doing the following in the MainActivity:
package com.example.app;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
private WebView mWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Receive broad Cast fromn External App
IntentFilter filter = new IntentFilter("com.mysender.Data");
registerReceiver(myReceiver, filter);
}
private MyReceiver myReceiver =new MyReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
String path = intent.getStringExtra("path");
Toast.makeText(context,"Data Received from External App: " + path, Toast.LENGTH_SHORT).show();
}
};
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);
}
}
http://i.stack.imgur.com/vnfQt.png
As shown above From settings when I change the value of temprature units from metric to imperial and press back button my app got crash and showing below error
http://i.stack.imgur.com/dBeHk.png
SettingsActivity
package com.example.poo.sunshine;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
public class SettingsActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(R.id.container, new MyPreferenceFragment())
.commit();
}
public static class MyPreferenceFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add 'general' preferences, defined in the XML file
addPreferencesFromResource(R.xml.pref_general);
// For all preferences, attach an OnPreferenceChangeListener so the UI summary can be
// updated when the preference changes.
PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference locationPref = findPreference(getString(R.string.pref_location_key));
Preference unitsPref = findPreference(getString(R.string.pref_units_key));
prefChanged(sharedPreferences, locationPref, key);
prefChanged(sharedPreferences, unitsPref, key);
}
private void prefChanged(SharedPreferences sharedPreferences, Preference pref, String key) {
if (sharedPreferences instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list (since they have separate labels/values).
ListPreference listPreference = (ListPreference) sharedPreferences;
int prefIndex = listPreference.findIndexOfValue(key);
if (prefIndex >= 0) {
pref.setSummary(listPreference.getEntries()[prefIndex]);
} else {
pref.setSummary(sharedPreferences.getString(key, ""));
}
}
}
}
}
The problem is cause from the view of your Fragment is not yet attached to your SettingActivity.
To avoid this error, you can check with isAdded() before access views in your Fragment.
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(isAdded()){
Preference locationPref = findPreference(getString(R.string.pref_location_key));
Preference unitsPref = findPreference(getString(R.string.pref_units_key));
prefChanged(sharedPreferences, locationPref, key);
prefChanged(sharedPreferences, unitsPref, key);
}
}
Another solution and I would like to suggest as well.
You should register the preference changed listener in onViewCreated() in your Fragment. So that mean your Fragment is fully attached.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
PreferenceManager.getDefaultSharedPreferences(getActivity())
.registerOnSharedPreferenceChangeListener(this);
}
Hope this will work!
I'm quite new to programming.
I'm trying to make a simple app with two activities, where the second activity can change the text of the first. I know it can be done using intents, but I was wondering if there is a more direct way of doing it, for example using the second activity to call a function from the first activity?
Here's the code I have so far:
The MainActivity, which contains a TextView and a button to open the second activity:
public class MainActivity extends Activity {
TextView textview;
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textview = (TextView) findViewById(R.id.et2);
button = (Button) findViewById(R.id.b1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(MainActivity.this, ChangeText.class);
startActivity(intent);
}
});
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
}
public void changetext(String message) {
textview.setText(message);
}
}
And the second activity, ChangeText, which contains an EditText and a button which should change the text of the TextView in MainActivity and then finish itself:
public class ChangeText extends Activity{
EditText edittext;
Button button;
private MainActivity mainclass;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.change_text);
edittext = (EditText)findViewById(R.id.et2);
button = (Button)findViewById(R.id.b2);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
String message = edittext.getText().toString();
mainclass.changetext(message);
finish();
}
});
}
}
As you can see I tried to make the app work by making a public function in MainActivity which receives a string and sets the TextView with it, and then I call this function from the ChangeText activity.
The problem: it keeps crashing! Can anyone tell me how I can make this work?
Seems like I answered almost exactly the same question a week or so ago, so this is probably a duplicate, but I can't seem to find the original question.
The short answer is no - you can't call a method in an Activity from another Activity. The issue is that for normal programming purposes, only one Activity exists at a time*.
If you do something to circumvent this, then you're risking causing some major issues, including high memory usage, null pointer exceptions, etc.
The correct way to do this is indeed through the Intent system.
* Activities may or may not actually get destroyed when they become inactive, depending on things like how you use the back stack.
However, you should always program is if they do get destroyed when they become inactive - read, understand, and respect the Activity lifecycle.
For something as simple as your app, the "most direct" approach is to use the intent and startActivityForResult and them implement an onActivityResult in your main activity.
The problem you'll run into, even if you correctly pass you Activity references around is they are not guaranteed to be running at the same time.
Other ways aside from Intents, is to use a class(s) not involved with the Activity. Either a background service or a static variable in a class that extends Application. I rarely use Application classes anymore in favor of services and binding Activities them.
If I use an EventBus in projects, they can send Sticky events, which will hold the data until cleared.
Android uses a messaging mechanism to communicate between its components. This messaging mechnism is essential to Android, so you should use it. And as you already said, the messaging is implemented by Intents. ;-)
If you want something more complex, use an EventBus or implement a your own subscribe/publish mechanism that does what you want.
Use static variable
Example
In your MainActivity define
public static String msg = null;
then in your ChangeText activity assign changed text to it like
MainActivity.msg = edittext.getText().toString();
now in your main activity override the onResume() methode
if(msg != null){
textview.setText(msg);
msg = null;
}
You must LocalBroadCast Manager to do so
Here is the MainActivity which has the TextView which has to updated by another Activity
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView txt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt=(TextView)findViewById(R.id.txt1);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("custom-event-name"));
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String s1= intent.getStringExtra("myString");
getIt(s1);
}
};
#Override
protected void onDestroy() {
// Unregister since the activity is about to be closed.
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
public void getIt(String s)
{
System.out.println(s);
txt.setText(s);
}
public void go(View view)
{
Intent intent = new Intent(this,WriteText.class);
startActivity(intent);
}
}
And This is the Activity which contains the EditText which updates the TextView in the previous activity
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
public class WriteText extends Activity {
EditText ed1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_write_text);
ed1 = (EditText)findViewById(R.id.textView);
}
public void come(View view){
Intent intent = new Intent("custom-event-name");
intent.putExtra("myString", ed1.getText().toString());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
This Worked for me , Hope it works for you too
I have below snippet code to pass a parameter from a class (activity) to another class. To do so, used sharedPreferences, but i try to get in my secondclass the value that was saved in main activity , i am getting java.lang.Nullpointer exception. What I am doing wrong here?
public class Secondclass extends Activity {
//other functions....
private void get_file_name() {
final main m=new main();
String myvalue=m.set_paramater();
//I want to access FOLDER_NAME here
Log.e("TAG","the value "+myvalue);
}
}
public class main extends Activity{
String FOLDER_NAME;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FOLDER_NAME="a_name";
Save_file_name("APP_NAME",FOLDER_NAME);
}
private void Save_file_name(String key,String value){
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.commit();
}
public String set_paramater(){
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
String strSaveddata = sharedPreferences.getString("APP_NAME", "");
return strSaveddata;
}
}
}
Here is the trace file:
E/AndroidRuntime(10622): FATAL EXCEPTION: main
E/AndroidRuntime(10622): java.lang.NullPointerException
E/AndroidRuntime(10622): at android.content.ContextWrapper.getPackageName(ContextWrapper.java:120)
E/AndroidRuntime(10622): at android.app.Activity.getLocalClassName(Activity.java:3488)
E/AndroidRuntime(10622): at android.app.Activity.getPreferences(Activity.java:3522)
It is bad practice to instantiate an Activity from another Activity, in your case with the line:
final main m=new main();
Android handles the creation of all your activities and you shouldn't have to do it yourself. If you do it this way the Activity will not have a valid Application Context. Without a valid Application context getPreferences(MODE_PRIVATE) will return null.
Also, it is probably better to use:
PreferenceManager.getDefaultSharedPreferences(this)
Using getPreferences(...) will make the preferences private to your Activity. Using getDefaultSharedPreferences(this) will make your preferences available to other activities instead of just the Activity that created it. This allows you to share your data across your two activities.
Activity.getPreferences() retrieve a SharedPreferences object for accessing preferences that are private to this activity, which means in two activities you got different SharedPreferences.
You may use Context.getSharedPreferences() with same name to get same SharedPreferences
final main m=new main();
It is wrong!
as you are using
SharedPreferences sharedPreferences = gePreferences(MODE_PRIVATE);
which required Context. Which is null at the time when you call set_paramater()
Just make set_paramater() in Secondclass. It will solve your problem!
package com.example.test;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class main extends Activity {
String FOLDER_NAME;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FOLDER_NAME = "a_name";
Save_file_name("APP_NAME", FOLDER_NAME);
Button nextButton=(Button)findViewById(R.id.next_button);
nextButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(main.this,Secondclass.class));
}
});
}
private void Save_file_name(String key, String value) {
SharedPreferences sharedPreferences = getSharedPreferences(
"myPreffFile", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.commit();
}
}
and...
package com.example.test;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class Secondclass extends Activity {
// other functions....
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button nextButton = (Button) findViewById(R.id.next_button);
nextButton.setText("Show Value");
nextButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
get_file_name();
}
});
}
private void get_file_name() {
Toast.makeText(this, set_paramater(), Toast.LENGTH_SHORT).show();
}
public String set_paramater() {
SharedPreferences sharedPreferences = getSharedPreferences(
"myPreffFile", MODE_PRIVATE);
String strSaveddata = sharedPreferences.getString("APP_NAME", "");
return strSaveddata;
}
}
NOTE: it is fully test code. I run this..if still error came then the fault is in other place.
Not an answer to your problem but just some info. You can share data among activities of your application by extending the Android Application class.
Extend the Application class and create your own class.
package com.foo.bar;
import android.app.Application;
public class MyApplication extends Application {
private boolean foo;
#Override
public void onCreate() {
foo = false;
}
public void SetFoo(boolean fooValue) {
foo = fooValue;
}
public boolean GetFoo() {
return foo;
}
}
Your manifest must set the application class.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.foo.bar"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="16"/>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:name=".MyApplication">
<activity
android:label="#string/app_name"
android:name=".MyActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Your can access the application class instance within an activity like this.
MyApplication mApp = (MyApplication)getApplication();