AsyncTask onPostExecute UI Changes - java

It is always the little things that stump me for hours.
I have an onPostExecute method from an AsyncTask class that looks like so:
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
showColumnCounts();
dataDownloadCompleteToast();
}
The toast works just fine. However, my showColumnCounts() method refuses to work. It works just fine on the main thread. I use it during onCreate() just not here. I thought the onPostExecute ran on the UI thread?
Here is my showColumnCounts() method if it is relevant.
public void showColumnCounts() {
TextView totalView = (TextView) findViewById(R.id.totalColumn2);
TextView ignoredView = (TextView) findViewById(R.id.ignoredColumn2);
TextView rView = (TextView) findViewById(R.id.rColumn2);
Cursor c = myDB.getEmptyRColumn("");
int count = c.getCount();
if (count == 0) {
c.close();
return;
}
String unread = String.valueOf(count);
String total = getTotalCount();
int tTotal = Integer.parseInt(total);
int r = tTotal - count;
String read = String.valueOf(r);
totalView.setText(total);
ignoredView.setText(unread);
rView.setText(read);
c.close();
}
I've been fiddling with it for a while now assuming the answer should be obvious but I'm calling uncle. Can't figure it.
Edit***** 6/30
I THINK I've found my problem. In my background thread I am using a parse.com method "query.findInBackground" which I assume is starting a third thread? I'm trying to update this to "query.find" and I'm hoping that will fix.

First of all you should move all your TextView declarations inside your onCreate method
if you want to change or perform some UI operation, if you want to perform some non UI based operations while the thread is running then do that in doInBackground() method

You should move …setText(...) lines into
runOnUiThread(new Runnable(){
void run(){
// UI stuff
});

You need to tell where is your async class located and the showColumnCounts() function located.
If they both where in different class then you should create a context to call the function from the async class.
Take this as example and try.
Example:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
new AsyncClass(this);
super.onCreate(savedInstanceState);
}
public void showColumnCounts() {
TextView totalView = (TextView) findViewById(R.id.totalColumn2);
TextView ignoredView = (TextView) findViewById(R.id.ignoredColumn2);
TextView rView = (TextView) findViewById(R.id.rColumn2);
Cursor c = myDB.getEmptyRColumn("");
int count = c.getCount();
if (count == 0) {
c.close();
return;
}
String unread = String.valueOf(count);
String total = getTotalCount();
int tTotal = Integer.parseInt(total);
int r = tTotal - count;
String read = String.valueOf(r);
totalView.setText(total);
ignoredView.setText(unread);
rView.setText(read);
c.close();
}
public class AsyncClass extends AsyncTask<String, Void, Boolean> {
private Activity activity;
public AsyncClass(Activity main_activity) {
this.activity = main_activity;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
activity.showColumnCounts();
dataDownloadCompleteToast();
}
}
}

If you want to do some UI change process in background running operation(ASYNC TASK),you write that codes in UI thread. Example:
YourActivity.this.runOnUiThread(
new Runnable()
void run()
{
//UI changes
showColumnCounts();
});

Related

How to add the TextView to the layout programmatically?

