I'm developing a dictionary using *.txt files in /raw directory, also I have a history (current 18 entries).
Every OnResume() I'm getting history entries from file on SDCard and filling ListArray's than use ArrayAdapter to fill a ListView.
I can't understand why I have a big memory leak (every onResume() adds about 4-6 MB to the memory). Please help me.
Here is my code:
public class SecondTab extends Activity {
ListView lv1;
ArrayList <String> ArrayHist = new ArrayList <String>();
ArrayList <String> ArrayHistMin = new ArrayList <String>();
BufferedReader Buffer;
InputStream file;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hist);
SetContent();
if (ru.andr.dictu.FirstTab.myErrorInHist)
{
Toast.makeText(this, getString(R.string.err_hist), Toast.LENGTH_LONG).show();
}
}
public void SetContent()
{
//show History entries
//trying to solve memory leak
try
{
ArrayHist.clear();
ArrayHistMin.clear();
}
catch (Exception e){}
ArrayHist=null;
ArrayHistMin=null;
ArrayHist = new ArrayList <String>();
ArrayHistMin = new ArrayList <String>();
Buffer=null;
file=null;
if (ru.andr.dictu.FirstTab.myErrorInHist!=true)
{
//filling arrays
try {
file = new FileInputStream(ru.andr.dictu.history_func.File_hist()); //getting name of file from common store
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Buffer = new BufferedReader(new InputStreamReader(file));
try {
String Str;
int counter_hist_content = 0;
while ( (Str = Buffer.readLine()) != null){ //reading from history file
String myTrimStr = Str.trim();
ArrayHistMin.add(myTrimStr.substring(0, myTrimStr.indexOf(";;")).intern()); //main word
ArrayHist.add(myTrimStr.substring(myTrimStr.indexOf(";;")+2).intern()); //ususaly translate
if (counter_hist_content==50) break;//needs only 50 entries
counter_hist_content++;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try
{
//closing files, buffers
file.reset();
file.close();
Buffer.reset();
Buffer.close();
}catch (Exception e) {}
}
lv1 = (ListView)findViewById(R.id.history);
lv1.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item_hist, ArrayHistMin));
lv1.setTextFilterEnabled(true);
lv1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
changeClass (position , ArrayHist.get(position));
}
});
lv1.setOnItemLongClickListener(new OnItemLongClickListener(){
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
ru.andr.dictu.myspeak.text=null;
ru.andr.dictu.myspeak.text=ArrayHistMin.get(arg2);
if (ru.andr.dictu.myspeak.text.indexOf("[")!=-1)
ru.andr.dictu.myspeak.text=ru.andr.dictu.myspeak.text.substring(0,ru.andr.dictu.myspeak.text.indexOf("[")).intern();
speakClass();
return true;
}
});
}
public void speakClass() {
Intent intent = new Intent();
intent.setClass(this, myspeak.class);
startActivity(intent);
}
public void changeClass(int position, String extArray) {
Intent intent = new Intent();
intent.setClass(this, List.class);
intent.putExtra(List.results, extArray.toString().intern());
startActivity(intent);
getParent().overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
}
#Override protected void onPause() {super.onPause(); }
#Override
protected void onResume()
{
super.onResume();
SetContent();
}
My guess is the new InputStreamReader(file) is being leaked. You need to close this reader.
Though if this does not solve the problem, dump the hprof data and check using MAT tool in eclipse. You can point out which class is taking maximum heap.
Edit: You can dump hprof in DDMS view. It is one of the buttons right above where processes are displayed
Related
I have problem in my application.
I want to show user's profile, and I have two links in my app.
One link is via TextView, which run showUser(View v) method:
public void showUser(View v){
Intent i;
i=new Intent(getApplicationContext(), ShowProfile.class);
i.putExtra("id",user); // user is String with users ID
startActivity(i);
}
And the second link is in dialog, which user can open:
( I will post here whole method, but I'll highlight important part )
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder .setTitle(R.string.show_photo_show_rated_users_title)
.setNegativeButton("Close", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
ListView modeList = new ListView(this);
String[] stringArray = new String[ratedUsers.size()];
for ( int i=0 ; i<ratedUsers.size() ; i++ ){
stringArray[i] = ratedUsers.get(i).get("name");
}
ArrayAdapter<String> modeAdapter = new ArrayAdapter<String>(this, R.layout.dropdown_item_white, android.R.id.text1, stringArray);
modeList.setAdapter(modeAdapter);
modeList.setOnItemClickListener(new ListView.OnItemClickListener(){
/*********************** IMPORTANT PART *********************************/
#Override
public void onItemClick(AdapterView<?> parent, View arg1, int index,long arg3) {
Intent i;
i=new Intent(ShowPhotoDetails.this , ShowProfile.class);
i.putExtra("id",ratedUsers.get(index).get("id"));
/**** ratedUsers is ArrayList<HashMap<String,String>> ****/
startActivity(i);
}});
builder.setView(modeList);
final Dialog dialog = builder.create();
dialog.show();
}
And finally here's ShowProfile.class:
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.profile);
Intent i = getIntent();
try {
id = i.getStringExtra("id");
}catch(Exception e){
e.printStackTrace();
Toast.makeText(getBaseContext(), "Error loading intent", Toast.LENGTH_SHORT).show();
finish();
}
try{
Log.w("ID",id); //always give right number
new GetUserInformations().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, id);
/*
If I comments this asyncTask, there's no error at all, but if I run it, It
open debug View in Eclipse, says that "Source not found" and crashes...
No LogCat Output
*/
}catch(Exception e){
e.printStackTrace();
}
...
I wonder why in one case it run perfectly and in the other it crashes. As I wrote in code, there's no LogCat output for this crash. It don't even say Uncaught exception or something like this.
EDIT: I found out what gives me the error.
public class GetUserInformations extends AsyncTask<String,Void,Void>{
Map<String,Object> tmpUser;
#Override
protected void onPreExecute(){
tmpUser = new HashMap<String,Object>();
}
#Override
protected Void doInBackground(String... arg) {
try{
int u_id = Integer.parseInt(arg[0]);
tmpUser = myDb.getUser(u_id); // downloading info
}catch(Exception e){
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void arg){
if ( tmpUser != null ){
Log.w("LOG",""+tmpUser.get("name"));
name = (String) tmpUser.get("name");
fbId = (String) tmpUser.get("id");
email = (String) tmpUser.get("email");
country = (Integer) tmpUser.get("country");
userName.setText(name);
profilepic.setProfileId(fbId);
userSubscribe.setVisibility(View.VISIBLE);
}
else {
Toast.makeText(getBaseContext(), "Error", Toast.LENGTH_SHORT).show();
finish();
}
}
}
When I open activity for first time, everything downloads fine, but when I backPress and click on link to this Activity again, then it gives me NullPointerException.
Do you know why ?
In your onItemClick function, try to put :
i = new Intent(getApplicationContext(), ShowProfile.class);
instead of :
i = new Intent(ShowPhotoDetails.this, ShowProfile.class);
remove this:
new GetUserInformations().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, id);
and use :
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
new GetUserInformations().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, id);
}
else {
new GetUserInformations().execute(id);
}
What is the API level on which you are facing this problem. Try to run it on different levels, taking Honeycomb as a reference.
Need to check the same and apply execute or executeONExecutor like this:
if (currentApiVersion >=
android.os.Build.VERSION_CODES.HONEYCOMB) {
new YourAsynctask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
new YourAsynctask().execute();
}
Check this asynctask-threading-regression-confirmed blog post
I'm creating an app wich is supposed to do the following:
- When started shows a splash/info-activity.
- In next activity shows a list of names as checkboxes
- user can add new names via EditText & Add-button (list updated dynamically)
- When closing app, and reopening, names previously added should be saved and displayed in list.
I've tried to setup my list as ArrayList in my startingactivity just to see if I can save and load my information correctly:
public class StartActivity extends Activity implements OnClickListener {
Typeface face;
TextView tvStartIntrotext;
Button bStartStart;
ArrayList<String> names = new ArrayList<String>();
String NAMESFILE = "names_file";
FileOutputStream fos;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.startactivity);
face = Typeface.createFromAsset(getAssets(), "andalemono.ttf");
bStartStart = (Button) findViewById(R.id.bStartStart);
bStartStart.setTypeface(face);
tvStartIntrotext = (TextView) findViewById(R.id.tvStartIntrotext);
tvStartIntrotext.setTypeface(face);
bStartStart.setOnClickListener(this);
try {
fos = openFileOutput(NAMESFILE, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
names.add("Name Name");
oos.writeObject(names);
oos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.startactivity, menu);
return true;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent startIntent = new Intent(StartActivity.this, Choose.class);
startActivity(startIntent);
}
}
To read and display I have this in my other activity so far:
public class Choose extends Activity implements OnClickListener {
String NAMESFILE = "names_file";
FileInputStream fis;
Button bChooseChoose, bChooseAdd;
Typeface face;
TextView tvChoosePick;
EditText etChooseAddnew;
LinearLayout llMain;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.slideinright, R.anim.slideoutleft);
setContentView(R.layout.choose);
face = Typeface.createFromAsset(getAssets(), "andalemono.ttf");
bChooseChoose = (Button) findViewById(R.id.bChooseChoose);
bChooseChoose.setTypeface(face);
bChooseChoose.setOnClickListener(this);
bChooseAdd = (Button) findViewById(R.id.bChooseAdd);
bChooseAdd.setTypeface(face);
bChooseAdd.setOnClickListener(this);
tvChoosePick = (TextView) findViewById(R.id.tvChoosePick);
tvChoosePick.setTypeface(face);
etChooseAddnew = (EditText) findViewById(R.id.etChooseAddnew);
etChooseAddnew.setTypeface(face);
etChooseAddnew.setBackgroundResource(R.color.white1);
etChooseAddnew.setHintTextColor(color.greytext);
llMain = (LinearLayout) findViewById(R.id.llMain);
try {
fis = openFileInput(NAMESFILE);
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList<Object> names = (ArrayList<Object>) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < names.size(); i++) {
CheckBox cbb = new CheckBox(this);
cbb.setText(names.get(i));
cbb.setTypeface(face);
cbb.setTextSize(16);
llMain.addView(cbb);
}
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()){
case R.id.bChooseChoose:
break;
case R.id.bChooseAdd:
/*This button for adding new list name*/
break;
}
}
}
One error I'm getting at this point is "setText" in my for-loop. Don't yet know how to get the information from the file opened to display in a list correctly. Although the for-loop works when no fileInput/Output is used.
Any pointers to what I can try would be really helpful, since I'm new to Android programming. :)
Thx!
The problem is that names variable declared inside try-catch block and cannot be accessed from outside. Just move declaration out of the block:
List<Object> names;
try {
fis = openFileInput(NAMESFILE);
ObjectInputStream ois = new ObjectInputStream(fis);
names = (ArrayList<Object>) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
names = Collections.emptyList();
}
UPDATE
And you can't use cbb.setText(names.get(i)) because names.get(i) is not a String. It's an object (that actually should be String if you saved strings in NAMESFILE).
You can either case it to String:
cbb.setText((String)names.get(i))
or use toString method:
cbb.setText(names.get(i).toString())
I'm writting an app, which lets user to input URL then select the location to put the downloaded file. But I'm get stuck in the 2nd step.
All I want to do is display the location like this:
And return the path to location.
Anyone has the solution? Thanks in advance!
PS: Display the external storage.
Create activity
public class ... extend activity
{
string path = "/";
public void onResume()
{
...
setContentView(..);
if (getIntent().hasExtra("path"))
{
path = getIntent().getStringExtra("path");
}
listview = findviewbyid(R.id.listview);
listview.setAdapter(new adapter(path));
listview.setOnItemClickListener(this);
}
public void onActivityResult(result)
{
if (resultOK) ...
}
public void onclicklisteneer(view,pos,id)
{
if (dir)
{
Intent intent = new Intent(this, this.class);
intent.put("path",path+" "+view.getAdapter().getItem(pos))
intent.setFlag(FLAG_NEW_TASK)
startActivityForResult(intent)
}
else if (file)
{
setResult(Result_OK);
finish();
}
}
}
This is how I do, and it works for me:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tree_view);
File dir = new File("/sdcard");
ArrayList<String> folders = new ArrayList<String>();
final File[] fileList = dir.listFiles();
if (fileList == null){
Toast msg = Toast.makeText(this, "No files", 3000);
msg.show();
}else{
for (File f:fileList){
if (f.isDirectory()){
folders.add(f.getName());
}
}
final ListView lvFolder = (ListView)findViewById(R.id.lvTree);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_selectable_list_item, folders);
lvFolder.setAdapter(adapter);
lvFolder.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View v,
int position, long id) {
// TODO Auto-generated method stub
Object o = lvFolder.getItemAtPosition(position);
String fullObject = (String)o;
Toast.makeText(getApplicationContext(), "You have chosen: " + " " + fullObject.toString(), Toast.LENGTH_LONG).show();
}
});
}
}
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
detail of list item in another screen
When I select an item I want the application to navigate to the second activity and take a value of selected item and the related link to the TextView which exists in the second activity. The code should work but when I run it the emulator gives me a message saying "Unfortunately the application stopped". I don't know what to do to make it work?
public class LastActivity extends ListActivity {
/** Called when the activity is first created. */
static List<String> links;
List<String> names;
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
String link=links.get(position);
Intent intent = new Intent(getApplicationContext(),Details.class);
intent.putExtra("name",names.get(position));
intent.putExtra("url",link);
Log.e("n",names.get(position)+"."+ link );
startActivity(intent);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
links=new ArrayList<String>();
names=new ArrayList<String>();
try{
URL url=new URL(webservice);
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(getInputStream(url), "UTF_8");
boolean insideItem = false;
// Returns the type of current event: START_TAG, END_TAG, etc..
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equalsIgnoreCase("item")) {
insideItem = true;
} else if (xpp.getName().equalsIgnoreCase("Name")) {
if (insideItem)
names.add(xpp.nextText()); //extract the headline
} else if (xpp.getName().equalsIgnoreCase("url")) {
if (insideItem)
links.add(xpp.nextText()); //extract the link of article
}
}else if(eventType==XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")){
insideItem=false;
}
eventType = xpp.next(); //move to next element
}
}catch (MalformedURLException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, names);
setListAdapter(adapter);
}
private InputStream getInputStream(URL url) {
// TODO Auto-generated method stub
try {
return url.openConnection().getInputStream();
} catch (IOException e) {
return null;
}
}
}
//second class or acticvites
public class Details extends LastActivity{
LastActivity last=new LastActivity();
TextView tv;
TextView url;
String read;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.details);
tv=(TextView) findViewById(R.id.text);
url=(TextView) findViewById(R.id.link);
Intent intent=getIntent();
// receiving data
String name = intent.getStringExtra("name");
String path=intent.getStringExtra("links");
Log.e("Second Screen", name + "." + path);
tv.setText(name);
url.setText(path);
}
I think the problem is with passing putExtra values in the intents. Check your first Activity, you have used the key as "url", but in the details Activity you are using "links" as the key. So you are getting null Pointer Exception. Change it properly.
intent.putExtra("name",names.get(position));
intent.putExtra("url",link);
in Details Activity,
String name = intent.getStringExtra("name");
String path=intent.getStringExtra("url");
instead of,
String path=intent.getStringExtra("links");
In your First Activity you have exntended ListActivty, try to replace it with Activity alone.
Or change your ListView id to #android:list in your xml file.
For more info, look at this question , "Stopped Unexpectedly" tried 10000 times to fix
And also check this for more idea,
Your content must have a ListView whose id attribute is 'android.R.id.list
I was trying to do some data loading in Splash page in my app using asynctask, but the app stuck at the splash screen, and logcat print:
Default buffer size used in BufferedOutputStream constructor. It would be better to be explicit if an 8k buffer is required.
Here are my code
package com.appkon.hdtvs;
public class Splash extends Activity {
private ChannelDB mDB;
private TextView loading;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
AppConnect.getInstance(this);
loading =(TextView)findViewById(R.id.loading);
}
private class SetDB extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
try {
if (tabIsExist(null)==true){
mDB.Reset();
Bitmap bigbang1 = BitmapFactory.decodeResource(getResources(), R.drawable.bigbang1);
Bitmap bigbang2 = BitmapFactory.decodeResource(getResources(), R.drawable.bigbang2);
mDB.createchannelEntry(new ChannelPoster(castle4, "灵书妙探 (第四季)" ,"http://appkon.com/hdtvs/channel/castle4.xml" ,"http://movie.douban.com/subject/6742616/" ));
mDB.createchannelEntry(new ChannelPoster(castle3, "灵书妙探 (第三季)" ,"http://appkon.com/hdtvs/channel/castle4.xml" ,"http://movie.douban.com/subject/4836898/" ));
}
}catch (Exception e) {
Intent i = new Intent();
i.setClassName("com.appkon.hdtvs",
"com.appkon.hdtvs.HDtvs");
finish();
startActivity(i);
}
return null;
}
protected void onProgress(String load) {
loading.setText("载入中···");
}
protected void onPostExecute(String finish) {
loading.setText("载入完成");
}
}
public boolean tabIsExist(String channelS_TABLE){
boolean result = false;
if(channelS_TABLE == null){
return false;
}
Cursor cursor= ChannelDB.check();
startManagingCursor(cursor);
try {
if(cursor.moveToNext()){
int count = cursor.getInt(0);
if(count>0){
result = true;
}
}
} catch (Exception e) {
Log.e(this.toString(),"error:"+e.toString());
Intent intent = new Intent(this,HDtvs.class);
startActivity(intent);
this.finish();
}
return result;
}
}
So what seem to be the problem? Is that because my res images are too big.
Somewhere a BufferedOutputStream is used but not constructed with a size (second argument). Maybe you used libs do the mess.