I have picture showing activity from fragment. When call picture and showing alright. But when i click back button it's very laggy . after some time activity is closing.
Is following image downloading library slow?(Or this activity alright, is resuming fragment slow?) I don't know how to fix this. Where is the problem? Please give me tip or solution?
public class Activity_detail_image extends AppCompatActivity{
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail_image);
toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
String urls = getIntent().getStringExtra("image");
//
// SubsamplingScaleImageView iv = (SubsamplingScaleImageView)findViewById(R.id.zoom_image);
//
// iv.setImage(ImageSource.resource(R.drawable.amestros_01));
if(LoginActivity.isNetworkAvailable()) {
new DownloadImageTask((SubsamplingScaleImageView) findViewById(R.id.zoom_image))
.execute(urls);
} else{
Toast.makeText(this, "Check your Internet connection!", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Activity_detail_image.this, LoginActivity.class);
startActivity(intent);
this.finish();
}
}
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
SubsamplingScaleImageView bmImage;
public DownloadImageTask(SubsamplingScaleImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImage(ImageSource.bitmap(result));
}
}
xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#color/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:theme="#style/ThemeOverlay.AppCompat.Dark"
app:titleTextColor="#android:color/white"
app:contentInsetStartWithNavigation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="right">
<TextView
android:gravity="center|start"
android:id="#+id/action_title"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="4">
</TextView>
</LinearLayout>
</android.support.v7.widget.Toolbar>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="#+id/zoom_image"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
Remove this
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
}
and write in onCreate Method
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
Also Use Glide or Picaso to load bitmap in imageview in onPostExecute method
Related
I am trying to implement "Swipe to load more" method in my application but I got that error when I swipe down in the first time. This is what it showed in the console:
E/SwipeRefreshLayout: Got ACTION_MOVE event but don't have an active
pointer id. E/SwipeRefreshLayout: Got ACTION_MOVE event but don't have
an active pointer id. E/SwipeRefreshLayout: Got ACTION_MOVE event but
don't have an active pointer id. E/SwipeRefreshLayout: Got ACTION_MOVE
event but don't have an active pointer id.
This is my layout code:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="training.com.chatgcmapplication.ChatActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipeLayout"
android:layout_width="match_parent"
android:layout_height="380dp">
<ListView
android:id="#+id/listMessage"
android:layout_width="match_parent"
android:layout_height="380dp"
android:layout_alignParentLeft="false"
android:layout_alignParentTop="false"
android:divider="#null"
android:listSelector="#android:color/transparent"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll" />
</android.support.v4.widget.SwipeRefreshLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="1">
<EditText
android:id="#+id/txt_chat"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.92"
android:inputType="text" />
<Button
android:id="#+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="30dp"
android:text="#string/btn_send" />
</LinearLayout>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
And when I swipe in the second time: it load double data.
This is ChatActivity, what implement that method:
public class ChatActivity extends AppCompatActivity implements View.OnClickListener, SwipeRefreshLayout.OnRefreshListener {
private static EditText txt_chat;
private String registId;
private String chatTitle;
private MessageSender mgsSender;
private int userId;
private DatabaseHelper databaseHelper;
private TimeUtil timeUtil;
private MessageAdapter messageAdapter;
private int offsetNumber = 5;
private SwipeRefreshLayout swipeRefreshLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
Button btn_send = (Button) findViewById(R.id.btn_send);
txt_chat = (EditText) findViewById(R.id.txt_chat);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeLayout);
swipeRefreshLayout.setOnRefreshListener(this);
ListView lv_message = (ListView) findViewById(R.id.listMessage);
timeUtil = new TimeUtil();
databaseHelper = DatabaseHelper.getInstance(getApplicationContext());
btn_send.setOnClickListener(this);
Bundle bundle = getIntent().getExtras();
chatTitle = bundle.getString("titleName");
if (getIntent().getBundleExtra("INFO") != null) {
chatTitle = getIntent().getBundleExtra("INFO").getString("name");
this.setTitle(chatTitle);
} else {
this.setTitle(chatTitle);
}
registId = bundle.getString("regId");
userId = databaseHelper.getUser(chatTitle).getUserId();
List<Message> messages = databaseHelper.getLastTenMessages(AppConfig.USER_ID, databaseHelper.getUser(chatTitle).getUserId(), 0);
messageAdapter = new MessageAdapter(getApplicationContext(), R.layout.chat_item, (ArrayList<Message>) messages);
LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, new IntentFilter("Msg"));
if (messages.size() > 0) lv_message.setAdapter(messageAdapter);
}
private BroadcastReceiver onNotice = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
try {
Message messageObj = new Message();
messageObj.setMessage(message);
messageObj.setUserId(userId);
messageObj.setSender_id(AppConfig.USER_ID);
messageObj.setExpiresTime(timeUtil.formatDateTime(timeUtil.getCurrentTime()));
messageAdapter.add(messageObj);
} catch (ParseException e) {
e.printStackTrace();
}
messageAdapter.notifyDataSetChanged();
}
};
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
super.onDestroy();
}
private static MessageSenderContent createMegContent(String regId, String title) {
String message = txt_chat.getText().toString();
MessageSenderContent mgsContent = new MessageSenderContent();
mgsContent.addRegId(regId);
mgsContent.createData(title, message);
return mgsContent;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_send:
String message = txt_chat.getText().toString();
databaseHelper = DatabaseHelper.getInstance(getApplicationContext());
mgsSender = new MessageSender();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
MessageSenderContent mgsContent = createMegContent(registId, AppConfig.USER_NAME);
mgsSender.sendPost(mgsContent);
return null;
}
}.execute();
databaseHelper.addMessage(message, timeUtil.getCurrentTime(), userId, AppConfig.USER_ID);
txt_chat.setText("");
try {
Message messageObj = new Message();
messageObj.setMessage(message);
messageObj.setUserId(AppConfig.USER_ID);
messageObj.setSender_id(userId);
messageObj.setExpiresTime(timeUtil.formatDateTime(timeUtil.getCurrentTime()));
messageAdapter.add(messageObj);
} catch (ParseException e) {
e.printStackTrace();
}
messageAdapter.notifyDataSetChanged();
break;
}
}
#Override
public void onRefresh() {
swipeRefreshLayout.setRefreshing(true);
List<Message> messages = databaseHelper.getLastTenMessages(AppConfig.USER_ID, databaseHelper.getUser(chatTitle).getUserId(), offsetNumber);
messageAdapter.insertToTheFirst(messages);
messageAdapter.notifyDataSetChanged();
offsetNumber += 5;
Log.i("Offset number", offsetNumber + "");
swipeRefreshLayout.setRefreshing(false);
}
}
UPDATE ISSUE's REASON
I found the reason of that issue. It due to I force the listview scroll to the bottom when it init with this code :
android:stackFromBottom="true"
I replace that code with this but still have same issue:
lv_message.post(new Runnable() {
#Override
public void run() {
lv_message.setSelection(lv_message.getCount() -1);
}
});
I think the problem is , You are trying to show , dismiss and refresh swipeRefreshLayout inside the same method i.e onRefresh().
Make seperate methods for showing and dismissing dialog and invoke them from the place where they are required as I have done below:
#Override
public void onRefresh() {
// refresh code here.
}
#Override
public void showDialog() {
swipeRef.post(new Runnable() {
#Override
public void run() {
if(swipeRef != null)
swipeRef.setRefreshing(true);
}
});
}
#Override
public void dismissDialog() {
if(swipeRef!=null && swipeRef.isShown() )
swipeRef.setRefreshing(false);
}
I'm trying to use a SwipeToRefreshLayout to update some information inside a marker. Although I use android:layout_width="wrap_content" to keep the content size, for some reason it always fills the parent, leaving a huge space below the information content. What am I doing wrong?
By the way, if I don't have the SwipeRefreshLayout , and use only the ScrollView, that empty space doesn't appear.
Here is my XML code:
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/svMarker"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/svMarkerInfo">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/llMarkerInfo">
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
Thank you for your answers!
I leave also the image of how is being showed using the SwipeRefreshLayout. Behind the marker information there is a map:
If I dont use SwipeRefreshLayout, the marker information is shown the next way, which visually is what I am looking for. but I'm missing the SwipeToRefresh update:
The SwipeRefreshLayout will disabled while dragging a map by using a listener and the refresh will only take place if you swipe down on the second half ( i.e. the layout below map). To get map drag events, we need to do some workaround because there is no direct support from Google and this library MapStateListener has done that. Just paste these three classes MapStateListener.java, TouchableMapFragment.java, TouchableWrapper.java into your project.
Here is a working example.
MainActivity.java
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback
{
private SwipeRefreshLayout swipeRefreshLayout;
private View secondHalf;
private TouchableMapFragment mMap;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.svMarker);
secondHalf = findViewById(R.id.secondHalf);
setUpMap();
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
{
#Override
public void onRefresh()
{
// A thread to keep RefreshLayout busy for 5 seconds
if(!swipeRefreshLayout.isRefreshing())
new LoadImagesTask().execute();
}
});
}
public void setUpMap()
{
try
{
if (mMap == null)
{
mMap = ((TouchableMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.firstHalf));
mMap.getMapAsync(this);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
#Override
public void onMapReady(GoogleMap googleMap)
{
new MapStateListener(googleMap, mMap, this)
{
#Override
public void onMapTouched()
{
// Map touched
swipeRefreshLayout.setEnabled(false);
}
#Override
public void onMapReleased() {
// Map released
swipeRefreshLayout.setEnabled(true);
}
#Override
public void onMapUnsettled() {
// Map unsettled
}
#Override
public void onMapSettled() {
// Map settled
}
};
}
private class LoadImagesTask extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids)
{
try
{
for (int i = 1; i <= 5; i++)
{
Thread.sleep(1000);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid)
{
super.onPostExecute(aVoid);
swipeRefreshLayout.setRefreshing(false);
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout android:id="#+id/svMarker"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2">
<fragment
android:id="#+id/firstHalf"
android:name="com.esealed.watermeterclient.TouchableMapFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
<ScrollView
android:id="#+id/secondHalf"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/colorAccent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Other views comes here -->
</LinearLayout>
</ScrollView>
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>
The only solution I could figure out was defining the SwipeRefreshLayout size dinamically. No need to change my XML file.
On my MapActivity.class, where I manage the marker's info, every time I show a new marker information, I call the next method:
LinearLayout llMarkerInfo = (LinearLayout) findViewById(R.id.llMarkerInfo);
SwipeRefreshLayout svMarker = (SwipeRefreshLayout) findViewById(R.id.svMarker);
//First i register to the listener so I can get the measured size of the marker information's layout
ViewTreeObserver vto = llMarkerInfo.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//I get the measured width and height of the marker information's layout
int width = llMarkerInfo.getMeasuredWidth();
int height = llMarkerInfo.getMeasuredHeight();
//Set that size to the SwipeToRefresh layout
LinearLayout.LayoutParams svParams = new LinearLayout.LayoutParams(width, height);
svMarker.setLayoutParams(svParams);
//Unregister the listener so is not called many times
if (Build.VERSION.SDK_INT < 16)
llMarkerInfo.getViewTreeObserver().removeGlobalOnLayoutListener(this);
else
llMarkerInfo.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
This way, I define exactly the size my marker information's layout has, to my SwipeRefreshLayout, dinamically.
Image with the final result (expected = reality):
I read some essays about releasing memories for Bitmap objects. I create a sample to test this problem as below.
MainActivity class:
public class MainActivity extends Activity {
private Bitmap bitmap;
private InputStream inputStream;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
try {
inputStream = getAssets().open("image1.jpg");
bitmap = BitmapFactory.decodeStream(inputStream);
}catch(Exception e){
Log.v("hoabao91", e.getMessage());
}
}
#Override
protected void onPause() {
super.onPause();
try {
inputStream.close();
inputStream = null;
bitmap.recycle();
bitmap = null;
}catch(Exception e){
Log.v("hoabao91", e.getMessage());
}
}
public void click(View view){
startActivity(new Intent(this, TestActivity.class));
}
}
TestActivity class:
public class TestActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
}
activity_main view:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit"
android:onClick="click"/>
</LinearLayout>
activity_test:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.hoa.test2.TestActivity">
</RelativeLayout>
I use android debug tool to track allocated memory
This is a status when I deploy the app
The system allocate to all objects including bitmap object 11.96 MB
Then I click the button "Submit" to go to TestActivity, the method onPause() will be called and the bitmap object will be release by recycle(). But status of allocated memory doesn't decrease. In contrast, it increase a little more (11.99 MB)!
Someone help me with explaining about that or giving me a solution to decrease allocated memory. To avoid leak of memory for large app.
I want to display multiple image views from URL place alongside each
My xml is :
<HorizontalScrollView android:id="#+id/horizontalScroll"
android:visibility="gone"
android:layout_width="wrap_content"
android:background="#EEEEEE"
android:layout_height="100dp"
android:scrollbars="horizontal"
android:layout_gravity="center">
<LinearLayout
android:id="#+id/imgLayout"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_height="wrap_content">
</LinearLayout>
</HorizontalScrollView>
My java code :
Drawable imgg;
ImageView image;
LinearLayout layout;
layout = (LinearLayout)findViewById(R.id.imgLayout);
private void grabImageFromUrl(String url) throws Exception
{
imgg = Drawable.createFromStream((InputStream)new URL(url).getContent(), "src");
}
/////////////////////////////////////////////////////////////////////////////////////////
class DownloadImageFromURL extends AsyncTask<String, String, String> {
String _ads;
public DownloadImageFromURL(String ads)
{
_ads = ads;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... f_url) {
image = new ImageView(getApplicationContext());
image.setId(imgId++);
try
{
grabImageFromUrl("http://dariran.com/Ads/Mobile/Small/" + _ads);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
protected void onProgressUpdate(String... progress) {
}
#Override
protected void onPostExecute(String file_url) {
try
{
image.setImageDrawable(imgg);
layout.addView(image);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
DownloadImageFromURL Class built on a loop syntax(images count)
I loaded images but they placed on each other
I don't know why can't display true.
This is my xml file:
<ProgressBar
android:id="#+id/progress_index"
style="#android:style/Widget.ProgressBar.Inverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
<ListView
android:id="#+id/listview_index"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarStyle="outsideInset">
</ListView>
I try to mProgress.setVisibility(View.GONE) after mListView.setAdapter() ,but when I check the "Show layout bounds" in the "Developer options".The layout not actually gone.As the picture shows,the ProgressBar is still in the center of the FrameLayout.Why?
Java code:
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mProgress = (ProgressBar) view.findViewById(R.id.progress_index);
mProgress.setVisibility(View.VISIBLE);
mAdapter = new CustomAdapter(getActivity());
new MyTask().execute();
lv.setAdapter(mAdapter);
}
public class MyTask extends AsyncTask<Integer, Void, ArrayList<NewsItem>> {
protected ArrayList<NewsItem> doInBackground(Integer... params) {
// some execution....
}
protected void onPostExecute(ArrayList<NewsItem> result) {
mAdapter.notifyDataSetChanged();
mProgress.setVisibility(View.GONE);
mListView.setVisibility(View.VISIBLE);
}
}
can you try this:
ProgressDialog mProgress = new ProgressDialog(activity.this);
...........
mProgress.dismiss();