I'm trying to make messages like in messenger. They must appear one after another. So I use the LinearLayout and add the TextView to it. But the appear all at once. I use the loop, but it looks like it doesn't work!
Here is the code
final LinearLayout lm = (LinearLayout) findViewById(R.id.line_layout);
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(10, 10, 500, 50);
int i = 0;
for (final Task task : tasks) {
i = i + 1;
for (int j = 0; j < 1; j++) {
final TextView message = new TextView(TaskActivity.this);
message.setText(task.getName());
message.setId(task.getId());
message.setLayoutParams(params);
message.setTextSize(30);
message.setBackground(getApplicationContext().getDrawable(R.drawable.task_text));
Toast.makeText(TaskActivity.this, "Text loaded",
Toast.LENGTH_SHORT).show();
lm.addView(message);
SystemClock.sleep(1000);
}
}
The TextViews appear at once no matter the timer. The app waits while the Timer for every circle of the loop and returns the hole messengers at once!
See the screenshot of the app:
So how would you do this task and resolve the problem? Thank you!
If you want the behaviour as in Messenger , you should use RecyclerView in android.
https://developer.android.com/guide/topics/ui/layout/recyclerview
With the time interval to add a new message, you can use recyclerview notify methods to show the new messages.
define a layout in which you need to add your textView and then do the following
LayoutParams lparams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
TextView tv=new TextView(this);
tv.setLayoutParams(lparams);
tv.setText("test");
this.parentLayout.addView(tv);
Your code is running on the uiThread so the UI doesn't update until the loop is complete. Have a look at using an AsyncTask to pause the app in the background and do the update after finishing. Try something like this:
public class TestActivity extends Activity
{
Queue<String> messages = new LinkedList<String>();
class PushNextMessage extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... params)
{
try
{
Thread.sleep(1000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void _void)
{
String message = messages.remove();
//this is where you add the view to the base layout
if (messages.size() > 0)
{
new PushNextMessage().execute();
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
messages.add("message 1");
messages.add("message 2");
messages.add("message 3");
new PushNextMessage().execute();
}
}

Java class extends MainActivity but findViewById comes back null?

This class extends my main Activity.
public class Numbers extends MainActivity{
public ArrayList<ImageView> getNumbers () {
ArrayList<ImageView> numbers = new ArrayList<>();
ImageView one = (ImageView) findViewById(R.id.one);
numbers.add(one);
return numbers;
}
And I've done some digging but can figure out why my variable "one" is coming back null.
My MainActivity has a ContentView set.
This is the content of my onCreate in MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView start = (ImageView) findViewById(R.id.start);
sceneRoot = (ViewGroup) findViewById(R.id.scene_root);
questionView = findViewById(R.id.questionView);
startView = findViewById(R.id.startView);
gameOverView = findViewById(R.id.gameOver);
animSlide = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide);
animSlide.setAnimationListener(this);
animZoom = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.zoom_fade);
animZoom.setAnimationListener(this);
set.addTransition(new Fade())
.addTransition(new Slide(Gravity.RIGHT));
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getQuestion();
TransitionManager.beginDelayedTransition(sceneRoot, set);
startView.setVisibility(View.GONE);
questionView.setVisibility(View.VISIBLE);
}
});
}
public void getQuestion (){
time = (TextView) findViewById(R.id.timeBar);
time.startAnimation(animSlide);
}
I don't call getNumbers() until after start has been clicked and the animation has started.
public void onAnimationStart(Animation animation){
if(animation == animSlide) {
final Questions questions = new Questions();
Numbers n = new Numbers();
for (int i = 0; i < n.getNumbers().size(); i++) {
n.getNumbers().get(i).setVisibility(View.GONE);
n.getNumbersTen().get(i).setVisibility(View.GONE);
}
n.getNumbers().get(0).setVisibility(View.VISIBLE);
EDIT:
If anyone was wondering, I got it to work by extending the class as a Fragment instead of my MainActivity. Then I just used the fragment in my xml.
Because you extended an Activity class doesn't mean setContentView gets called for that class also. It will only do so if properly started and you call super.onCreate(bundle) from your own implementation of onCreate within Numbers
Basically, you should never new any Activity. It has no life-cycle, and therefore no content view, so findViewById just won't work.
Numbers n = new Numbers();
You could not extend anything and have a data-only class around your list of images.
public class Numbers {
private List<ImageView> numbers = new ArrayList<ImageView>();
public Numbers() {}
public void addNumber(ImageView v) { numbers.add(v); }
public List<ImageView> getNumbers() { return numbers; }
}
And from MainActivity you can find and add as you want.
Number n = new Numbers();
n.addNumber((ImageView) findViewById(R.id.one));
However, I don't know if that is useful, really...
Maybe a Fragment would serve a better purpose if you want a "sub-view" of your Activity, but it's hard to tell.

Attempt to call a method but I get a NullPointerException

I want to create a connection through socket but I'm having trouble with the graphic of my App:
This is my activity:
public class Messaggi2 extends ActionBarActivity{
LinearLayout mLayout;
ScrollView scroll;
EditText scriviMessaggi;
Button invia;
Socket connessione;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaggi2);
mLayout = (LinearLayout) findViewById(R.id.LinearScrollLayout);
scroll = (ScrollView) findViewById(R.id.scrollView2);
scriviMessaggi = (EditText) findViewById(R.id.Scrivi);
invia = (Button) findViewById(R.id.Invia);
LavoraDietro asd = new LavoraDietro(connessione);
asd.execute();
}
private TextView createNewTextView(String text) {
final LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); final TextView textView = new TextView(this);
textView.setLayoutParams(lparams);
textView.setText(text);
textView.setBackgroundResource(R.drawable.balloon_broadcast_incoming_pressed);
return textView;
}
private TextView createNewTextViewSent(String text) {
final LinearLayout.LayoutParams llparams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
llparams.gravity = Gravity.RIGHT;
final TextView textViewSent = new TextView(this);
textViewSent.setLayoutParams(llparams);
textViewSent.setText(text);
textViewSent.setBackgroundResource(R.drawable.balloon_outgoing_normal);
return textViewSent;
}
public void AggiungiTextALlayout(String messaggio){
mLayout.addView(createNewTextView(messaggio));
aggiornaScroll();
}
public void AggiungiTextInviatoALlayout(String messaggio){
mLayout.addView(createNewTextViewSent(messaggio));
aggiornaScroll();
}
public void aggiornaScroll(){
scroll.post(new Runnable() {
#Override
public void run() {
scroll.fullScroll(View.FOCUS_DOWN);
}
});
}
}
This is my AsynTask class:
public class LavoraDietro extends AsyncTask<Void, Void, Socket> {
Socket connessione;
boolean vediSeDeviPartire;
Messaggi2 mess = new Messaggi2();
public LavoraDietro(Socket connessione){
this.connessione = connessione;
}
#Override
protected Socket doInBackground(Void... params){
try {
InetAddress local = InetAddress.getByName("192.168.1.71");
connessione = new Socket(local , 7000);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
return null;
}catch(Exception e){
e.printStackTrace();
}
return connessione;
}
#Override
protected void onPostExecute(Socket result) {
super.onPostExecute(result);
if(result != null){
vediSeDeviPartire = true;
mess.AggiungiTextALlayout("Sono connesso al server");
mess.AggiungiTextALlayout("I canali sono aperi..");
}
else{
mess.AggiungiTextALlayout("ERRORE CONNESSIONE AL SERVER ");
}
}
}
Using this code when I start my app the connection is established and then it crashes. What I see on my Logcat is this Exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
So I tried to delete the content of my onPostExecute and everything works perfect. So the mistake is to try to call the method AggiungiTextAlLayout on my AsyncTask class.
Can someone help me with this? Can someone suggest me something? I'm new in this field so I know that this is a stupid thing but I need help.
Thanks guys in advance
EDITED WITH THE SOLUTION
Thanks to Ataulm I got the problem and I solved it I changed the costructor of my LavoraDietro class (unfortunatly I can't change the name of variables and classes in English. But next time I ll use english Name of course )
LavoraDietro Class
public class LavoraDietro extends AsyncTask<Void, Void, Socket> {
Socket connessione;
boolean vediSeDeviPartire;
Messaggi2 action;
public LavoraDietro(Socket connessione, Messaggi2 action){
this.connessione = connessione;
this.action = action;
}
#Override
protected Socket doInBackground(Void... params){
try {
InetAddress local = InetAddress.getByName("192.168.1.71");
connessione = new Socket(local , 7000);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
return null;
}catch(Exception e){
e.printStackTrace();
}
return connessione;
}
#Override
protected void onPostExecute(Socket result) {
super.onPostExecute(result);
if(result != null){
vediSeDeviPartire = true;
action.AggiungiTextALlayout("Sono connesso al server");
action.AggiungiTextALlayout("I canali sono aperi..");
}
else{
action.AggiungiTextALlayout("ERRORE CONNESSIONE AL SERVER ");
}
}
}
And in the Messaggi2 class I changed the call of the constructor in this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaggi2);
mLayout = (LinearLayout) findViewById(R.id.LinearScrollLayout);
scroll = (ScrollView) findViewById(R.id.scrollView2);
scriviMessaggi = (EditText) findViewById(R.id.Scrivi);
invia = (Button) findViewById(R.id.Invia);
LavoraDietro asd = new LavoraDietro(connessione, this);
asd.execute();
Your AsyncTask has a reference to mess which is an object of type Messaggi2.
Messaggi2 is a subclass of Activity. You attempt, inside your AsyncTask, to create a new instance of that class.
The Android system has no awareness of this object; it has called none of the life cycle methods, such as onCreate() where the activity's layout would typically be inflated. This means that none of your views are inflated nor even initialised.
When you call mess.AggiungiTextALlayout("Sono connesso al server");, mLayout is null.
The NPE you see may likely not even be this one.
TL;DR: don't instantiate your Activity objects like Java objects; use them as specified within the Android framework.
I suspect you have this Activity starting correctly somewhere. The mistake is that you've not associated that activity with your Asynctask. When you create LavoraDietro, you pass a reference to the Socket in the constructor; you can also pass a reference to your activity, and assign that to the mess field, instead of calling new Messaggi2(). I'm not advocating this structure. But that is the issue at hand.
A few general tips to help you avoid this in future / or spot it faster:
be consistent with your naming; it's difficult to read your code when you're switching between English and Italian.
it's equally difficult for others to read your code if you don't maintain follow Java conventions with class/method names.
When you're extending Activity, it's typical to append the word "Activity" after your class; in this example new Messaggi2Activity() would have been easier to spot.
Where you're able, pass a Class's dependencies as parameters in the constructor; don't rely on constructing these dependencies yourself inside that class. Once you do this, you can begin to draw lines around what your class is responsible for; the less it's responsible for, the harder it is for your class to mess up.
That problem is for put a variable with no "data", verify your variables

