I have a class called HeaderView which I use all over my application:
public HeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
ctx = context;
commonApi = AAALifestyleApplication.commonApi;
user = commonApi.getCurrentUser();
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.header_view, this, true);
((ImageView)this.findViewById(R.id.logo)).setOnClickListener(this);
inboxButton = (ImageView) this.findViewById(R.id.inbox_image);
inboxButton.setOnClickListener(this);
inboxButton2 = (ImageView) this.findViewById(R.id.inbox_image2);
inboxButton2.setOnClickListener(this);
requestsButton = (ImageView) this.findViewById(R.id.requests_image);
requestsButton.setOnClickListener(this);
requestsButton2 = (ImageView) this.findViewById(R.id.requests_image2);
requestsButton2.setOnClickListener(this);
progressBar = (ProgressBar) this.findViewById(R.id.header_progress_bar);
if (!showProgressBar) {
progressBar.setVisibility(INVISIBLE);
}
AAAAsyncTask.setProgressBarListener(this);
refreshView();
}
public static void refreshView(){
SharedPreferences sp = ctx.getSharedPreferences("HeaderView", Context.MODE_PRIVATE);
int newMessages = sp.getInt("newMessagesCount", 0);
int newRequests = sp.getInt("newRequestsCount", 0);
if(newMessages > 0){
Log.d("daim", "new messages!");
inboxButton.setVisibility(View.GONE);
inboxButton2.setVisibility(View.VISIBLE);
}
else{
Log.d("daim", "no new messages!");
inboxButton.setVisibility(View.VISIBLE);
inboxButton2.setVisibility(View.GONE);
}
if(newRequests > 0){
requestsButton.setVisibility(View.GONE);
requestsButton2.setVisibility(View.VISIBLE);
}
else{
requestsButton.setVisibility(View.VISIBLE);
requestsButton2.setVisibility(View.GONE);
}
}
In my Activity, this HeaderView gets called onCreate cause its specified in the XML, and also in onResume() like this:
#Override
public void onResume(){
super.onResume();
HeaderView.refreshView();
}
In the onCreate() method this works correctly, but onResume() I get the right amount of messages and I even logged this, so I know for sure that "no new messages" is printed, but the setVisibility() method doesn't update at all, and instead I see the previous ImageView when I had "new messages".
Please help, I've tried using handler with a thread to see if that was the problem, but it still remains this way.
You should instantiate your view, and make the refreshView non-static.
Declare your Activity like this:
public class YourActivity extends Activity {
private HeaderView mHeaderView;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mHeaderView = new HeaderView(this);
}
#Override
public void onResume(){
super.onResume();
mHeaderView.refreshView();
}
}
And remove the static keyword in your refreshView method declaration.
Related
In this code below can i only once instantiate view? Then, I can using it for some method in helper class.
public class Helper {
private Context context;
private Activity activity;
private TextView textView;
private Button button;
public Helper(Context context, Activity activity) {
this.context = context;
this.activity = activity;
}
public void firstMethod() {
textView = (TextView) activity.findViewById(R.id.text_view);
button = (Button) activity.findViewById(R.id.button);
textView.setText(R.string.some_text_1);
button.setText("Tes1 Button")
}
public void secondMethod() {
textView = (TextView) activity.findViewById(R.id.text_view);
button = (Button) activity.findViewById(R.id.button);
textView.setText(R.string.some_text_2);
button.setText("Tes2 Button")
}
}
As you can see textView and button instantiate twice in different method, but I just want single instantiate. How to code that?
UPDATE
In activity we can do this:
protected void onCreate(Bundle savedInstanceState) {
//see this code
textView = (TextView) findViewById(R.id.text_view);
button = (Button) findViewById(R.id.button);
}
And then in method we just do like this:
public void someMethod() {
textView.setText(R.string.some_text_2);
button.setText("Tes2 Button")
}
I need code like shown above in non activity. is it possible ?
If I understand what you're asking correctly, you can instantiate them in your constructor, like this
public Helper(Context context) {
// You really don't even need to save context in this case since
// you only use it in the constructor. If your real problem is more
// complex you may still need to though
this.context = context;
textView = (TextView) context.findViewById(R.id.text_view);
button = (Button) context.findViewById(R.id.button);
}
then you don't have to do so in firstMethod and secondMethod, which can just be
public void firstMethod() {
textView.setText(R.string.some_text_1);
button.setText("Tes1 Button")
}
public void secondMethod() {
textView.setText(R.string.some_text_2);
button.setText("Tes2 Button")
}
You could then create your helper class from within, say, your Activity onCreate like
private Helper helper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time_till);
helper = new Helper(this);
}
Use context instead of activity:-
Make sure you need to pass Activity to Non Activity class as constructor parameter as you are initialized in your code.
refer:-findViewById in non activity class
public void secondMethod() {
textView = (TextView) context.findViewById(R.id.text_view);
button = (Button) context.findViewById(R.id.button);
textView.setText(R.string.some_text_2);
button.setText("Tes2 Button")
}
Make initialization in constructor:
public Helper(Context context, Activity activity) {
this.context = context;
this.activity = activity;
textView = (TextView) activity.findViewById(R.id.text_view);
button = (Button) activity.findViewById(R.id.button);
}
In android, I have a custom layout I built:
public class ButtonMatch extends RelativeLayout
{
private final TextView text_round, text_match, text_player1, text_player2;
public ButtonMatch(final Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.button_match, this, true);
text_round = (TextView) findViewById(R.id.text_round);
text_match = (TextView) findViewById(R.id.text_match);
text_player1 = (TextView) findViewById(R.id.text_player1);
text_player2 = (TextView) findViewById(R.id.text_player2);
}
public void setRound(String text) {
text_round.setText(text);
}
public void setMatch(String text) {
text_match.setText(text);
}
public void setPlayer1(String text) {
text_player1.setText(text);
}
public void setPlayer2(String text) {
text_player2.setText(text);
}
public String getPlayer1() {
return text_player1.getText();
}
public String getPlayer2() {
return text_player2.getText();
}
}
Then I am adding this layout in code with the following:
ButtonMatch button = new ButtonMatch(this);
button.setLayoutParams(layout);
button.setTag(match.get("id"));
button.setMatch(match.get("identifier").toString());
button.setPlayer1(players.get(match.get("player1_id").toString()));
button.setPlayer2(players.get(match.get("player2_id").toString()));
button.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
Intent intent = new Intent(view.getContext(), ChallongeMatch.class);
intent.putExtra(MainActivity.EXTRA_API_KEY, API_KEY);
intent.putExtra(MainActivity.EXTRA_SUBDOMAIN, SUBDOMAIN);
intent.putExtra(MainActivity.EXTRA_EVENT_ID, EVENT_ID);
intent.putExtra(MainActivity.EXTRA_MATCH_ID, view.getTag().toString());
intent.putExtra(MainActivity.EXTRA_PLAYER1, view.getPlayer1());
intent.putExtra(MainActivity.EXTRA_PLAYER2, view.getPlayer2());
}
});
What I am missing though, is in the Intent with the onClickListener, I am trying to get the contents of the text_player1 and text_player2 as follows:
intent.putExtra(MainActivity.EXTRA_PLAYER1, view.getPlayer1());
intent.putExtra(MainActivity.EXTRA_PLAYER2, view.getPlayer2());
The problem is those two functions don't work getPlayer1() and getPlayer2, because they dont exist in the view...
How do I get these two functions to work. I don't know a lot about Android/Java yet, so please be explain as much as you can.
You forgot casting view to ButtonMatch.
This is safe, because you set the click listener on the button object.
Change your code to
((ButtonMatch) view).getPlayer1()
to access the method on your object.
I have a chronometer in my list view. The problem is that sometimes it gets leaked i.e. i can see the OnChronometerTickListener executing every second even after i have navigated to another tab or scrolled the list view item out of view or even pressed the Home button. It seems a waste of resources, since i need it to run only when it is actually visible.
Is there a way to avoid this behaviour? Note that it happens only sometimes.
public class TimerLayout extends LinearLayout {
private static final String LOG_TAG = "TimerLayout";
Button btn_endTimer;
Button btn_cancelTimer;
Chronometer cmt_timer;
Runnable updateTimerThread;
Handler handler;
public TimerLayout(Context context, AttributeSet attrs) {
super(context,attrs);
setOrientation(LinearLayout.VERTICAL);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.timer, this, true);
cmt_timer = (Chronometer) getChildAt(0);
btn_endTimer = (Button) ((ViewGroup) getChildAt(1)).getChildAt(0);
btn_cancelTimer = (Button) ((ViewGroup) getChildAt(1)).getChildAt(1);
btn_endTimer.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
cmt_timer.stop();
}
});
btn_cancelTimer.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
cmt_timer.stop();
}
});
cmt_timer.setOnChronometerTickListener(new OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer arg0) {
if(BuildConfig.DEBUG){Log.d(LOG_TAG,"onChronometerTick.objectid=" + System.identityHashCode(TimerLayout.this));}
}
});
}
public void init(Date startTime){
cmt_timer.stop();
if(startTime!=null){
Date now = new Date();
long elapsedTime = now.getTime() - startTime.getTime();
cmt_timer.setBase(SystemClock.elapsedRealtime() - elapsedTime);
cmt_timer.start();
}
}
}
I call the init method of this class in the bindView() method of my cursorAdaptor to start it.
The trick is to stop the chronometers in the onPause() of the fragment/activity.
So i create a class to hold the chronometers :
public class ChronometerHolder {
private WeakHashMap<Date, Chronometer> chronometerMap;
private static final String LOG_TAG = "ChronometerHolder";
public ChronometerHolder() {
chronometerMap = new WeakHashMap<Date, Chronometer>();
}
public void add(Date dt_startTime, Chronometer chronometer){
chronometerMap.put(dt_startTime, chronometer);
}
public void remove(Date dt_startTime){
chronometerMap.remove(dt_startTime);
}
public int getCount(){
return chronometerMap.size();
}
public void startAll() {
// start any chronometers that were paused
if (chronometerMap.size() > 0) {
Set<Entry<Date, Chronometer>> set = chronometerMap.entrySet();
Iterator<Entry<Date, Chronometer>> iterator = set.iterator();
Entry<Date, Chronometer> entry;
while (iterator.hasNext()) {
entry = (Entry<Date, Chronometer>) iterator.next();
entry.getValue().start();
}
}
}
}
public void stopAll() {
// stop any chronometers that might be running
if (chronometerMap.size() > 0) {
Set<Entry<Date, Chronometer>> set = chronometerMap.entrySet();
Iterator<Entry<Date, Chronometer>> iterator = set.iterator();
Entry<Date, Chronometer> entry;
while (iterator.hasNext()) {
entry = (Entry<Date, Chronometer>) iterator.next();
entry.getValue().stop();
}
}
}
}
Then i make the below changes :
Return the chronometer object from init() :
public Chronometer init(Date startTime){
Chronometer obj = null;
cmt_timer.stop();
if(startTime!=null){
Date now = new Date();
long elapsedTime = now.getTime() - startTime.getTime();
cmt_timer.setBase(SystemClock.elapsedRealtime() - elapsedTime);
cmt_timer.start();
obj = cmt_timer;
}
return obj;
}
In the fragment, instantiate the holder class :
ChronometerHolder chronometerHolder = new ChronometerHolder();
Every time you initialize the chrononmeter( in the bindView() of the CursorAdapter), add it to the holder :
Chronometer tmpChronometer = viewHolder.myTimer.init(dt_hitSessionStartTime);
if(tmpChronometer != null){
chronometerHolder.add(dt_hitSessionStartTime, tmpChronometer);
}
In onPause(), stop all the chronometers :
chronometerHolder.stopAll();
In onResume(), start all the chronometers :
chronometerHolder.startAll();
When the you press the Home button instead of exiting the app, and then open the app again, the bindView() calls are not executed. That means the chronometers are in a stopped state. So it has to be started in onResume() as done in #5.
I have an adapter used to display messages on the list view alike messages in chat application . I am able to display the content flawlessly once the activity is created , but when I go back and create activity again , adapter don't work as usual .
What I found in debugging is follows:
function receives() is called when message is received and update the
register , as I mentioned above there is no problem to display the
data in list view once the activity is created , but once I go back
and relauch the activity I am not able to display received messages .
Is there something I am missing in onResume() onPause or onStart() method with respect to custom adapter such as registering or decalring the custom adapter again? Thanks for help.
Following is the code of my activity class which uses custom adapter to display sent and received messages:
public class hotListener extends ListActivity {
private XMPPConnection connection;
private IBinder binder;
private Handler mHandler = new Handler();
private ArrayList<String> messages = new ArrayList<String>();
ArrayList<ChatMessage> messagex= new ArrayList<ChatMessage>();;
ChattingAdapter adaptex;
Intent mIntent ;
private ListView listview;
EditText sender_message ;
String msg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listener);
//messagex.add(new ChatMessage("Hello", false));
adaptex = new ChattingAdapter(getApplicationContext(),messagex);
setListAdapter(adaptex);
Button send_button = (Button) findViewById(R.id.chat_send_message);
sender_message = (EditText) findViewById(R.id.chat_input);
send_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
msg = sender_message.getText().toString();
sender_message.setText("");
if(!(msg.length()==0)){
messagex.add(new ChatMessage(msg, true));
//addNewMessage(new ChatMessage(msg, true));
adaptex.notifyDataSetChanged();
getListView().setSelection(messagex.size()-1);
}
}
});
if(!isMyServiceRunning()){
System.out.println("seems like service not running");
startService(new Intent(this,xService.class));
System.out.print(" now started ");
}
}
#Override
protected void onStart(){
super.onStart();
Boolean kuch = bindService(new Intent(this,xService.class), mConnection,Context.BIND_AUTO_CREATE);
//System.out.println(kuch);
System.out.println("bind done");
}
private void receives(XMPPConnection connection2) {
//ChatManager chatmanager = connection.getChatManager();
connection2.getChatManager().addChatListener(new ChatManagerListener() {
#Override
public void chatCreated(Chat arg0, boolean arg1) {
arg0.addMessageListener(new MessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
final String from = message.getFrom();
final String body = message.getBody();
mHandler.post(new Runnable() {
ChatMessage kudi = new ChatMessage(body, false);
#Override
public void run() {
messagex.add(kudi);
adaptex.notifyDataSetChanged();
getListView().setSelection(messagex.size()-1);
Toast.makeText(hotListener.this,body,Toast.LENGTH_SHORT).show(); }
});
}
});
}
});
}
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for(RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)){
if(xService.class.getName().equals(service.service.getClassName())){
return true;
}
}
//System.out.print("false");
return false;
}
#Override
protected void onResume() {
bindService(new Intent(this, xService.class), mConnection, Context.BIND_AUTO_CREATE);
super.onResume();
}
#Override
protected void onPause() {
unbindService(mConnection);
super.onPause();
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
connection = null;
service = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
//System.out.println("binding in hot listener");
service = ((xService.MyBinder)binder).getService();
connection = service.getConnection();
receives(connection);
Log.wtf("Service","connected");
}
};
void addNewMessage(ChatMessage m)
{
System.out.println("1");
messagex.add(m);
System.out.println("2");
adaptex.notifyDataSetChanged();
System.out.println("3");
getListView().setSelection(messagex.size()-1);
}
}
Here is my custom adapter (there is no problem in custom adapter but adding to make things clear) :
public class ChattingAdapter extends BaseAdapter{
private Context mContext;
private ArrayList<ChatMessage> mMessages;
public ChattingAdapter(Context context, ArrayList<ChatMessage> messages) {
super();
this.mContext = context;
this.mMessages = messages;
}
#Override
public int getCount() {
return mMessages.size();
}
#Override
public Object getItem(int position) {
return mMessages.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ChatMessage message = (ChatMessage) this.getItem(position);
ViewHolder holder;
if(convertView == null)
{
holder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.listitem, parent, false);
holder.message = (TextView) convertView.findViewById(R.id.text1);
convertView.setTag(holder);
}
else
holder = (ViewHolder) convertView.getTag();
holder.message.setText(message.getMessage());
LayoutParams lp = (LayoutParams) holder.message.getLayoutParams();
//Check whether message is mine to show green background and align to right
if(message.isMine())
{ holder.message.setBackgroundResource(R.drawable.msgbox_new_selected_go_up);
lp.gravity = Gravity.RIGHT;
}
//If not mine then it is from sender to show orange background and align to left
else
{
holder.message.setBackgroundResource(R.drawable.msgbox_other_go_up);
lp.gravity = Gravity.LEFT;
}
holder.message.setLayoutParams(lp);
//holder.message.setTextColor(R.color.textColor);
return convertView;
}
private static class ViewHolder
{
TextView message;
}
#Override
public long getItemId(int position) {
//Unimplemented, because we aren't using Sqlite.
return position;
}
}
p.s: I am not storing any messages in sqlite as I dont want to restore messages for now, but I want new messages to be displayed at least onresume of activty. I can display sent messages after pressing send button but no received messages which works fine for the first time activity is created.
EDIT: I did more debugging , it turns out problem is not in resume activity , if I dont use receives() function for first time , and resume activity after going back , then receives() will work , that means , function inside receives() : getListView().setSelection(messagex.size()-1); works only once .
Either first time on receiving message or next time if and only if its not called first time on activity .
I think problem lies when you try to resume activity , you are still running the previous mHandler running and thus your instance of message is not destroyed and when you resume your activity it creates a problem . Make sure your mhandler destroys all instance of objects when unstop is called.
There's no place in your code where you save your messagex ArrayList. When you quit your activity by hitting back, your array get's distroyed (Garbage Collection takes care of it).
When you relaunch your activity your messagex ArrayList is created again, it's a brand new variable.
In fact, you're not relaunching your activity, you're creating a new instance.
EDIT:
I've never worked with the XMPPConnection objects before, but something else worth trying is the following:
When binding to the service, you're calling connection2.getChatManager().addChatListener and also arg0.addMessageListener but when unbinding you're not calling any removeXXX methods. I could be that since you're not removing your listeners, the whole XMPPConnection object still have references to the listeners that live in a dead Activity, and they are not being garbage collected.
I write a custom dialog and try to get some data from its parent activity, but I always get null when I call getOwnerActivity, could anyone tell me why this happen? Why I can show the data in the DemoDialog while failed to show data from TestDialogActivity?
Many thanks in advance.
DialogTestActivity
public class DialogTestActivity extends Activity {
List<String> data = new ArrayList<String>();
Button button;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
showDialog(0);
}
});
}
public List<String> getData(){
data.add("one");
data.add("two");
data.add("three");
return data;
}
public Dialog onCreateDialog(int id){
return new DemoDialog(this);
}
}
DemoDialog
public class DemoDialog extends Dialog {
Context context;
public DemoDialog(Context context) {
super(context);
setContentView(R.layout.dialog);
this.context = context;
setTitle("Delete City");
ListView list = (ListView)findViewById(R.id.list);
ArrayAdapter<String> aa = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_multiple_choice, ((DialogTestActivity)getOwnerActivity()).getData());
// ArrayAdapter<String> aa = new ArrayAdapter<String>(context, android.R.layout.simple_list_item_multiple_choice, getData());
list.setAdapter(aa);
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
private List<String> getData(){
List<String> data = new ArrayList<String>();
data.add("1");
data.add("2");
return data;
}
}
I tried to use getOwnerActivity() method in all possible methods of my custom Dialog. It always returns null (Android 2.3). Then I checked its source code and the activity it returns is set only in setOwnerActivity(Activity activity) which is not called anywhere. So if you want getOwnerActivity() to return value different than null, you have to do this:
public MyCustomDialog(Context context) {
super(context);
if (context instanceof Activity) {
setOwnerActivity((Activity) context);
}
}
If you think about the situation, you will understand why. When you call new DemoDialog(this), you execute all the code in the constructor. After that, you return it from onCreateDialog and Android does its magic. If you try to get owner from the constructor, Android hasn't hooked it yet, so you have no owner yet.
So you can do either of these:
public class DemoDialog extends Dialog {
public DemoDialog(Context context) {
super(context);
// chances of context not being an activity is very low, but better to check.
Activity owner = (context instanceof Activity) ? (Activity)context : null;
if (owner != null) {
// owner activity is defined here
}
}
public void onAttachedToWindow() {
super.onAttachedToWindow();
// getOwnerActivity() should be defined here if called via showDialog(), so do the related init here
Activity owner = getOwnerActivity();
if (owner != null) {
// owner activity defined here
}
}
}
Note that the second method is preferred because
You can extends your custom dialog from AppCompatDialog and access to activity by this code:
public static Activity scanForActivity(Context context) {
if (context == null)
return null;
else if (context instanceof Activity)
return (Activity) context;
else if (context instanceof ContextWrapper)
return scanForActivity(((ContextWrapper) context).getBaseContext());
return null;
}
This, below, worked for me.
private Activity activity;
public MyCustomDialog(Activity activity) {
super(activity);
this.activity = activity;
}
Then I use activity instead of getOwnerActivity().