I have no idea why my Android application is crashing. I noticed it happened when I put in the simple firstTime variable, but I'm honestly clueless to why the firstTime variable would make the whole application crash. Every other part works if I take out the if statement. This is what I have put in so far:
public class MainActivity extends Activity {
static int firstTime = 0;
BroadcastReceiver receiver = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
if(firstTime == 0){
logTime(false);
firstTime++;
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
receiver = new BroadcastReceiver(){
#Override
public void onReceive(Context arg0, Intent arg1) {
if(arg1.getAction().equals(Intent.ACTION_SCREEN_OFF)){
logTime(true);
}
else if(arg1.getAction().equals(Intent.ACTION_SCREEN_ON)){
logTime(false);
}
}
};
registerReceiver(receiver, filter);
}
Might anyone know why the firstTime variable crashes my application? thanks!
I didn't think of this before, I was thinking you wanted to just increment the int, so I wasn't thinking about calling logTime() again, and didn't see how it could crash with such a simple concept.
Your issue is most likely the order, since with your current code the textView in the method will be null and will throw an NPE when accessed.
This is because the findViewById() in logTime() will return null (a content view isn't set - so there isn't anything to find):
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(firstTime == 0){
logTime(false);
firstTime++;
}
Related
I have the following code:
((ImageButton)findViewById(R.id.fish)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(StartupActivity.this, GameActivity.class);
intent.putExtra(NAME_EXTRA, ((EditText)findViewById(R.id.name)).getText().toString().trim());
intent.putExtra(TYPE_EXTRA, FishTypes.FISH.toString());
intent.putExtra(WORLD_TYPE_EXTRA, worldType);
intent.putExtra(LOGO_EXTRA, BitmapFactory.decodeResource(getResources(), R.drawable.logo));
startActivity(intent);
}
});
If I start activity and click on ImageButton it send me to the same Activity I was before (StartupActivity). However if I comment out the last putExtra like this:
//intent.putExtra(LOGO_EXTRA, BitmapFactory.decodeResource(getResources(), R.drawable.logo));
Then it works fine. It sends me to the GameActivity as I want. What could be the problem?
EDIT
My GameActivity looks like this:
public class GameActivity extends Activity {
public static GamePanel gamePanel;
public static String name;
public static FishTypes type;
public static String worldType;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(getWindow().FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
name = getIntent().getStringExtra(StartupActivity.NAME_EXTRA);
type = FishTypes.parse(getIntent().getStringExtra(StartupActivity.TYPE_EXTRA));
worldType = getIntent().getStringExtra(StartupActivity.WORLD_TYPE_EXTRA);
gamePanel = new GamePanel(this);
//gamePanel.bitmaps.put("logo", (Bitmap)getIntent().getParcelableExtra(StartupActivity.LOGO_EXTRA));
setContentView(gamePanel);
if(!StartupActivity.isNetworkAvailable()) {
Toast.makeText(StartupActivity.getInstance(), "You have no internet connection...", Toast.LENGTH_LONG).show();
finish();
}
}
#Override
protected void onDestroy() {
if(gamePanel.client != null)
gamePanel.client.disconnect();
StartupActivity.getInstance().reopen();
super.onDestroy();
}
}
What I want to achieve is preloading this bitmap in StartupActivity and then just send it to the GameActivity to the GamePanel and then draw it on the canvas as a loading image. I can't load this image in GameActivity because it will be late to show it. Do you understand?
So first of all, there is an Intent payload limit, as far as I know there is a limit of 1MB, but in some cases can be 500kb. If this limit is overreached the app will crash, in your case crashed and restarted.
Second of all, Bundle and Intent are used to send small amount of data to Activity and Fragments, usually some configs/params so that the activity/fragment will know how to build itself.
Third, is a really bad practice to pass around instances of bitmaps, you need just a second of distraction to create a huge leak in your app, that will cost you a lot of time to find and fix it.
Now the solution for you is really simple. You can pass the id of the bitmap you want to use in the next activity.
Intent intent = new Intent(StartupActivity.this, GameActivity.class);
intent.putExtra(NAME_EXTRA, ((EditText)findViewById(R.id.name)).getText().toString().trim());
intent.putExtra(TYPE_EXTRA, FishTypes.FISH.toString());
intent.putExtra(WORLD_TYPE_EXTRA, worldType);
intent.putExtra(LOGO_EXTRA, R.drawable.logo); // R.drawable.logo is actually an int.
startActivity(intent);
In your GameActivity
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(...)
int myAwesomeDrawable = getIntent().getExtra(LOGO_EXTRA, 0); // 0 is default value in case nothing is added to the key
if(myAwesomeDrawable != 0){ // safety check
imageView.setImageResource(myAwesomeDrawable);
// or do whatever you like with it.
}
public class MainActivity {
private MyListViewHelper mTimelineHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
mListViewHelper = new MyListViewHelper();
mListViewHelper.createListView();
startService(new Intent(this, MyService.class));
}
}
MyService class:
public class MyService extends Service {
private int mCount = 0;
public static final long NOTIFY_INTERVAL = 10 * 1000;
private static MyListViewHelper mListViewHelper;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// cancel if already existed
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
}
#Override
public void onDestroy() {
mTimer.cancel();
}
private class TimeDisplayTimerTask extends TimerTask implements LocationListener {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
//DO SOMETHING HERE
...........
mCount++;
if(mCount==4){
mListViewHelper = new MyListViewHelper()
mListViewHelper.addItemToList("ABCD");
}
}
});
public boolean isMainActivityRunning(string packageName) {
ActivityManager activityManager = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasksInfo = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (int i = 0; i < tasksInfo.size(); i++) {
if(tasksInfo.get(i).baseActivity.getPackageName.toString().equals(packageName)
return true;
}
return false;
}
}
}
MyListViewHelper class:
public class MyListViewHelper {
private ListView mListView;
private ArrayList<String> mArrayList;
public MyListViewHelper () {
}
public void createListView(){
mArrayList = new ArrayList<String>();
mListView = (ListView) activity.findViewById(R.id.listView1);
// I make a short version,so we suppose adapter is already prepared here
mListView.setadapter(adapter);
}
public void addItemToList(String myString){
mArrayList.add(myString);
adapter.notifiDateSetChanged();
}
}
What I want is for every 10 seconds, service will do something, and then if it do that 4 times, I will add one item to ListView. I forgot to save logcat before change it back to the time before I edited, so there is no logcat, sorry for that. But I'm pretty sure there is nothing wrong with others and the problem is just somewhere in the code above since I'm leanring Android and I don't have much knowledge about Service. Please teach me to fix that!
You could use EventBus to tell your Activity that the Service is updating the list.
For example...
Your Activity:
public void onEventMainThread(ListUpdateEvent event) {
mList.add(event.getValue());
mAdapter.notifyDataSetChanged();
}
Your Service:
EventBus.getDefault().post(new ListUpdateEvent("Value to add"));
ListUpdateEvent is a simple POJO that lets you share data. Using onEventMainThread allows you to automatically protect the list from being updated on a background thread.
Here is info about how to send messages from services to activity components. So you just need to send data about new list item.
Have you tried changing adapter.notifiDateSetChanged(); to adapter.notifyDataSetChanged();
And by the way, the best way to update your activity via service is to register a broadcast receiver in your activity's onResume() and send a broadcast from your service when you want to update the activity and put your data as an extra. Don't forget to unregister() your receiver in onPause() and to declare your service in the Manifest.
You can read more about data flow from service via broadcast to activity here http://www.truiton.com/2014/09/android-service-broadcastreceiver-example/
You can't. It is not possible to update UI components in an Activity from a Service. Or, if you'd find a way to do that, I would say it is a bad idea*.
I think the EventBus implementation of Knosses is a good idea. I would like to suggest an implementation using a database, Loaders and Broadcasts.
The Activity with the ListView would use a CursorLoader to get the list content from the data source. The Service would add the items to the database each NOTIFY_INTERVAL and send out a Broadcast. The Activity would register a BroadcastReceiver that listens to the Broadcasts send by the Service, on receiving a Broadcast in the Activity, call getLoaderManager().restartLoader(), so the content in the ListView will refresh.
Edit:
* Let me elaborate a bit on that; as you can also bind a Service to your Activity. In that case, it is perfectly valid to update a UI component through the binding.
I am trying to make a button in one activity (SetupMenu) that, when pressed, puts an int into the intent and carries that over to the next activity (IntroActivity) where a textView will retrieve the int and display it.
Problem is, when the app runs and I get to the activity and press the button, the app crashes and my emulator tells me that "Unfortunately [my app] has stopped working."
I feel like I've tested every possible angle to get this to work. I should note that the button has worked fine, the textview has worked fine, everything else is working smoothly - I only run into issues when I try retrieving the intent and displaying it in textView. I tried passing through a String instead of an Int and also had issues (my string would not appear). Any pointers?
SetupMenu activity (here I put an int into my intent):
public class SetupMenu extends Activity {
public final static String extra_progress_key = "com.example.angelsanddemons.track_players";
public int track_players = 0;
public void to_intro(View view) {
Intent intent = new Intent(this, IntroActivity.class);
intent.putExtra(extra_progress_key, track_players);
startActivity(intent);
}
IntroActivity activity (here I try to retrieve the int from the intent):
public class IntroActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
int temp = intent.getIntExtra(SetupMenu.extra_progress_key, 0 );
TextView textView = new TextView(this);
textView.setText(temp);
setContentView(textView);
}
}
One problem is that you can't set a TextView's text to an int; you'll need to first convert it to an string. It's also not a good idea to be manipulating views before you've inflated them, so perhaps your onCreate() should be:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
int temp = intent.getIntExtra(SetupMenu.extra_progress_key, 0 );
TextView textView = new TextView(this);
setContentView(textView);
textView.setText(String.valueof(temp));
}
I see nothing that ensure that SetupMenu activity is created and in memory when IntroActivity is launched. To make sure, don't pass the variable, but the string itself and check if it work:
int temp = intent.getIntExtra("com.example.angelsanddemons.track_players", 0 );
I'm Trying to set a value(global) in a function and access it outside function that is in "On create()" in android
I've tried making the global variable static, and I even tried to write it in a "edit text" and parsing it in "on create()" . but it keeps initializing to 0.0 (the variable is a double type)
when i tried to access in "on create()",
oh and i can't return the value because the function is too nested so all hierarchy is too complex. :(
Can anyone help me with this;
public class TryActivity extends Activity
{
double BAT;\\ global value
public void onCreate(Bundle savedInstanceState)
{
disp(); // calling the function disp to set the value to BAT
String To_string=Double.toString(BAT);
System.out.println("Current Battery level ==="+To_string); \\ prints 0.0 the wrong value
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void disp(){
this.registerReceiver(this.batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent){
double level= intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);
BAT=level;
Textview1 = (EditText) findViewById(R.id.Textview1);
Textview1.setText(Double.toString(BAT)); // sets the correct value
System.out.println("bbbattererrerey 1 "+Double.toString(BAT)); //prints the correct value
}
};
}
Simply initialize the variable as public static gobally in the class. You will be able to access it from anywhere.
Define as public static your variables:
public class TryActivity extends Activity
{
public static double BAT; //global value.
public void onCreate(Bundle savedInstanceState) {
...
...
...
You are getting BAT with value of 0.0 because when your activity starts execute the method onCreate() and the the method disp() that only register the Intent to get the Battery Level.
If you want to get the battery level at the start of your activity you can do it with a function to get the battery level without receiving updates.
public float getMyBatteryLevel() {
Intent batteryIntent = this.getApplicationContext().registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return batteryIntent.getIntExtra("level", -1);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
//* Add this method.
getMyBatteryLevel()
disp(); // calling the function disp to set the value to BAT
String To_string = Double.toString(BAT);
System.out.println("Current Battery level ==="+To_string); //prints the right battery level.
The problem is you don't understand the concept of concurrency. The BroadcastReceiver's onReceive() won't be called immediately. Thus, you are just setting up the BroadcastReceiver in disp(), and not directly touching BAT. BAT will only be filled with the correct value when onReceive() is called.
If you will look in to your logs the System.out.println() you have written in onCreate will be called before the System.out.println() written in onReceive of your BroadcastReceiver even it is written after your disp() method.
Reason :
In disp() method you are just registering your BroadcastRecever doesn't mean that your BroadcastReceiver is called. It will be called after sometime when your battery level will be changed.
Solution :
If you want to do something with yout BAT variable define a function in your Activity class and write whole logic inside it like
doThings(double batteryLevele){
//write whatever you want to do with BAT
}
and call this function from onReceive method of your BroadcastReceiver.
I currently have a tabhost with 5 tabs. Over one of the tabs I have an ImageView that when the tabs are created it pulls data via POST to display a number. I am wondering how from one of the tab activities (say Rate.java) I could call that method to update that ImageView that is over one of the tabs.
I know it's not very specific but I think I wrote it so you know what I am talking about.
Let me know if you require anymore info.
talitore
Based on the information given, two options that immediately come to mind are:
Send a broadcast from the tab activity (e.g. Rate.java) and have the activity hosting the ImageView listen for it.
Create some sort of BaseActivity (extending Activity) that takes a custom Listener interface with an update method. Have your tab activities extend that BaseActivity and the activity with your ImageView implement it. You can then call the update method on the listener from your tab activities (instantiate them as a BaseActivity and pass along the listener) and make the activity with the ImageView act upon it.
//Edit per request:
A good starting point for information about broadcasts and receivers is the documentation for the BroadcastReceiver. In your case it's probably easiest to just create them in code.
A minimal example will contain something like the following:
BroadcastSendingActivity:
public class BroadcastSendingActivity extends Activity {
public static final String UPDATE_IMAGEVIEW = "UPDATE_IMAGEVIEW";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sender);
Intent i = new Intent();
i.setAction(UPDATE_IMAGEVIEW);
sendBroadcast(i);
}
}
BroadcastReceivingActivity:
public class BroadcastReceivingActivity extends Activity {
private BroadcastReceiver mReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.receiver);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver();
}
#Override
protected void onResume() {
super.onResume();
registerReceiver();
}
private void registerReceiver() {
if (mReceiver == null) {
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BroadcastSendingActivity.UPDATE_IMAGEVIEW)) {
// code to update imageview...
}
}
};
}
getApplicationContext().registerReceiver(mReceiver, new IntentFilter(BroadcastSendingActivity.UPDATE_IMAGEVIEW));
}
private void unregisterReceiver() {
if (mReceiver != null) {
getApplicationContext().unregisterReceiver(mReceiver);
}
}
}
Note that I did not test the code, but I'm sure you'll be able to figure out any mistakes I might've made. :)