Passing a TextView or TextView Array to a function in Android

I'm a rookie programmer, and I'm trying to setup a function to pass a TextView or an array of TextViews to a function, so it can be called at various points in the activity.
public class ScoreboardActivity extends Activity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scoreboard);
...
final TextView STATVIEW1A = (TextView) findViewById(R.id.place_stat1a); //Team 1
final TextView STATVIEW1B = (TextView) findViewById(R.id.place_stat1b);
final TextView STATVIEW1C = (TextView) findViewById(R.id.place_stat1c);
final TextView STATVIEW1D = (TextView) findViewById(R.id.place_stat1d);
final TextView STATVIEW2A = (TextView) findViewById(R.id.place_stat2a); //Team 2
final TextView STATVIEW2B = (TextView) findViewById(R.id.place_stat2b);
final TextView STATVIEW2C = (TextView) findViewById(R.id.place_stat2c);
final TextView STATVIEW2D = (TextView) findViewById(R.id.place_stat2d);
//final TextView[] STATVIEW = {STATVIEW1A,STATVIEW1B,STATVIEW1C,STATVIEW1D,
// STATVIEW2A,STATVIEW2B,STATVIEW2C,STATVIEW2D};
...
postStats();
... or
postStats(STATVIEW[]);
I want to have a routine to post the (8) TextViews on my activity_scoreobard layout. I have tried just referencing the STATVIEW1A in the function:
public void postStats () {
STATVIEW1AX.setText("#dumps: " + Integer.toString(DUMP1[GAME_NO]));
}
I have also tried referencing each of the TextViews from passing an array of TextViews in the function:
public void postStats (TextView[] VIEWSTAT) {
VIEWSTAT[6].setText("#dumps: "+ Integer.toString(DUMP2[GAME_NO]));
}
While both don't show errors in Eclipse, the program does not like either situation.
Generally it's not a good idea to pass them to function...
but if you want you can try something like this...
TextView[] STATVIEW = new TextView[SIZE];
then to initialize
STATVIEW[0] = (TextView) findViewById(R.id.place_stat1a); //Team 1
STATVIEW[1] = (TextView) findViewById(R.id.place_stat1b);
......
then pass your Array
postStats(STATVIEW);
Alternative would be
create a method and pass the values and set them to TextViews
something like this
public void fillData(String[] data)
{
for (int i=0;i<STATVIEW.length;i++)
{
STATVIEW[i].setText(data[i]);
}
}
It is better to use an array of WeakReference objects to hold the references to your Text views and initialize this array in the OnCreate method of your activity, using this method everytime that system destroy your activity the references to the items can be garbage collected automatically and you won't cause memory leaks. As far as i know the standard way for holding a reference to an ephemeral object like the activity itself or a views on it is to use WeakReference objects.
For understanding what a WeakReference is read the following article on Wikipedia:
http://en.wikipedia.org/wiki/Weak_reference
Also read this page:
https://developer.android.com/reference/java/lang/ref/WeakReference.html
Instead of Overloading postStats() function you can try using postStats(TextView... VIEWSTAT). In this function you can check the number of arguments by VIEWSTAT.length.
ArrayList<TextView> tmpArrayList = new ArrayList<TextView>();
for(int y=0; y<10; y++)
{
tmpArrayList.add(getTextView(txtBoxCount++));
}
this.postStats(tmpArrayList);
private TextView getTextView(int i)
{
int id=0;
try {
id = R.id.class.getField("textview" + i).getInt(0);
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (SecurityException e) {
e.printStackTrace();
}
catch(IllegalAccessException e) {
e.printStackTrace();
}
catch (NoSuchFieldException e) {
e.printStackTrace();
}
textview = (TextView)findViewById(id);
textview.setTag("0");
return textview;
}
public void postStats (ArrayList<TextView> viewstat) {
//do some work here
}

MainActivity.this is not an enclosing class AsyncTask

I'm trying to create an AsyncTask for the 1st time, but I don't have much luck.
My AsyncTask needs to get some information from a server and then add new layouts to the main layout to display this information.
Everything seems to be more or less clear but, the error message "MainActivity is not an enclosing class" is bothering me.
Nobody else seems to have this problem, so I think I miss something very obvious, I just don't know what it is.
Also, I'm not sure if I used the right way to get the context, and because my application doesn't compile so I can't test it.
Your help is much appreciated.
Here is my code:
public class BackgroundWorker extends AsyncTask<Context, String, ArrayList<Card>> {
Context ApplicationContext;
#Override
protected ArrayList<Card> doInBackground(Context... contexts) {
this.ApplicationContext = contexts[0];//Is it this right way to get the context?
SomeClass someClass = new SomeClass();
return someClass.getCards();
}
/**
* Updates the GUI before the operation started
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
/**
* Updates the GUI after operation has been completed
*/
protected void onPostExecute(ArrayList<Card> cards) {
super.onPostExecute(cards);
int counter = 0;
// Amount of "cards" can be different each time
for (Card card : cards) {
//Create new view
LayoutInflater inflater = (LayoutInflater) ApplicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewSwitcher view = (ViewSwitcher)inflater.inflate(R.layout.card_layout, null);
ImageButton imageButton = (ImageButton)view.findViewById(R.id.card_button_edit_nickname);
/**
* A lot of irrelevant operations here
*/
// I'm getting the error message below
LinearLayout insertPoint = (LinearLayout)MainActivity.this.findViewById(R.id.main);
insertPoint.addView(view, counter++, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
}
Eclipse is probably right, and you are trying to access a class (MainActivity) that is inside it's own file from another class that is in its own file (BackgroundWorker) . There is no way to do that - how is one class supposed to know about the other's instance magically? What you can do:
Move the AsyncTask so it is an inner class in MainActivity
Pass off your Activity to the AsyncTask (via its constructor) then acess using activityVariable.findViewById(); (I am using mActivity in the example below) Alternatively, your ApplicationContext (use proper naming convention, the A needs to be lowercase) is actually an instance of MainActivity you're good to go, so do ApplicationContext.findViewById();
Using the Constructor example:
public class BackgroundWorker extends AsyncTask<Context, String, ArrayList<Card>>
{
Context ApplicationContext;
Activity mActivity;
public BackgroundWorker (Activity activity)
{
super();
mActivity = activity;
}
//rest of code...
As for
I'm not sure if I used the right way to get the context
It is fine.
Above example is inner class, here is standalone class...
public class DownloadFileFromURL extends AsyncTask<String, String, String> {
ProgressDialog pd;
String pathFolder = "";
String pathFile = "";
Context ApplicationContext;
Activity mActivity;
public DownloadFileFromURL (Activity activity)
{
super();
mActivity = activity;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(mActivity);
pd.setTitle("Processing...");
pd.setMessage("Please wait.");
pd.setMax(100);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setCancelable(true);
pd.show();
}
#Override
protected String doInBackground(String... f_url) {
int count;
try {
pathFolder = Environment.getExternalStorageDirectory() + "/YourAppDataFolder";
pathFile = pathFolder + "/yourappname.apk";
File futureStudioIconFile = new File(pathFolder);
if(!futureStudioIconFile.exists()){
futureStudioIconFile.mkdirs();
}
URL url = new URL(f_url[0]);
URLConnection connection = url.openConnection();
connection.connect();
// this will be useful so that you can show a tipical 0-100%
// progress bar
int lengthOfFile = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
FileOutputStream output = new FileOutputStream(pathFile);
byte data[] = new byte[1024]; //anybody know what 1024 means ?
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
// After this onProgressUpdate will be called
publishProgress("" + (int) ((total * 100) / lengthOfFile));
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return pathFile;
}
protected void onProgressUpdate(String... progress) {
// setting progress percentage
pd.setProgress(Integer.parseInt(progress[0]));
}
#Override
protected void onPostExecute(String file_url) {
if (pd!=null) {
pd.dismiss();
}
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(new File(file_url)), "application/vnd.android.package-archive" );
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(i);
}
}

Categories

Resources